UNOMI-561 : add endpoint to register json extensions (#406)

diff --git a/api/src/main/java/org/apache/unomi/api/schema/JSONSchemaExtension.java b/api/src/main/java/org/apache/unomi/api/schema/JSONSchemaExtension.java
new file mode 100644
index 0000000..652102d
--- /dev/null
+++ b/api/src/main/java/org/apache/unomi/api/schema/JSONSchemaExtension.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.unomi.api.schema;
+
+import org.apache.unomi.api.Metadata;
+import org.apache.unomi.api.MetadataItem;
+
+/**
+ * Object which represents a JSON schema extensions stored in the persistence service
+ */
+public class JSONSchemaExtension extends MetadataItem {
+    public static final String ITEM_TYPE = "jsonSchemaExtension";
+
+    private String id;
+    private String extension;
+    private double priority;
+    private String schemaId;
+
+    public JSONSchemaExtension() {
+    }
+
+    /**
+     * Instantiates a new JSON schema with an id and a schema extension as string
+     *
+     * @param id        id of the extension
+     * @param schemaId  id of the schema
+     * @param extension as string
+     * @param priority  priority to process the extension
+     */
+    public JSONSchemaExtension(String id, String schemaId, String extension, float priority) {
+        super(new Metadata(id));
+        this.id = id;
+        this.extension = extension;
+        this.priority = priority;
+        this.schemaId = schemaId;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getExtension() {
+        return extension;
+    }
+
+    public void setExtension(String extension) {
+        this.extension = extension;
+    }
+
+    public double getPriority() {
+        return priority;
+    }
+
+    public void setPriority(double priority) {
+        this.priority = priority;
+    }
+
+    public String getSchemaId() {
+        return schemaId;
+    }
+
+    public void setSchemaId(String schemaId) {
+        this.schemaId = schemaId;
+    }
+}
diff --git a/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java
index 05ac24d..33f4b72 100644
--- a/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java
+++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java
@@ -16,7 +16,7 @@
  */
 package org.apache.unomi.api.schema.json;
 
-import org.apache.unomi.api.services.SchemaRegistry;
+import org.apache.unomi.api.services.SchemaService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,10 +33,10 @@
 
     Map<String, Class<? extends JSONType>> jsonTypes = new HashMap<>();
 
-    SchemaRegistry schemaRegistry;
+    SchemaService schemaService;
 
-    public JSONTypeFactory(SchemaRegistry schemaRegistry) {
-        this.schemaRegistry = schemaRegistry;
+    public JSONTypeFactory(SchemaService schemaService) {
+        this.schemaService = schemaService;
         jsonTypes.put("object", JSONObjectType.class);
         jsonTypes.put("string", JSONStringType.class);
         jsonTypes.put("array", JSONArrayType.class);
@@ -49,7 +49,7 @@
     List<JSONType> getTypes(Map<String, Object> schemaTree) {
         if (schemaTree.containsKey("$ref")) {
             String schemaId = (String) schemaTree.get("$ref");
-            JSONSchema refSchema = schemaRegistry.getSchema(schemaId);
+            JSONSchema refSchema = schemaService.getSchema(schemaId);
             if (refSchema != null) {
                 schemaTree = refSchema.getSchemaTree();
             } else {
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/services/SchemaService.java
similarity index 65%
rename from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
rename to api/src/main/java/org/apache/unomi/api/services/SchemaService.java
index b25a613..bbd6c9d 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java
+++ b/api/src/main/java/org/apache/unomi/api/services/SchemaService.java
@@ -28,7 +28,7 @@
 /**
  * Service that allow to manage JSON schema. It allows to get, save and delete schemas
  */
-public interface SchemaRegistry {
+public interface SchemaService {
 
     /**
      * Retrieves json schema metadatas, ordered according to the specified {@code sortBy} String and and paged: only {@code size} of them
@@ -53,7 +53,6 @@
      */
     boolean isValid(Object object, String schemaId);
 
-
     /**
      * Get a schema matching by a schema id
      *
@@ -106,4 +105,50 @@
      * @return true if the schema has been deleted
      */
     boolean deleteSchema(InputStream schemaStream);
+
+    /**
+     * Save an extension of a JSON schema
+     *
+     * @param extensionStream inputStream of the extension
+     */
+    void saveExtension(InputStream extensionStream) throws IOException;
+
+    /**
+     * Save an extension of a JSON schema
+     *
+     * @param extension as String value
+     */
+    void saveExtension(String extension) throws IOException;
+
+    /**
+     * Delete an extension
+     *
+     * @param extensionStream inputStream of the extension to delete
+     * @return true if the extension has been deleted
+     */
+    boolean deleteExtension(InputStream extensionStream) throws IOException;
+
+    /**
+     * Delete an extension by an id
+     *
+     * @param extensionId id of the extension
+     * @return true if the extension has been deleted
+     */
+    boolean deleteExtension(String extensionId);
+
+    /**
+     * Retrieves json schema extension metadatas, ordered according to the specified {@code sortBy} String and and paged: only {@code size}
+     * of them
+     * are retrieved, starting with the {@code
+     * offset}-th one.
+     *
+     * @param offset zero or a positive integer specifying the position of the first element in the total ordered collection of matching elements
+     * @param size   a positive integer specifying how many matching elements should be retrieved or {@code -1} if all of them should be retrieved
+     * @param sortBy an optional ({@code null} if no sorting is required) String of comma ({@code ,}) separated property names on which ordering should be performed, ordering elements according to the property order in the
+     *               String, considering each in turn and moving on to the next one in case of equality of all preceding ones. Each property name is optionally followed by
+     *               a column ({@code :}) and an order specifier: {@code asc} or {@code desc}.
+     * @return a {@link PartialList} of json schema extension metadata
+     */
+    PartialList<Metadata> getJsonSchemaExtensionsMetadatas(int offset, int size, String sortBy);
+
 }
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java
index 8347fd7..eff1964 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java
@@ -38,7 +38,7 @@
 import org.apache.unomi.api.schema.json.JSONSchema;
 import org.apache.unomi.api.schema.json.JSONType;
 import org.apache.unomi.api.services.ProfileService;
-import org.apache.unomi.api.services.SchemaRegistry;
+import org.apache.unomi.api.services.SchemaService;
 import org.apache.unomi.graphql.CDPGraphQLConstants;
 import org.apache.unomi.graphql.converters.UnomiToGraphQLConverter;
 import org.apache.unomi.graphql.fetchers.CustomEventOrSetPropertyDataFetcher;
@@ -88,7 +88,7 @@
 
     private final ProfileService profileService;
 
-    private final SchemaRegistry schemaRegistry;
+    private final SchemaService schemaService;
 
     private final List<GraphQLTypeFunctionProvider> typeFunctionProviders;
 
@@ -188,7 +188,7 @@
 
     private GraphQLSchemaProvider(final Builder builder) {
         this.profileService = builder.profileService;
-        this.schemaRegistry = builder.schemaRegistry;
+        this.schemaService = builder.schemaService;
         this.eventPublisher = builder.eventPublisher;
         this.typeFunctionProviders = builder.typeFunctionProviders;
         this.extensionsProviders = builder.extensionsProviders;
@@ -331,7 +331,7 @@
     }
 
     private void registerDynamicUnomiInputEvents(GraphQLSchema.Builder schemaBuilder) {
-        final List<JSONSchema> unomiEventTypes = schemaRegistry.getSchemasByTarget("events");
+        final List<JSONSchema> unomiEventTypes = schemaService.getSchemasByTarget("events");
 
         if (!unomiEventTypes.isEmpty()) {
             for (JSONSchema unomiEventType : unomiEventTypes) {
@@ -353,7 +353,7 @@
     }
 
     private void registerDynamicUnomiOutputEvents(GraphQLSchema.Builder schemaBuilder) {
-        final List<JSONSchema> unomiEventTypes = schemaRegistry.getSchemasByTarget("events");
+        final List<JSONSchema> unomiEventTypes = schemaService.getSchemasByTarget("events");
 
         if (!unomiEventTypes.isEmpty()) {
             final GraphQLCodeRegistry.Builder codeRegisterBuilder = graphQLAnnotations.getContainer().getCodeRegistryBuilder();
@@ -650,7 +650,7 @@
         }
 
         // now add all unomi defined event types
-        final List<JSONSchema> unomiEventTypes = schemaRegistry.getSchemasByTarget("events");
+        final List<JSONSchema> unomiEventTypes = schemaService.getSchemasByTarget("events");
         unomiEventTypes.forEach(eventType -> {
             final String typeName = UnomiToGraphQLConverter.convertEventType(eventType.getName());
             final GraphQLInputType eventInputType = (GraphQLInputType) getFromTypeRegistry(typeName + "Input");
@@ -812,15 +812,15 @@
                 .getGraphQLType(annotatedClass, graphQLAnnotations.getContainer(), false);
     }
 
-    public static Builder create(final ProfileService profileService, final SchemaRegistry schemaRegistry) {
-        return new Builder(profileService, schemaRegistry);
+    public static Builder create(final ProfileService profileService, final SchemaService schemaService) {
+        return new Builder(profileService, schemaService);
     }
 
     static class Builder {
 
         final ProfileService profileService;
 
-        final SchemaRegistry schemaRegistry;
+        final SchemaService schemaService;
 
         List<GraphQLTypeFunctionProvider> typeFunctionProviders;
 
@@ -840,9 +840,9 @@
 
         UnomiEventPublisher eventPublisher;
 
-        private Builder(final ProfileService profileService, final SchemaRegistry schemaRegistry) {
+        private Builder(final ProfileService profileService, final SchemaService schemaService) {
             this.profileService = profileService;
-            this.schemaRegistry = schemaRegistry;
+            this.schemaService = schemaService;
         }
 
         public Builder typeFunctionProviders(List<GraphQLTypeFunctionProvider> typeFunctionProviders) {
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java
index 24fb973..7d6198d 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java
@@ -21,7 +21,7 @@
 import graphql.schema.GraphQLCodeRegistry;
 import graphql.schema.GraphQLSchema;
 import org.apache.unomi.api.services.ProfileService;
-import org.apache.unomi.api.services.SchemaRegistry;
+import org.apache.unomi.api.services.SchemaService;
 import org.apache.unomi.graphql.fetchers.event.UnomiEventPublisher;
 import org.apache.unomi.graphql.providers.GraphQLAdditionalTypesProvider;
 import org.apache.unomi.graphql.providers.GraphQLCodeRegistryProvider;
@@ -83,7 +83,7 @@
 
     private ProfileService profileService;
 
-    private SchemaRegistry schemaRegistry;
+    private SchemaService schemaService;
 
     private CDPEventInterfaceRegister eventInterfaceRegister;
 
@@ -131,8 +131,8 @@
     }
 
     @Reference
-    public void setSchemaRegistry(SchemaRegistry schemaRegistry) {
-        this.schemaRegistry = schemaRegistry;
+    public void setSchemaService(SchemaService schemaService) {
+        this.schemaService = schemaService;
     }
 
     @Reference
@@ -330,7 +330,7 @@
 
     @SuppressWarnings("unchecked")
     private GraphQLSchema createGraphQLSchema() {
-        final GraphQLSchemaProvider schemaProvider = GraphQLSchemaProvider.create(profileService, schemaRegistry)
+        final GraphQLSchemaProvider schemaProvider = GraphQLSchemaProvider.create(profileService, schemaService)
                 .typeFunctionProviders(typeFunctionProviders)
                 .extensionsProviders(extensionsProviders)
                 .additionalTypesProviders(additionalTypesProviders)
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java
index 9f62673..2d6cebb 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java
@@ -19,7 +19,7 @@
 import graphql.TypeResolutionEnvironment;
 import graphql.schema.GraphQLObjectType;
 import org.apache.unomi.api.schema.json.JSONSchema;
-import org.apache.unomi.api.services.SchemaRegistry;
+import org.apache.unomi.api.services.SchemaService;
 import org.apache.unomi.graphql.converters.UnomiToGraphQLConverter;
 import org.apache.unomi.graphql.services.ServiceManager;
 import org.apache.unomi.graphql.types.output.CDPEventInterface;
@@ -29,10 +29,12 @@
     @Override
     public GraphQLObjectType getType(TypeResolutionEnvironment env) {
         final ServiceManager serviceManager = env.getContext();
-        SchemaRegistry schemaRegistry = serviceManager.getService(SchemaRegistry.class);
+        SchemaService schemaService = serviceManager.getService(SchemaService.class);
 
         final CDPEventInterface eventInterface = env.getObject();
-        final JSONSchema eventSchema = schemaRegistry.getSchema("https://unomi.apache.org/schemas/json/events/" + eventInterface.getEvent().getEventType() + "/1-0-0");
+        final JSONSchema eventSchema =
+                schemaService.getSchema("https://unomi.apache.org/schemas/json/events/" + eventInterface.getEvent().getEventType() + "/1-0"
+                        + "-0");
         if (eventSchema != null) {
             final String typeName = UnomiToGraphQLConverter.convertEventType(eventSchema.getName());
             return env.getSchema().getObjectType(typeName);
diff --git a/itests/src/test/java/org/apache/unomi/itests/JSONSchemaIT.java b/itests/src/test/java/org/apache/unomi/itests/JSONSchemaIT.java
index 086aa04..3719038 100644
--- a/itests/src/test/java/org/apache/unomi/itests/JSONSchemaIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/JSONSchemaIT.java
@@ -20,7 +20,8 @@
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.entity.ContentType;
 import org.apache.unomi.api.schema.UnomiJSONSchema;
-import org.apache.unomi.api.services.SchemaRegistry;
+import org.apache.unomi.api.schema.JSONSchemaExtension;
+import org.apache.unomi.api.services.SchemaService;
 import org.apache.unomi.persistence.spi.PersistenceService;
 import org.junit.After;
 import org.junit.Before;
@@ -49,12 +50,13 @@
 @ExamReactorStrategy(PerSuite.class)
 public class JSONSchemaIT extends BaseIT {
     private final static String JSONSCHEMA_URL = "/cxs/jsonSchema";
+    private final static String JSONSCHEMAEXTENSION_URL = "/cxs/jsonSchemaExtension";
     private static final int DEFAULT_TRYING_TIMEOUT = 2000;
     private static final int DEFAULT_TRYING_TRIES = 30;
 
     @Inject
     @Filter(timeout = 600000)
-    protected SchemaRegistry schemaRegistry;
+    protected SchemaService schemaService;
 
     @Inject
     @Filter(timeout = 600000)
@@ -64,11 +66,14 @@
     public void setUp() throws InterruptedException {
         keepTrying("Couldn't find json schema endpoint", () -> get(JSONSCHEMA_URL, List.class), Objects::nonNull, DEFAULT_TRYING_TIMEOUT,
                 DEFAULT_TRYING_TRIES);
+        keepTrying("Couldn't find json schema extension endpoint", () -> get(JSONSCHEMAEXTENSION_URL, List.class), Objects::nonNull,
+                DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
     }
 
     @After
     public void tearDown() {
-        schemaRegistry.deleteSchema("https://unomi.apache.org/schemas/json/events/test-event-type/1-0-0");
+        schemaService.deleteSchema("https://unomi.apache.org/schemas/json/events/test-event-type/1-0-0");
+        schemaService.deleteExtension("extension-test-event-1");
     }
 
     @Test
@@ -124,4 +129,48 @@
             assertEquals("Save should have failed", 500, response.getStatusLine().getStatusCode());
         }
     }
+
+    @Test
+    public void testGetJsonSchemaExtensionsMetadatas() throws InterruptedException {
+        List jsonSchemaExtensions = get(JSONSCHEMAEXTENSION_URL, List.class);
+        assertTrue("JSON schema extension list should be empty", jsonSchemaExtensions.isEmpty());
+
+        post(JSONSCHEMAEXTENSION_URL, "schemas/extension/extension-test-event-example.json", ContentType.TEXT_PLAIN);
+
+        jsonSchemaExtensions = keepTrying("Couldn't find json extensions", () -> get(JSONSCHEMAEXTENSION_URL, List.class),
+                (list) -> !list.isEmpty(), DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+        assertFalse("JSON schema list should not be empty", jsonSchemaExtensions.isEmpty());
+        assertEquals("JSON schema list should not be empty", 1, jsonSchemaExtensions.size());
+    }
+
+    @Test
+    public void testSaveNewJSONSchemaExtension() throws InterruptedException {
+
+        assertTrue("JSON schema list should be empty", persistenceService.getAllItems(JSONSchemaExtension.class).isEmpty());
+
+        CloseableHttpResponse response = post(JSONSCHEMAEXTENSION_URL, "schemas/extension/extension-test-event-example.json",
+                ContentType.TEXT_PLAIN);
+
+        assertEquals("Invalid response code", 200, response.getStatusLine().getStatusCode());
+
+        keepTrying("Couldn't find json schemas extensions", () -> get(JSONSCHEMAEXTENSION_URL, List.class), (list) -> !list.isEmpty(),
+                DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+    }
+
+    @Test
+    public void testDeleteJSONSchemaExtension() throws InterruptedException {
+        assertTrue("JSON schema list should be empty", persistenceService.getAllItems(JSONSchemaExtension.class).isEmpty());
+
+        post(JSONSCHEMAEXTENSION_URL, "schemas/extension/extension-test-event-example.json", ContentType.TEXT_PLAIN);
+
+        keepTrying("Couldn't find json schemas extension", () -> get(JSONSCHEMAEXTENSION_URL, List.class), (list) -> !list.isEmpty(),
+                DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+
+        CloseableHttpResponse response = delete(JSONSCHEMAEXTENSION_URL + "/extension-test-event-1");
+        assertEquals("Invalid response code", 204, response.getStatusLine().getStatusCode());
+
+        keepTrying("wait for empty list of schemas extensions", () -> get(JSONSCHEMA_URL, List.class), List::isEmpty,
+                DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+    }
+
 }
diff --git a/itests/src/test/resources/schemas/extension/extension-test-event-example.json b/itests/src/test/resources/schemas/extension/extension-test-event-example.json
new file mode 100644
index 0000000..b68e5e1
--- /dev/null
+++ b/itests/src/test/resources/schemas/extension/extension-test-event-example.json
@@ -0,0 +1,26 @@
+{
+  "id": "extension-test-event-1",
+  "schemaId": "https://unomi.apache.org/schemas/json/events/test-event-type/1-0-0",
+  "description": "An event for example",
+  "name": "Name of the event",
+  "priority": "10",
+  "extension": {
+    "allOf": [
+      {
+        "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0"
+      }
+    ],
+    "properties": {
+      "properties": {
+        "type": "object",
+        "properties": {
+          "floatProperty": {
+            "type": "number",
+            "maximum": "100",
+            "description": "Extension of float property"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/rest/src/main/java/org/apache/unomi/rest/endpoints/JsonSchemaEndPoint.java b/rest/src/main/java/org/apache/unomi/rest/endpoints/JsonSchemaEndPoint.java
index 96992d2..dfc8900 100644
--- a/rest/src/main/java/org/apache/unomi/rest/endpoints/JsonSchemaEndPoint.java
+++ b/rest/src/main/java/org/apache/unomi/rest/endpoints/JsonSchemaEndPoint.java
@@ -19,7 +19,7 @@
 
 import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
 import org.apache.unomi.api.Metadata;
-import org.apache.unomi.api.services.SchemaRegistry;
+import org.apache.unomi.api.services.SchemaService;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Reference;
 import org.slf4j.Logger;
@@ -51,15 +51,15 @@
     private static final Logger logger = LoggerFactory.getLogger(JsonSchemaEndPoint.class.getName());
 
     @Reference
-    private SchemaRegistry schemaRegistry;
+    private SchemaService schemaService;
 
     public JsonSchemaEndPoint() {
-        logger.info("Initializing JSON schema service endpoint...");
+        logger.info("Initializing JSON schema endpoint...");
     }
 
     @WebMethod(exclude = true)
-    public void setSchemaRegistry(SchemaRegistry schemaRegistry) {
-        this.schemaRegistry = schemaRegistry;
+    public void setSchemaService(SchemaService schemaService) {
+        this.schemaService = schemaService;
     }
 
     /**
@@ -77,7 +77,7 @@
     @Path("/")
     public List<Metadata> getJsonSchemaMetadatas(@QueryParam("offset") @DefaultValue("0") int offset,
             @QueryParam("size") @DefaultValue("50") int size, @QueryParam("sort") String sortBy) {
-        return schemaRegistry.getJsonSchemaMetadatas(offset, size, sortBy).getList();
+        return schemaService.getJsonSchemaMetadatas(offset, size, sortBy).getList();
     }
 
     /**
@@ -91,7 +91,7 @@
     @Consumes(MediaType.TEXT_PLAIN)
     @Produces(MediaType.APPLICATION_JSON)
     public Response save(String jsonSchema) {
-        schemaRegistry.saveSchema(jsonSchema);
+        schemaService.saveSchema(jsonSchema);
         return Response.ok().build();
     }
 
@@ -104,6 +104,6 @@
     @DELETE
     @Path("/{base64JsonSchemaId}")
     public void remove(@PathParam("base64JsonSchemaId") String base64JsonSchemaId) {
-        schemaRegistry.deleteSchema(new String(Base64.getDecoder().decode(base64JsonSchemaId)));
+        schemaService.deleteSchema(new String(Base64.getDecoder().decode(base64JsonSchemaId)));
     }
 }
diff --git a/rest/src/main/java/org/apache/unomi/rest/endpoints/JsonSchemaExtensionEndPoint.java b/rest/src/main/java/org/apache/unomi/rest/endpoints/JsonSchemaExtensionEndPoint.java
new file mode 100644
index 0000000..5033124
--- /dev/null
+++ b/rest/src/main/java/org/apache/unomi/rest/endpoints/JsonSchemaExtensionEndPoint.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.unomi.rest.endpoints;
+
+import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
+import org.apache.unomi.api.Metadata;
+import org.apache.unomi.api.services.SchemaService;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jws.WebMethod;
+import javax.jws.WebService;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.util.List;
+
+@WebService
+@Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
+@CrossOriginResourceSharing(allowAllOrigins = true, allowCredentials = true)
+@Path("/jsonSchemaExtension")
+@Component(service = JsonSchemaExtensionEndPoint.class, property = "osgi.jaxrs.resource=true")
+public class JsonSchemaExtensionEndPoint {
+
+    private static final Logger logger = LoggerFactory.getLogger(JsonSchemaExtensionEndPoint.class.getName());
+
+    @Reference
+    private SchemaService schemaService;
+
+    public JsonSchemaExtensionEndPoint() {
+        logger.info("Initializing JSON schema extension endpoint...");
+    }
+
+    @WebMethod(exclude = true)
+    public void setSchemaService(SchemaService schemaService) {
+        this.schemaService = schemaService;
+    }
+
+    /**
+     * Retrieves the 50 first json schema extension metadatas by default.
+     *
+     * @param offset zero or a positive integer specifying the position of the first element in the total ordered collection of matching elements
+     * @param size   a positive integer specifying how many matching elements should be retrieved or {@code -1} if all of them should be retrieved
+     * @param sortBy an optional ({@code null} if no sorting is required) String of comma ({@code ,}) separated property names on which ordering should be performed, ordering
+     *               elements according to the property order in the
+     *               String, considering each in turn and moving on to the next one in case of equality of all preceding ones. Each property name is optionally followed by
+     *               a column ({@code :}) and an order specifier: {@code asc} or {@code desc}.
+     * @return a List of the 50 first json schema metadata
+     */
+    @GET
+    @Path("/")
+    public List<Metadata> getJsonSchemaExtensionsMetadatas(@QueryParam("offset") @DefaultValue("0") int offset,
+            @QueryParam("size") @DefaultValue("50") int size, @QueryParam("sort") String sortBy) {
+        return schemaService.getJsonSchemaExtensionsMetadatas(offset, size, sortBy).getList();
+    }
+
+    /**
+     * Save a JSON schema extension
+     *
+     * @param jsonSchemaExtension the schema as string to save
+     * @return Response of the API call
+     */
+    @POST
+    @Path("/")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response save(String jsonSchemaExtension) throws IOException {
+        schemaService.saveExtension(jsonSchemaExtension);
+        return Response.ok().build();
+    }
+
+    /**
+     * Deletes a JSON schema extension.
+     * The id is a Base64 id as the id have is basically an URL
+     *
+     * @param id the identifier of the JSON schema that we want to delete
+     */
+    @DELETE
+    @Path("/{id}")
+    public void remove(@PathParam("id") String id) {
+        schemaService.deleteExtension(id);
+    }
+}
diff --git a/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java b/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
index ddaefea..20fbdfe 100644
--- a/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/impl/events/EventServiceImpl.java
@@ -63,7 +63,7 @@
 
     private BundleContext bundleContext;
 
-    private SchemaRegistry schemaRegistry;
+    private SchemaService schemaService;
 
     private Set<String> predefinedEventTypeIds = new LinkedHashSet<String>();
 
@@ -112,8 +112,8 @@
         this.shouldBeCheckedEventSourceId = shouldBeCheckedEventSourceId;
     }
 
-    public void setSchemaRegistry(SchemaRegistry schemaRegistry) {
-        this.schemaRegistry = schemaRegistry;
+    public void setSchemaService(SchemaService schemaService) {
+        this.schemaService = schemaService;
     }
     public void setPersistenceService(PersistenceService persistenceService) {
         this.persistenceService = persistenceService;
@@ -139,7 +139,7 @@
     }
 
     public boolean isEventValid(Event event) {
-        return schemaRegistry.isValid(event, "https://unomi.apache.org/schemas/json/events/" + event.getEventType() + "/1-0-0");
+        return schemaService.isValid(event, "https://unomi.apache.org/schemas/json/events/" + event.getEventType() + "/1-0-0");
     }
 
     public String authenticateThirdPartyServer(String key, String ip) {
diff --git a/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java b/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaServiceImpl.java
similarity index 78%
rename from services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java
rename to services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaServiceImpl.java
index ae4e3db..c9c1e96 100644
--- a/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java
+++ b/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaServiceImpl.java
@@ -30,12 +30,13 @@
 import org.apache.commons.io.IOUtils;
 import org.apache.unomi.api.Metadata;
 import org.apache.unomi.api.PartialList;
+import org.apache.unomi.api.schema.JSONSchemaExtension;
 import org.apache.unomi.api.schema.UnomiJSONSchema;
 import org.apache.unomi.api.schema.json.JSONSchema;
 import org.apache.unomi.api.schema.json.JSONTypeFactory;
 import org.apache.unomi.api.services.ProfileService;
 import org.apache.unomi.api.services.SchedulerService;
-import org.apache.unomi.api.services.SchemaRegistry;
+import org.apache.unomi.api.services.SchemaService;
 import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.persistence.spi.PersistenceService;
 import org.osgi.framework.BundleContext;
@@ -56,16 +57,18 @@
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
-public class SchemaRegistryImpl implements SchemaRegistry {
+public class SchemaServiceImpl implements SchemaService {
 
     private static final String URI = "https://json-schema.org/draft/2019-09/schema";
 
-    private static final Logger logger = LoggerFactory.getLogger(SchemaRegistryImpl.class.getName());
+    private static final Logger logger = LoggerFactory.getLogger(SchemaServiceImpl.class.getName());
 
     private final Map<String, JSONSchema> predefinedUnomiJSONSchemaById = new HashMap<>();
 
     private Map<String, JSONSchema> schemasById = new HashMap<>();
 
+    private Map<String, JSONSchemaExtension> extensionById = new HashMap<>();
+
     private BundleContext bundleContext;
 
     private ProfileService profileService;
@@ -110,7 +113,7 @@
         JsonSchema jsonSchema = null;
         try {
             JSONSchema validationSchema = schemasById.get(schemaId);
-            if (validationSchema != null){
+            if (validationSchema != null) {
                 schemaAsString = objectMapper.writeValueAsString(schemasById.get(schemaId).getSchemaTree());
                 jsonSchema = jsonSchemaFactory.getSchema(schemaAsString);
             } else {
@@ -180,6 +183,55 @@
     }
 
     @Override
+    public void saveExtension(InputStream extensionStream) throws IOException {
+        saveExtension(IOUtils.toString(extensionStream));
+    }
+
+    @Override
+    public void saveExtension(String extension) throws IOException {
+        JSONSchemaExtension jsonSchemaExtension = buildExtension(extension);
+        persistenceService.save(jsonSchemaExtension);
+        extensionById.put(jsonSchemaExtension.getId(), jsonSchemaExtension);
+    }
+
+    @Override
+    public boolean deleteExtension(InputStream extensionStream) throws IOException {
+        JsonNode jsonNode = objectMapper.readTree(extensionStream);
+        return deleteExtension(jsonNode.get("id").asText());
+    }
+
+    @Override
+    public boolean deleteExtension(String extensionId) {
+        extensionById.remove(extensionId);
+        return persistenceService.remove(extensionId, JSONSchemaExtension.class);
+    }
+
+    @Override
+    public PartialList<Metadata> getJsonSchemaExtensionsMetadatas(int offset, int size, String sortBy) {
+        PartialList<JSONSchemaExtension> items = persistenceService.getAllItems(JSONSchemaExtension.class, offset, size, sortBy);
+        List<Metadata> details = new LinkedList<>();
+        for (JSONSchemaExtension definition : items.getList()) {
+            details.add(definition.getMetadata());
+        }
+        return new PartialList<>(details, items.getOffset(), items.getPageSize(), items.getTotalSize(), items.getTotalSizeRelation());
+    }
+
+    private JSONSchemaExtension buildExtension(String extension) throws JsonProcessingException {
+        JsonNode jsonNode = objectMapper.readTree(extension);
+        JSONSchemaExtension jsonSchemaExtension = new JSONSchemaExtension();
+        jsonSchemaExtension.setId(jsonNode.get("id").asText());
+        jsonSchemaExtension.setSchemaId(jsonNode.get("schemaId").asText());
+        jsonSchemaExtension.setExtension(jsonNode.get("extension").toString());
+        jsonSchemaExtension.setPriority(jsonNode.get("priority").asDouble());
+        Metadata metadata = new Metadata();
+        metadata.setId(jsonNode.get("id").asText());
+        metadata.setDescription(jsonNode.get("description").asText());
+        metadata.setName(jsonNode.get("name").asText());
+        jsonSchemaExtension.setMetadata(metadata);
+        return jsonSchemaExtension;
+    }
+
+    @Override
     public JSONSchema getSchema(String schemaId) {
         return schemasById.get(schemaId);
     }
@@ -239,11 +291,17 @@
                 jsonSchema -> schemasById.put(jsonSchema.getId(), buildJSONSchema(jsonSchemaFactory.getSchema(jsonSchema.getSchema()))));
     }
 
+    private void refreshJSONSchemasExtensions() {
+        extensionById = new HashMap<>();
+        persistenceService.getAllItems(JSONSchemaExtension.class).forEach(extension -> extensionById.put(extension.getId(), extension));
+    }
+
     private void initializeTimers() {
         TimerTask task = new TimerTask() {
             @Override
             public void run() {
                 refreshJSONSchemas();
+                refreshJSONSchemasExtensions();
             }
         };
         scheduledFuture = schedulerService.getScheduleExecutorService()
@@ -251,19 +309,18 @@
     }
 
     public void init() {
-
         JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder(URI, JsonMetaSchema.getV201909())
                 .addKeyword(new UnomiPropertyTypeKeyword(profileService, this)).addKeyword(new NonValidationKeyword("self")).build();
         jsonSchemaFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909))
                 .addMetaSchema(jsonMetaSchema).defaultMetaSchemaURI(URI).uriFetcher(getUriFetcher(), "https", "http").build();
 
         initializeTimers();
-        logger.info("Schema registry initialized.");
+        logger.info("Schema service initialized.");
     }
 
     public void destroy() {
         scheduledFuture.cancel(true);
-        logger.info("Schema registry shutdown.");
+        logger.info("Schema service shutdown.");
     }
 
     public void setBundleContext(BundleContext bundleContext) {
diff --git a/services/src/main/java/org/apache/unomi/services/impl/schemas/UnomiPropertyTypeKeyword.java b/services/src/main/java/org/apache/unomi/services/impl/schemas/UnomiPropertyTypeKeyword.java
index 2f02d51..973d4ac 100644
--- a/services/src/main/java/org/apache/unomi/services/impl/schemas/UnomiPropertyTypeKeyword.java
+++ b/services/src/main/java/org/apache/unomi/services/impl/schemas/UnomiPropertyTypeKeyword.java
@@ -27,8 +27,7 @@
 import com.networknt.schema.ValidationMessage;
 import org.apache.unomi.api.PropertyType;
 import org.apache.unomi.api.services.ProfileService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.unomi.api.services.SchemaService;
 
 import java.text.MessageFormat;
 import java.util.Collection;
@@ -41,7 +40,7 @@
 class UnomiPropertyTypeKeyword extends AbstractKeyword {
 
     private final ProfileService profileService;
-    private final SchemaRegistryImpl schemaRegistry;
+    private final SchemaServiceImpl schemaService;
 
     private static final class UnomiPropertyTypeJsonValidator extends AbstractJsonValidator {
 
@@ -50,17 +49,17 @@
         JsonSchema parentSchema;
         ValidationContext validationContext;
         ProfileService profileService;
-        SchemaRegistryImpl schemaRegistry;
+        SchemaServiceImpl schemaService;
 
         public UnomiPropertyTypeJsonValidator(String keyword, String schemaPath, JsonNode schemaNode, JsonSchema parentSchema,
-                ValidationContext validationContext, ProfileService profileService, SchemaRegistryImpl schemaRegistry) {
+                ValidationContext validationContext, ProfileService profileService, SchemaServiceImpl schemaService) {
             super(keyword);
             this.schemaPath = schemaPath;
             this.schemaNode = schemaNode;
             this.parentSchema = parentSchema;
             this.validationContext = validationContext;
             this.profileService = profileService;
-            this.schemaRegistry = schemaRegistry;
+            this.schemaService = schemaService;
         }
 
         @Override
@@ -76,7 +75,7 @@
                 } else {
                     // @todo further validation, if it can be used in this context (event, profile, session)
                     String valueTypeId = propertyType.getValueTypeId();
-                    JsonSchema jsonSchema = schemaRegistry
+                    JsonSchema jsonSchema = schemaService
                             .getJsonSchema("https://unomi.apache.org/schemas/json/values/" + valueTypeId + ".json");
                     if (jsonSchema == null) {
                         validationMessages.add(buildValidationMessage(CustomErrorMessageType
@@ -112,16 +111,16 @@
         }
     }
 
-    public UnomiPropertyTypeKeyword(ProfileService profileService, SchemaRegistryImpl schemaRegistry) {
+    public UnomiPropertyTypeKeyword(ProfileService profileService, SchemaServiceImpl schemaService) {
         super("unomiPropertyTypes");
         this.profileService = profileService;
-        this.schemaRegistry = schemaRegistry;
+        this.schemaService = schemaService;
     }
 
     @Override
     public JsonValidator newValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, ValidationContext validationContext)
             throws JsonSchemaException, Exception {
         return new UnomiPropertyTypeJsonValidator(this.getValue(), schemaPath, schemaNode, parentSchema, validationContext, profileService,
-                schemaRegistry);
+                schemaService);
     }
 }
diff --git a/services/src/main/java/org/apache/unomi/services/listener/JsonSchemaListener.java b/services/src/main/java/org/apache/unomi/services/listener/JsonSchemaListener.java
index b3b2fd2..21dab22 100644
--- a/services/src/main/java/org/apache/unomi/services/listener/JsonSchemaListener.java
+++ b/services/src/main/java/org/apache/unomi/services/listener/JsonSchemaListener.java
@@ -16,8 +16,9 @@
  */
 package org.apache.unomi.services.listener;
 
+import org.apache.unomi.api.schema.JSONSchemaExtension;
 import org.apache.unomi.api.schema.UnomiJSONSchema;
-import org.apache.unomi.api.services.SchemaRegistry;
+import org.apache.unomi.api.services.SchemaService;
 import org.apache.unomi.persistence.spi.PersistenceService;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
@@ -33,16 +34,19 @@
 /**
  * An implementation of a BundleListener for the JSON schema.
  * It will load the pre-defined schema files in the folder META-INF/cxs/schemas.
- * The script will be stored in the ES index jsonSchemas
+ * It will load the extension of schema in the folder META-INF/cxs/schemasextensions.
+ * The scripts will be stored in the ES index jsonSchema and the extension will be stored in jsonSchemaExtension
  */
 public class JsonSchemaListener implements SynchronousBundleListener {
 
     private static final Logger logger = LoggerFactory.getLogger(JsonSchemaListener.class.getName());
     public static final String ENTRIES_LOCATION = "META-INF/cxs/schemas";
 
+    public static final String EXTENSIONS_ENTRIES_LOCATION = "META-INF/cxs/schemasextensions";
+
     private PersistenceService persistenceService;
 
-    private SchemaRegistry schemaRegistry;
+    private SchemaService schemaService;
 
     private BundleContext bundleContext;
 
@@ -50,8 +54,8 @@
         this.persistenceService = persistenceService;
     }
 
-    public void setSchemaRegistry(SchemaRegistry schemaRegistry) {
-        this.schemaRegistry = schemaRegistry;
+    public void setSchemaService(SchemaService schemaService) {
+        this.schemaService = schemaService;
     }
 
     public void setBundleContext(BundleContext bundleContext) {
@@ -61,13 +65,14 @@
     public void postConstruct() {
         logger.info("JSON schema listener initializing...");
         logger.debug("postConstruct {}", bundleContext.getBundle());
-        createIndex();
+        createIndexes();
 
         loadPredefinedSchemas(bundleContext);
 
         for (Bundle bundle : bundleContext.getBundles()) {
             if (bundle.getBundleContext() != null && bundle.getBundleId() != bundleContext.getBundle().getBundleId()) {
                 saveSchemas(bundle.getBundleContext());
+                saveExtensions(bundle.getBundleContext());
             }
         }
 
@@ -92,6 +97,7 @@
             return;
         }
         unloadSchemas(bundleContext);
+        unloadExtensions(bundleContext);
     }
 
     public void bundleChanged(BundleEvent event) {
@@ -107,12 +113,17 @@
         }
     }
 
-    public void createIndex() {
+    public void createIndexes() {
         if (persistenceService.createIndex(UnomiJSONSchema.ITEM_TYPE)) {
             logger.info("{} index created", UnomiJSONSchema.ITEM_TYPE);
         } else {
             logger.info("{} index already exists", UnomiJSONSchema.ITEM_TYPE);
         }
+        if (persistenceService.createIndex(JSONSchemaExtension.ITEM_TYPE)) {
+            logger.info("{} index created", JSONSchemaExtension.ITEM_TYPE);
+        } else {
+            logger.info("{} index already exists", JSONSchemaExtension.ITEM_TYPE);
+        }
     }
 
     private void saveSchemas(BundleContext bundleContext) {
@@ -126,7 +137,7 @@
             logger.debug("Found JSON schema at {}, loading... ", predefinedSchemaURL);
 
             try (InputStream schemaInputStream = predefinedSchemaURL.openStream()) {
-                schemaRegistry.saveSchema(schemaInputStream);
+                schemaService.saveSchema(schemaInputStream);
             } catch (Exception e) {
                 logger.error("Error while loading schema definition {}", predefinedSchemaURL, e);
             }
@@ -143,7 +154,7 @@
             URL predefinedSchemaURL = predefinedSchemas.nextElement();
             logger.debug("Found predefined JSON schema at {}, loading... ", predefinedSchemaURL);
             try (InputStream schemaInputStream = predefinedSchemaURL.openStream()) {
-                schemaRegistry.loadPredefinedSchema(schemaInputStream);
+                schemaService.loadPredefinedSchema(schemaInputStream);
             } catch (Exception e) {
                 logger.error("Error while loading schema definition {}", predefinedSchemaURL, e);
             }
@@ -161,10 +172,46 @@
             logger.debug("Found predefined JSON schema at {}, loading... ", predefinedSchemaURL);
 
             try (InputStream schemaInputStream = predefinedSchemaURL.openStream()) {
-                schemaRegistry.deleteSchema(schemaInputStream);
+                schemaService.deleteSchema(schemaInputStream);
             } catch (Exception e) {
                 logger.error("Error while removing schema at {}", predefinedSchemaURL, e);
             }
         }
     }
+
+    private void saveExtensions(BundleContext bundleContext) {
+        Enumeration<URL> extensions = bundleContext.getBundle().findEntries(EXTENSIONS_ENTRIES_LOCATION, "*.json", true);
+        if (extensions == null) {
+            return;
+        }
+
+        while (extensions.hasMoreElements()) {
+            URL extensionURL = extensions.nextElement();
+            logger.debug("Found JSON schema extension at {}, loading... ", extensionURL);
+
+            try (InputStream extensionInputStream = extensionURL.openStream()) {
+                schemaService.saveExtension(extensionInputStream);
+            } catch (Exception e) {
+                logger.error("Error while loading schema extension at {}", extensionURL, e);
+            }
+        }
+    }
+
+    private void unloadExtensions(BundleContext bundleContext) {
+        Enumeration<URL> extensions = bundleContext.getBundle().findEntries(EXTENSIONS_ENTRIES_LOCATION, "*.json", true);
+        if (extensions == null) {
+            return;
+        }
+
+        while (extensions.hasMoreElements()) {
+            URL predefinedSchemaURL = extensions.nextElement();
+            logger.debug("Found JSON schema extension at {}, loading... ", predefinedSchemaURL);
+
+            try (InputStream extensionInputStream = predefinedSchemaURL.openStream()) {
+                schemaService.deleteExtension(extensionInputStream);
+            } catch (Exception e) {
+                logger.error("Error while loading schema extension at {}", predefinedSchemaURL, e);
+            }
+        }
+    }
 }
diff --git a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 4be07c9..1d1417c 100644
--- a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -102,7 +102,7 @@
         </interfaces>
     </service>
 
-    <bean id="schemaRegistryImpl" class="org.apache.unomi.services.impl.schemas.SchemaRegistryImpl" init-method="init"
+    <bean id="schemaServiceImpl" class="org.apache.unomi.services.impl.schemas.SchemaServiceImpl" init-method="init"
           destroy-method="destroy">
         <property name="bundleContext" ref="blueprintBundleContext"/>
         <property name="profileService" ref="profileServiceImpl"/>
@@ -110,13 +110,13 @@
         <property name="schedulerService" ref="schedulerServiceImpl"/>
         <property name="jsonSchemaRefreshInterval" value="${services.json.schema.refresh.interval}"/>
     </bean>
-    <service id="schemaRegistry" ref="schemaRegistryImpl" interface="org.apache.unomi.api.services.SchemaRegistry"/>
+    <service id="schemaService" ref="schemaServiceImpl" interface="org.apache.unomi.api.services.SchemaService"/>
 
     <bean id="jsonSchemaListenerImpl" class="org.apache.unomi.services.listener.JsonSchemaListener"
           init-method="postConstruct" destroy-method="preDestroy">
         <property name="persistenceService" ref="persistenceService"/>
         <property name="bundleContext" ref="blueprintBundleContext"/>
-        <property name="schemaRegistry" ref="schemaRegistryImpl"/>
+        <property name="schemaService" ref="schemaServiceImpl"/>
     </bean>
     <service id="jsonSchemaListener" ref="jsonSchemaListenerImpl">
         <interfaces>
@@ -129,7 +129,7 @@
         <property name="definitionsService" ref="definitionsServiceImpl"/>
         <property name="sourceService" ref="sourceServiceImpl"/>
         <property name="bundleContext" ref="blueprintBundleContext"/>
-        <property name="schemaRegistry" ref="schemaRegistryImpl"/>
+        <property name="schemaService" ref="schemaServiceImpl"/>
         <property name="predefinedEventTypeIds">
             <set>
                 <value>view</value>