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>