You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by jk...@apache.org on 2022/05/19 16:59:05 UTC
[unomi] 01/01: UNOMI-571: Fix concurrency issue, cache issue in JSON Schema and provide better tests coverage
This is an automated email from the ASF dual-hosted git repository.
jkevan pushed a commit to branch json-schema-extensions
in repository https://gitbox.apache.org/repos/asf/unomi.git
commit 9f119bb582bc3bb33b5289be3748b57430fdfa3a
Author: Kevan <ke...@jahia.com>
AuthorDate: Thu May 19 18:58:48 2022 +0200
UNOMI-571: Fix concurrency issue, cache issue in JSON Schema and provide better tests coverage
---
.../unomi/schema/rest/JsonSchemaEndPoint.java | 20 +--
.../apache/unomi/schema/api/JsonSchemaWrapper.java | 51 ++++--
.../org/apache/unomi/schema/api/SchemaService.java | 25 +--
.../unomi/schema/impl/SchemaServiceImpl.java | 196 ++++++++++++---------
.../unomi/schema/listener/JsonSchemaListener.java | 16 --
.../resources/OSGI-INF/blueprint/blueprint.xml | 2 -
.../java/org/apache/unomi/itests/JSONSchemaIT.java | 145 ++++++++++-----
.../resources/schemas/event-dummy-invalid-1.json | 9 +
.../resources/schemas/event-dummy-invalid-2.json | 9 +
.../resources/schemas/event-dummy-invalid-3.json | 8 +
.../test/resources/schemas/event-dummy-valid.json | 8 +
.../resources/schemas/events/dummy-event-type.json | 43 -----
.../schemas/events/float-property-type.json | 23 ---
.../schemas/events/negative-test-event-type.json | 13 --
.../resources/schemas/events/test-event-type.json | 14 --
.../schemas/schema-dummy-properties-updated.json | 24 +++
.../resources/schemas/schema-dummy-properties.json | 21 +++
.../src/test/resources/schemas/schema-dummy.json | 22 +++
...-invalid-name.json => schema-invalid-name.json} | 0
.../test-invalid.json => schema-invalid.json} | 0
...ined-event-type.json => schema-predefined.json} | 4 +-
21 files changed, 362 insertions(+), 291 deletions(-)
diff --git a/extensions/json-schema/rest/src/main/java/org/apache/unomi/schema/rest/JsonSchemaEndPoint.java b/extensions/json-schema/rest/src/main/java/org/apache/unomi/schema/rest/JsonSchemaEndPoint.java
index 26f09222f..6c9fb021d 100644
--- a/extensions/json-schema/rest/src/main/java/org/apache/unomi/schema/rest/JsonSchemaEndPoint.java
+++ b/extensions/json-schema/rest/src/main/java/org/apache/unomi/schema/rest/JsonSchemaEndPoint.java
@@ -18,7 +18,6 @@
package org.apache.unomi.schema.rest;
import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing;
-import org.apache.unomi.api.Metadata;
import org.apache.unomi.rest.exception.InvalidRequestException;
import org.apache.unomi.schema.api.SchemaService;
import org.osgi.service.component.annotations.Component;
@@ -32,7 +31,7 @@ import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Base64;
-import java.util.List;
+import java.util.Set;
@WebService
@Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
@@ -56,21 +55,14 @@ public class JsonSchemaEndPoint {
}
/**
- * Retrieves the 50 first json schema metadatas by default.
+ * Get the list of installed Json Schema Ids
*
- * @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
+ * @return A Set of JSON schema ids
*/
@GET
@Path("/")
- public List<Metadata> getJsonSchemaMetadatas(@QueryParam("offset") @DefaultValue("0") int offset,
- @QueryParam("size") @DefaultValue("50") int size, @QueryParam("sort") String sortBy) {
- return schemaService.getJsonSchemaMetadatas(offset, size, sortBy).getList();
+ public Set<String> getInstalledJsonSchemaIds() {
+ return schemaService.getInstalledJsonSchemaIds();
}
/**
@@ -81,7 +73,7 @@ public class JsonSchemaEndPoint {
*/
@POST
@Path("/")
- @Consumes(MediaType.TEXT_PLAIN)
+ @Consumes({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON})
@Produces(MediaType.APPLICATION_JSON)
public Response save(String jsonSchema) {
try {
diff --git a/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/api/JsonSchemaWrapper.java b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/api/JsonSchemaWrapper.java
index ce123879e..41049519d 100644
--- a/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/api/JsonSchemaWrapper.java
+++ b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/api/JsonSchemaWrapper.java
@@ -17,8 +17,10 @@
package org.apache.unomi.schema.api;
-import org.apache.unomi.api.Metadata;
-import org.apache.unomi.api.MetadataItem;
+import org.apache.unomi.api.Item;
+import org.apache.unomi.api.TimestampedItem;
+
+import java.util.Date;
/**
* Object which represents a JSON schema, it's a wrapper because it contains some additional info used by the
@@ -26,35 +28,35 @@ import org.apache.unomi.api.MetadataItem;
* The JSON schema is store as String to avoid transformation during JSON schema resolution in the Unomi SchemaService.
* Also, it's extending MetadataItem so that it can be persisted like that in Unomi storage system.
*/
-public class JsonSchemaWrapper extends MetadataItem {
+public class JsonSchemaWrapper extends Item implements TimestampedItem {
public static final String ITEM_TYPE = "jsonSchema";
- private String id;
private String schema;
private String target;
+ private String extendsSchema;
+ private Date timeStamp;
- public JsonSchemaWrapper(){}
+ /**
+ * Instantiates a new JSON schema
+ */
+ public JsonSchemaWrapper() {
+ }
/**
- * Instantiates a new JSON schema with an id and a schema as string
+ * Instantiates a new JSON schema
*
* @param id id of the schema
* @param schema as string
- * @param target of the schema
+ * @param target of the schema (optional)
+ * @param extendsSchema is the URI of another Schema to be extended by current one. (optional)
+ * @param timeStamp of the schema
*/
- public JsonSchemaWrapper(String id, String schema, String target) {
- super(new Metadata(id));
- this.id = id;
+ public JsonSchemaWrapper(String id, String schema, String target, String extendsSchema, Date timeStamp) {
+ super(id);
this.schema = schema;
this.target = target;
- }
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
+ this.extendsSchema = extendsSchema;
+ this.timeStamp = timeStamp;
}
public String getSchema() {
@@ -72,4 +74,17 @@ public class JsonSchemaWrapper extends MetadataItem {
public void setTarget(String target) {
this.target = target;
}
+
+ public String getExtendsSchema() {
+ return extendsSchema;
+ }
+
+ public void setExtendsSchema(String extendsSchema) {
+ this.extendsSchema = extendsSchema;
+ }
+
+ @Override
+ public Date getTimeStamp() {
+ return timeStamp;
+ }
}
\ No newline at end of file
diff --git a/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/api/SchemaService.java b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/api/SchemaService.java
index c479c4015..34c11e7d5 100644
--- a/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/api/SchemaService.java
+++ b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/api/SchemaService.java
@@ -17,32 +17,16 @@
package org.apache.unomi.schema.api;
-import org.apache.unomi.api.Metadata;
-import org.apache.unomi.api.PartialList;
-
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
+import java.util.Set;
/**
* Service that allow to manage JSON schema. It allows to get, save and delete schemas
*/
public interface SchemaService {
- /**
- * Retrieves json schema 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 metadata
- */
- PartialList<Metadata> getJsonSchemaMetadatas(int offset, int size, String sortBy);
-
/**
* Verify if a jsonNode is valid against a schema
*
@@ -52,6 +36,13 @@ public interface SchemaService {
*/
boolean isValid(String data, String schemaId);
+ /**
+ * Get the list of installed Json Schema Ids
+ *
+ * @return A Set of JSON schema ids
+ */
+ Set<String> getInstalledJsonSchemaIds();
+
/**
* Get a schema matching by a schema id
*
diff --git a/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/impl/SchemaServiceImpl.java b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/impl/SchemaServiceImpl.java
index e91d29776..51625f438 100644
--- a/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/impl/SchemaServiceImpl.java
+++ b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/impl/SchemaServiceImpl.java
@@ -17,27 +17,25 @@
package org.apache.unomi.schema.impl;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.*;
import com.networknt.schema.uri.URIFetcher;
import org.apache.commons.io.IOUtils;
-import org.apache.unomi.api.Metadata;
-import org.apache.unomi.api.PartialList;
+import org.apache.unomi.api.Item;
import org.apache.unomi.api.services.SchedulerService;
import org.apache.unomi.persistence.spi.PersistenceService;
import org.apache.unomi.schema.api.JsonSchemaWrapper;
import org.apache.unomi.schema.api.SchemaService;
-import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
-import java.net.URISyntaxException;
import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -50,60 +48,84 @@ public class SchemaServiceImpl implements SchemaService {
ObjectMapper objectMapper = new ObjectMapper();
- private final Map<String, JsonSchemaWrapper> predefinedUnomiJSONSchemaById = new HashMap<>();
- private Map<String, JsonSchemaWrapper> schemasById = new HashMap<>();
+ private final ConcurrentMap<String, JsonSchemaWrapper> predefinedUnomiJSONSchemaById = new ConcurrentHashMap<>();
+ private ConcurrentMap<String, JsonSchemaWrapper> schemasById = new ConcurrentHashMap<>();
+
+ private final JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder(URI, JsonMetaSchema.getV201909())
+ .addKeyword(new NonValidationKeyword("self"))
+ .build();
+ private final URIFetcher jsonSchemaURIFetcher = uri -> {
+ logger.debug("Fetching schema {}", uri);
+ JsonSchemaWrapper jsonSchemaWrapper = schemasById.get(uri.toString());
+ if (jsonSchemaWrapper == null) {
+ logger.error("Couldn't find schema {}", uri);
+ return null;
+ }
+
+ return IOUtils.toInputStream(jsonSchemaWrapper.getSchema());
+ };
private Integer jsonSchemaRefreshInterval = 1000;
private ScheduledFuture<?> scheduledFuture;
- private BundleContext bundleContext;
private PersistenceService persistenceService;
private SchedulerService schedulerService;
private JsonSchemaFactory jsonSchemaFactory;
-
- @Override
- public PartialList<Metadata> getJsonSchemaMetadatas(int offset, int size, String sortBy) {
- PartialList<JsonSchemaWrapper> items = persistenceService.getAllItems(JsonSchemaWrapper.class, offset, size, sortBy);
- List<Metadata> details = new LinkedList<>();
- for (JsonSchemaWrapper definition : items.getList()) {
- details.add(definition.getMetadata());
- }
- return new PartialList<>(details, items.getOffset(), items.getPageSize(), items.getTotalSize(), items.getTotalSizeRelation());
- }
-
@Override
public boolean isValid(String data, String schemaId) {
- JsonSchema jsonSchema = null;
- JsonNode jsonNode = null;
+ JsonSchema jsonSchema;
+ JsonNode jsonNode;
try {
jsonNode = objectMapper.readTree(data);
jsonSchema = jsonSchemaFactory.getSchema(new URI(schemaId));
} catch (Exception e) {
- logger.error("Failed to process data to validate because {} - Set SchemaServiceImpl at DEBUG level for more detail ", e.getMessage());
+ logger.error("Schema validation failed because: {} - Set SchemaServiceImpl at DEBUG level for more detail ", e.getMessage());
logger.debug("full error",e);
return false;
}
if (jsonNode == null) {
- logger.warn("No data to validate");
+ // no data to validate
return false;
}
if (jsonSchema == null) {
- logger.warn("No schema found for {}", schemaId);
+ logger.warn("Schema validation failed because: Schema not found {}", schemaId);
+ return false;
+ }
+
+ Set<ValidationMessage> validationMessages;
+ try {
+ validationMessages = jsonSchema.validate(jsonNode);
+ } catch (Exception e) {
+ logger.error("Schema validation failed because: {} - Set SchemaServiceImpl at DEBUG level for more detail ", e.getMessage());
+ logger.debug("full error",e);
return false;
}
- Set<ValidationMessage> validationMessages = jsonSchema.validate(jsonNode);
if (validationMessages == null || validationMessages.isEmpty()) {
return true;
+ } else {
+ logger.error("Schema validation found {} errors while validating against schema: {} - Set SchemaServiceImpl at DEBUG level for more detail ", validationMessages.size(), schemaId);
+ if (logger.isDebugEnabled()) {
+ for (ValidationMessage validationMessage : validationMessages) {
+ logger.debug("Validation error: {}", validationMessage);
+ }
+ }
+ return false;
}
- for (ValidationMessage validationMessage : validationMessages) {
- logger.error("Error validating object against schema {}: {}", schemaId, validationMessage);
- }
- return false;
+ }
+
+ @Override
+ public JsonSchemaWrapper getSchema(String schemaId) {
+ return schemasById.get(schemaId);
+ }
+
+ @Override
+ public Set<String> getInstalledJsonSchemaIds() {
+ return schemasById.keySet();
}
@Override
@@ -114,22 +136,9 @@ public class SchemaServiceImpl implements SchemaService {
@Override
public void saveSchema(String schema) {
- JsonSchema jsonSchema = jsonSchemaFactory.getSchema(schema);
- JsonNode schemaNode = jsonSchema.getSchemaNode();
- String id = schemaNode.get("$id").asText();
-
- if (!predefinedUnomiJSONSchemaById.containsKey(id)) {
- String target = schemaNode.at("/self/target").asText();
- String name = schemaNode.at("/self/name").asText();
-
- if ("events".equals(target) && !name.matches("[_A-Za-z][_0-9A-Za-z]*")) {
- throw new IllegalArgumentException(
- "The \"/self/name\" value should match the following regular expression [_A-Za-z][_0-9A-Za-z]* for the Json schema on events");
- }
-
- JsonSchemaWrapper jsonSchemaWrapper = new JsonSchemaWrapper(id, schema, target);
+ JsonSchemaWrapper jsonSchemaWrapper = buildJsonSchemaWrapper(schema);
+ if (!predefinedUnomiJSONSchemaById.containsKey(jsonSchemaWrapper.getItemId())) {
persistenceService.save(jsonSchemaWrapper);
- schemasById.put(id, jsonSchemaWrapper);
} else {
throw new IllegalArgumentException("Trying to save a Json Schema that is using the ID of an existing Json Schema provided by Unomi is forbidden");
}
@@ -139,7 +148,7 @@ public class SchemaServiceImpl implements SchemaService {
public boolean deleteSchema(String schemaId) {
// forbidden to delete predefined Unomi schemas
if (!predefinedUnomiJSONSchemaById.containsKey(schemaId)) {
- schemasById.remove(schemaId);
+ // remove persisted schema
return persistenceService.remove(schemaId, JsonSchemaWrapper.class);
}
return false;
@@ -147,52 +156,69 @@ public class SchemaServiceImpl implements SchemaService {
@Override
public void loadPredefinedSchema(InputStream schemaStream) throws IOException {
- String jsonSchema = IOUtils.toString(schemaStream);
-
- // check that schema is valid and get the id
- JsonNode schemaNode = jsonSchemaFactory.getSchema(jsonSchema).getSchemaNode();
- String schemaId = schemaNode.get("$id").asText();
- String target = schemaNode.at("/self/target").asText();
- JsonSchemaWrapper jsonSchemaWrapper = new JsonSchemaWrapper(schemaId, jsonSchema, target);
-
- predefinedUnomiJSONSchemaById.put(schemaId, jsonSchemaWrapper);
- schemasById.put(schemaId, jsonSchemaWrapper);
+ String schema = IOUtils.toString(schemaStream);
+ JsonSchemaWrapper jsonSchemaWrapper = buildJsonSchemaWrapper(schema);
+ predefinedUnomiJSONSchemaById.put(jsonSchemaWrapper.getItemId(), jsonSchemaWrapper);
}
@Override
public boolean unloadPredefinedSchema(InputStream schemaStream) {
JsonNode schemaNode = jsonSchemaFactory.getSchema(schemaStream).getSchemaNode();
String schemaId = schemaNode.get("$id").asText();
-
- return predefinedUnomiJSONSchemaById.remove(schemaId) != null && schemasById.remove(schemaId) != null;
+ return predefinedUnomiJSONSchemaById.remove(schemaId) != null;
}
- @Override
- public JsonSchemaWrapper getSchema(String schemaId) {
- return schemasById.get(schemaId);
- }
+ private JsonSchemaWrapper buildJsonSchemaWrapper(String schema) {
+ JsonSchema jsonSchema = jsonSchemaFactory.getSchema(schema);
+ JsonNode schemaNode = jsonSchema.getSchemaNode();
- private URIFetcher getUriFetcher() {
- return uri -> {
- logger.debug("Fetching schema {}", uri);
- JsonSchemaWrapper jsonSchemaWrapper = schemasById.get(uri.toString());
- if (jsonSchemaWrapper == null) {
- logger.error("Couldn't find schema {}", uri);
- return null;
- }
- return IOUtils.toInputStream(jsonSchemaWrapper.getSchema());
- };
+ String schemaId = schemaNode.get("$id").asText();
+ String target = schemaNode.at("/self/target").asText();
+ String name = schemaNode.at("/self/name").asText();
+ String extendsSchema = schemaNode.at("/self/extends").asText();
+
+ if ("events".equals(target) && !name.matches("[_A-Za-z][_0-9A-Za-z]*")) {
+ throw new IllegalArgumentException(
+ "The \"/self/name\" value should match the following regular expression [_A-Za-z][_0-9A-Za-z]* for the Json schema on events");
+ }
+
+ return new JsonSchemaWrapper(schemaId, schema, target, extendsSchema, new Date());
}
private void refreshJSONSchemas() {
- schemasById = new HashMap<>();
- schemasById.putAll(predefinedUnomiJSONSchemaById);
+ // use local variable to avoid concurrency issues.
+ ConcurrentMap<String, JsonSchemaWrapper> schemasByIdReloaded = new ConcurrentHashMap<>();
+ schemasByIdReloaded.putAll(predefinedUnomiJSONSchemaById);
+ schemasByIdReloaded.putAll(persistenceService.getAllItems(JsonSchemaWrapper.class).stream().collect(Collectors.toMap(Item::getItemId, s -> s)));
+
+ // flush cache if size is different (can be new schema or deleted schemas)
+ boolean flushCache = schemasByIdReloaded.size() != schemasById.size();
+ // check dates
+ if (!flushCache) {
+ for (JsonSchemaWrapper reloadedSchema : schemasByIdReloaded.values()) {
+ JsonSchemaWrapper oldSchema = schemasById.get(reloadedSchema.getItemId());
+ if (oldSchema == null || !oldSchema.getTimeStamp().equals(reloadedSchema.getTimeStamp())) {
+ flushCache = true;
+ break;
+ }
+ }
+ }
- persistenceService.getAllItems(JsonSchemaWrapper.class).forEach(
- JsonSchemaWrapper -> schemasById.put(JsonSchemaWrapper.getId(), JsonSchemaWrapper));
+ if (flushCache) {
+ initJsonSchemaFactory();
+ }
+ schemasById = schemasByIdReloaded;
+ }
+
+ private void initPersistenceIndex() {
+ if (persistenceService.createIndex(JsonSchemaWrapper.ITEM_TYPE)) {
+ logger.info("{} index created", JsonSchemaWrapper.ITEM_TYPE);
+ } else {
+ logger.info("{} index already exists", JsonSchemaWrapper.ITEM_TYPE);
+ }
}
- private void initializeTimers() {
+ private void initTimers() {
TimerTask task = new TimerTask() {
@Override
public void run() {
@@ -203,18 +229,18 @@ public class SchemaServiceImpl implements SchemaService {
.scheduleWithFixedDelay(task, 0, jsonSchemaRefreshInterval, TimeUnit.MILLISECONDS);
}
- public void init() {
- JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder(URI, JsonMetaSchema.getV201909())
- .addKeyword(new NonValidationKeyword("self"))
- .build();
-
+ private void initJsonSchemaFactory() {
jsonSchemaFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909))
.addMetaSchema(jsonMetaSchema)
.defaultMetaSchemaURI(URI)
- .uriFetcher(getUriFetcher(), "https", "http")
+ .uriFetcher(jsonSchemaURIFetcher, "https", "http")
.build();
+ }
- initializeTimers();
+ public void init() {
+ initPersistenceIndex();
+ initJsonSchemaFactory();
+ initTimers();
logger.info("Schema service initialized.");
}
@@ -234,8 +260,4 @@ public class SchemaServiceImpl implements SchemaService {
public void setJsonSchemaRefreshInterval(Integer jsonSchemaRefreshInterval) {
this.jsonSchemaRefreshInterval = jsonSchemaRefreshInterval;
}
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
}
diff --git a/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/listener/JsonSchemaListener.java b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/listener/JsonSchemaListener.java
index 9e674d545..fda47dd85 100644
--- a/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/listener/JsonSchemaListener.java
+++ b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/listener/JsonSchemaListener.java
@@ -16,8 +16,6 @@
*/
package org.apache.unomi.schema.listener;
-import org.apache.unomi.persistence.spi.PersistenceService;
-import org.apache.unomi.schema.api.JsonSchemaWrapper;
import org.apache.unomi.schema.api.SchemaService;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@@ -41,14 +39,9 @@ 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";
- private PersistenceService persistenceService;
private SchemaService schemaService;
private BundleContext bundleContext;
- public void setPersistenceService(PersistenceService persistenceService) {
- this.persistenceService = persistenceService;
- }
-
public void setSchemaService(SchemaService schemaService) {
this.schemaService = schemaService;
}
@@ -60,7 +53,6 @@ public class JsonSchemaListener implements SynchronousBundleListener {
public void postConstruct() {
logger.info("JSON schema listener initializing...");
logger.debug("postConstruct {}", bundleContext.getBundle());
- createIndexes();
loadPredefinedSchemas(bundleContext, true);
@@ -106,14 +98,6 @@ public class JsonSchemaListener implements SynchronousBundleListener {
}
}
- public void createIndexes() {
- if (persistenceService.createIndex(JsonSchemaWrapper.ITEM_TYPE)) {
- logger.info("{} index created", JsonSchemaWrapper.ITEM_TYPE);
- } else {
- logger.info("{} index already exists", JsonSchemaWrapper.ITEM_TYPE);
- }
- }
-
private void loadPredefinedSchemas(BundleContext bundleContext, boolean load) {
Enumeration<URL> predefinedSchemas = bundleContext.getBundle().findEntries(ENTRIES_LOCATION, "*.json", true);
if (predefinedSchemas == null) {
diff --git a/extensions/json-schema/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/extensions/json-schema/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 02e3280c0..15443922b 100644
--- a/extensions/json-schema/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/extensions/json-schema/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -33,7 +33,6 @@
<bean id="schemaServiceImpl" class="org.apache.unomi.schema.impl.SchemaServiceImpl" init-method="init"
destroy-method="destroy">
- <property name="bundleContext" ref="blueprintBundleContext"/>
<property name="persistenceService" ref="persistenceService"/>
<property name="schedulerService" ref="schedulerService"/>
<property name="jsonSchemaRefreshInterval" value="${json.schema.refresh.interval}"/>
@@ -42,7 +41,6 @@
<bean id="jsonSchemaListenerImpl" class="org.apache.unomi.schema.listener.JsonSchemaListener"
init-method="postConstruct" destroy-method="preDestroy">
- <property name="persistenceService" ref="persistenceService"/>
<property name="bundleContext" ref="blueprintBundleContext"/>
<property name="schemaService" ref="schemaServiceImpl"/>
</bean>
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 97879bdd4..0e63ae362 100644
--- a/itests/src/test/java/org/apache/unomi/itests/JSONSchemaIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/JSONSchemaIT.java
@@ -19,7 +19,7 @@ package org.apache.unomi.itests;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
-import org.apache.unomi.persistence.spi.PersistenceService;
+import org.apache.unomi.api.Event;
import org.apache.unomi.schema.api.JsonSchemaWrapper;
import org.apache.unomi.schema.api.SchemaService;
import org.junit.After;
@@ -37,9 +37,7 @@ import java.util.Base64;
import java.util.List;
import java.util.Objects;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
/**
* Class to tests the JSON schema features
@@ -56,10 +54,6 @@ public class JSONSchemaIT extends BaseIT {
@Filter(timeout = 600000)
protected SchemaService schemaService;
- @Inject
- @Filter(timeout = 600000)
- protected PersistenceService persistenceService;
-
@Before
public void setUp() throws InterruptedException {
keepTrying("Couldn't find json schema endpoint", () -> get(JSONSCHEMA_URL, List.class), Objects::nonNull, DEFAULT_TRYING_TIMEOUT,
@@ -67,76 +61,141 @@ public class JSONSchemaIT extends BaseIT {
}
@After
- public void tearDown() {
- schemaService.deleteSchema("https://unomi.apache.org/schemas/json/events/testEventType/1-0-0");
+ public void tearDown() throws InterruptedException {
+ removeItems(JsonSchemaWrapper.class, Event.class);
+ // ensure all schemas have been cleaned from schemaService.
+ keepTrying("Couldn't find json schemas",
+ () -> schemaService.getInstalledJsonSchemaIds(),
+ (list) -> (!list.contains("https://unomi.apache.org/schemas/json/events/dummy/1-0-0") &&
+ !list.contains("https://unomi.apache.org/schemas/json/events/dummy/properties/1-0-0")),
+ DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
}
@Test
- public void testGetJsonSchemasMetadatas() throws InterruptedException {
- List jsonSchemas = get(JSONSCHEMA_URL, List.class);
- assertTrue("JSON schema list should be empty", jsonSchemas.isEmpty());
+ public void testValidation_SaveDeleteSchemas() throws InterruptedException, IOException {
+ // check that event is not valid at first
+ assertFalse(schemaService.isValid(resourceAsString("schemas/event-dummy-valid.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"));
+
+ // Push schemas
+ schemaService.saveSchema(resourceAsString("schemas/schema-dummy.json"));
+ schemaService.saveSchema(resourceAsString("schemas/schema-dummy-properties.json"));
+ keepTrying("Couldn't find json schemas",
+ () -> get(JSONSCHEMA_URL, List.class),
+ (list) -> (list.contains("https://unomi.apache.org/schemas/json/events/dummy/1-0-0") &&
+ list.contains("https://unomi.apache.org/schemas/json/events/dummy/properties/1-0-0")),
+ DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
- post(JSONSCHEMA_URL, "schemas/events/test-event-type.json", ContentType.TEXT_PLAIN);
+ // event should be valid now
+ keepTrying("Event should be valid",
+ () -> schemaService.isValid(resourceAsString("schemas/event-dummy-valid.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"),
+ isValid -> isValid,
+ DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
- jsonSchemas = keepTrying("Couldn't find json schemas", () -> get(JSONSCHEMA_URL, List.class), (list) -> !list.isEmpty(),
+ // Test multiple invalid event:
+ // unevaluated property at root:
+ assertFalse(schemaService.isValid(resourceAsString("schemas/event-dummy-invalid-1.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"));
+ // unevaluated property in properties:
+ assertFalse(schemaService.isValid(resourceAsString("schemas/event-dummy-invalid-2.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"));
+ // bad type number but should be string:
+ assertFalse(schemaService.isValid(resourceAsString("schemas/event-dummy-invalid-3.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"));
+
+ // remove one of the schema:
+ assertTrue(schemaService.deleteSchema("https://unomi.apache.org/schemas/json/events/dummy/properties/1-0-0"));
+ keepTrying("Schema should have been deleted",
+ () -> schemaService.getInstalledJsonSchemaIds(),
+ (list) -> !list.contains("https://unomi.apache.org/schemas/json/events/dummy/properties/1-0-0"),
+ DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+
+ // event should be invalid now that one of the schema have been deleted -> this is validating cache is correctly flushed
+ keepTrying("Event should be invalid since of the schema have been deleted",
+ () -> schemaService.isValid(resourceAsString("schemas/event-dummy-valid.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"),
+ isValid -> !isValid,
DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
- assertFalse("JSON schema list should not be empty", jsonSchemas.isEmpty());
- assertEquals("JSON schema list should not be empty", 1, jsonSchemas.size());
}
@Test
- public void testSaveNewValidJSONSchema() throws InterruptedException {
+ public void testValidation_UpdateSchema() throws InterruptedException, IOException {
+ // check that event is not valid at first
+ assertFalse(schemaService.isValid(resourceAsString("schemas/event-dummy-valid.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"));
+
+ // Push schemas
+ schemaService.saveSchema(resourceAsString("schemas/schema-dummy.json"));
+ schemaService.saveSchema(resourceAsString("schemas/schema-dummy-properties.json"));
+ keepTrying("Couldn't find json schemas",
+ () -> get(JSONSCHEMA_URL, List.class),
+ (list) -> (list.contains("https://unomi.apache.org/schemas/json/events/dummy/1-0-0") &&
+ list.contains("https://unomi.apache.org/schemas/json/events/dummy/properties/1-0-0")),
+ DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
- assertTrue("JSON schema list should be empty", persistenceService.getAllItems(JsonSchemaWrapper.class).isEmpty());
+ // event should be valid now
+ keepTrying("Event should be valid",
+ () -> schemaService.isValid(resourceAsString("schemas/event-dummy-valid.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"),
+ isValid -> isValid,
+ DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
- CloseableHttpResponse response = post(JSONSCHEMA_URL, "schemas/events/test-event-type.json", ContentType.TEXT_PLAIN);
+ // Test the invalid event, that use the new prop "invalidPropName" in properties:
+ assertFalse(schemaService.isValid(resourceAsString("schemas/event-dummy-invalid-2.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"));
- assertEquals("Invalid response code", 200, response.getStatusLine().getStatusCode());
- List jsonSchemas = keepTrying("Couldn't find json schemas", () -> get(JSONSCHEMA_URL, List.class), (list) -> !list.isEmpty(),
+ // update the schema to allow "invalidPropName":
+ schemaService.saveSchema(resourceAsString("schemas/schema-dummy-properties-updated.json"));
+ keepTrying("schema should be updated by refresh 1sec",
+ () -> schemaService.getSchema("https://unomi.apache.org/schemas/json/events/dummy/properties/1-0-0"),
+ schema -> (schema != null && schema.getSchema().contains("invalidPropName")),
+ DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+
+ // "invalidPropName" should be valid and allowed now
+ keepTrying("Event should be valid since of the schema have been updated",
+ () -> schemaService.isValid(resourceAsString("schemas/event-dummy-invalid-2.json"), "https://unomi.apache.org/schemas/json/events/dummy/1-0-0"),
+ isValid -> isValid,
DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
- assertFalse("JSON schema list should not be empty", jsonSchemas.isEmpty());
}
@Test
- public void testSavePredefinedJSONSchema() throws IOException {
- assertTrue("JSON schema list should be empty", persistenceService.getAllItems(JsonSchemaWrapper.class).isEmpty());
- try (CloseableHttpResponse response = post(JSONSCHEMA_URL, "schemas/events/predefined-event-type.json", ContentType.TEXT_PLAIN)) {
- assertEquals("Unable to save schema", 400, response.getStatusLine().getStatusCode());
- }
+ public void testEndPoint_GetInstalledJsonSchemas() throws InterruptedException {
+ List<String> jsonSchemas = get(JSONSCHEMA_URL, List.class);
+ assertFalse("JSON schema list should not be empty, it should contains predefined Unomi schemas", jsonSchemas.isEmpty());
}
@Test
- public void testDeleteJSONSchema() throws InterruptedException {
- assertTrue("JSON schema list should be empty", persistenceService.getAllItems(JsonSchemaWrapper.class).isEmpty());
+ public void testEndPoint_SaveDelete() throws InterruptedException, IOException {
+ assertNull(schemaService.getSchema("https://unomi.apache.org/schemas/json/events/dummy/1-0-0"));
- post(JSONSCHEMA_URL, "schemas/events/test-event-type.json", ContentType.TEXT_PLAIN);
+ // Post schema using REST call
+ try(CloseableHttpResponse response = post(JSONSCHEMA_URL, "schemas/schema-dummy.json", ContentType.TEXT_PLAIN)) {
+ assertEquals("Invalid response code", 200, response.getStatusLine().getStatusCode());
+ }
- keepTrying("Couldn't find json schemas", () -> get(JSONSCHEMA_URL, List.class), (list) -> !list.isEmpty(), DEFAULT_TRYING_TIMEOUT,
- DEFAULT_TRYING_TRIES);
+ // See schema is available
+ keepTrying("Schema should have been created", () -> schemaService.getSchema("https://unomi.apache.org/schemas/json/events/dummy/1-0-0"),
+ Objects::nonNull, DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+ // Delete Schema using REST call
String encodedString = Base64.getEncoder()
- .encodeToString("https://unomi.apache.org/schemas/json/events/testEventType/1-0-0".getBytes());
+ .encodeToString("https://unomi.apache.org/schemas/json/events/dummy/1-0-0".getBytes());
CloseableHttpResponse response = delete(JSONSCHEMA_URL + "/" + encodedString);
assertEquals("Invalid response code", 204, response.getStatusLine().getStatusCode());
- List jsonSchemas = keepTrying("wait for empty list of schemas", () -> get(JSONSCHEMA_URL, List.class), List::isEmpty,
- DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+ keepTrying("Schema should have been deleted", () -> schemaService.getSchema("https://unomi.apache.org/schemas/json/events/dummy/1-0-0"),
+ Objects::isNull, DEFAULT_TRYING_TIMEOUT, DEFAULT_TRYING_TRIES);
+ }
- assertTrue("JSON schema list should be empty", jsonSchemas.isEmpty());
+ @Test
+ public void testSaveFail_PredefinedJSONSchema() throws IOException {
+ try (CloseableHttpResponse response = post(JSONSCHEMA_URL, "schemas/schema-predefined.json", ContentType.TEXT_PLAIN)) {
+ assertEquals("Unable to save schema", 400, response.getStatusLine().getStatusCode());
+ }
}
@Test
- public void testSaveNewInvalidJSONSchema() throws IOException {
- assertTrue("JSON schema list should be empty", persistenceService.getAllItems(JsonSchemaWrapper.class).isEmpty());
- try (CloseableHttpResponse response = post(JSONSCHEMA_URL, "schemas/events/test-invalid.json", ContentType.TEXT_PLAIN)) {
+ public void testSaveFail_NewInvalidJSONSchema() throws IOException {
+ try (CloseableHttpResponse response = post(JSONSCHEMA_URL, "schemas/schema-invalid.json", ContentType.TEXT_PLAIN)) {
assertEquals("Unable to save schema", 400, response.getStatusLine().getStatusCode());
}
}
@Test
- public void testSaveSchemaWithInvalidName() throws IOException {
- assertTrue("JSON schema list should be empty", persistenceService.getAllItems(JsonSchemaWrapper.class).isEmpty());
- try (CloseableHttpResponse response = post(JSONSCHEMA_URL, "schemas/events/test-invalid-name.json", ContentType.TEXT_PLAIN)) {
+ public void testSaveFail_SchemaWithInvalidName() throws IOException {
+ try (CloseableHttpResponse response = post(JSONSCHEMA_URL, "schemas/schema-invalid-name.json", ContentType.TEXT_PLAIN)) {
assertEquals("Unable to save schema", 400, response.getStatusLine().getStatusCode());
}
}
diff --git a/itests/src/test/resources/schemas/event-dummy-invalid-1.json b/itests/src/test/resources/schemas/event-dummy-invalid-1.json
new file mode 100644
index 000000000..208c9edc2
--- /dev/null
+++ b/itests/src/test/resources/schemas/event-dummy-invalid-1.json
@@ -0,0 +1,9 @@
+{
+ "eventType":"dummy",
+ "scope":"dummy_scope",
+ "invalidPropName": "This is for sure an unknown property !!!!!",
+ "properties": {
+ "workspace": "dummy_workspace",
+ "path": "dummy/path"
+ }
+}
\ No newline at end of file
diff --git a/itests/src/test/resources/schemas/event-dummy-invalid-2.json b/itests/src/test/resources/schemas/event-dummy-invalid-2.json
new file mode 100644
index 000000000..eb3be4cba
--- /dev/null
+++ b/itests/src/test/resources/schemas/event-dummy-invalid-2.json
@@ -0,0 +1,9 @@
+{
+ "eventType":"dummy",
+ "scope":"dummy_scope",
+ "properties": {
+ "invalidPropName": "This is for sure an unknown property !!!!!",
+ "workspace": "dummy_workspace",
+ "path": "dummy/path"
+ }
+}
\ No newline at end of file
diff --git a/itests/src/test/resources/schemas/event-dummy-invalid-3.json b/itests/src/test/resources/schemas/event-dummy-invalid-3.json
new file mode 100644
index 000000000..841a598c9
--- /dev/null
+++ b/itests/src/test/resources/schemas/event-dummy-invalid-3.json
@@ -0,0 +1,8 @@
+{
+ "eventType":"dummy",
+ "scope":"dummy_scope",
+ "properties": {
+ "workspace": "dummy_workspace",
+ "path": 15
+ }
+}
\ No newline at end of file
diff --git a/itests/src/test/resources/schemas/event-dummy-valid.json b/itests/src/test/resources/schemas/event-dummy-valid.json
new file mode 100644
index 000000000..ae55bdf33
--- /dev/null
+++ b/itests/src/test/resources/schemas/event-dummy-valid.json
@@ -0,0 +1,8 @@
+{
+ "eventType":"dummy",
+ "scope":"dummy_scope",
+ "properties": {
+ "workspace": "dummy_workspace",
+ "path": "dummy/path"
+ }
+}
\ No newline at end of file
diff --git a/itests/src/test/resources/schemas/events/dummy-event-type.json b/itests/src/test/resources/schemas/events/dummy-event-type.json
deleted file mode 100644
index e17ce633f..000000000
--- a/itests/src/test/resources/schemas/events/dummy-event-type.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "$id": "https://unomi.apache.org/schemas/json/events/dummy_event_type/1-0-0",
- "$schema": "https://json-schema.org/draft/2019-09/schema",
- "self": {
- "vendor": "org.apache.unomi",
- "name": "dummy_event_type",
- "format": "jsonschema",
- "target": "events",
- "version": "1-0-0"
- },
- "title": "DummyEvent",
- "type": "object",
- "allOf": [
- {
- "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0"
- }
- ],
- "properties": {
- "source": {
- "type": "object",
- "properties": {
- "itemType": {
- "type": "string"
- },
- "scope": {
- "type": "string"
- },
- "itemId": {
- "type": "string"
- },
- "properties": {
- "type": "object",
- "properties": {
- "myProperty": {
- "type": "string",
- "maxLength": 20000
- }
- }
- }
- }
- }
- }
-}
diff --git a/itests/src/test/resources/schemas/events/float-property-type.json b/itests/src/test/resources/schemas/events/float-property-type.json
deleted file mode 100644
index 93bb3f8ea..000000000
--- a/itests/src/test/resources/schemas/events/float-property-type.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "$id": "https://unomi.apache.org/schemas/json/events/floatPropertyType/1-0-0",
- "$schema": "https://json-schema.org/draft/2019-09/schema",
- "self":{
- "vendor":"org.apache.unomi",
- "target" : "events",
- "name":"floatPropertyType",
- "format":"jsonschema",
- "version":"1-0-0"
- },
- "title": "FloatPropertyEvent",
- "type": "object",
- "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }],
- "properties" : {
- "properties" : {
- "type" : "object",
- "properties" : {
- "floatProperty" : { "type" : "number" }
- },
- "additionalProperties": false
- }
- }
-}
diff --git a/itests/src/test/resources/schemas/events/negative-test-event-type.json b/itests/src/test/resources/schemas/events/negative-test-event-type.json
deleted file mode 100644
index 5508a5e99..000000000
--- a/itests/src/test/resources/schemas/events/negative-test-event-type.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "$id": "https://unomi.apache.org/schemas/json/events/negativeTestEventType/1-0-0",
- "$schema": "https://json-schema.org/draft/2019-09/schema",
- "self":{
- "vendor":"org.apache.unomi",
- "name":"negativeTestEventType",
- "format":"jsonschema",
- "version":"1-0-0"
- },
- "title": "TestEvent",
- "type": "object",
- "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }]
-}
diff --git a/itests/src/test/resources/schemas/events/test-event-type.json b/itests/src/test/resources/schemas/events/test-event-type.json
deleted file mode 100644
index 8d5a928a2..000000000
--- a/itests/src/test/resources/schemas/events/test-event-type.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "$id": "https://unomi.apache.org/schemas/json/events/testEventType/1-0-0",
- "$schema": "https://json-schema.org/draft/2019-09/schema",
- "self":{
- "vendor":"org.apache.unomi",
- "name":"testEventType",
- "format":"jsonschema",
- "target":"events",
- "version":"1-0-0"
- },
- "title": "TestEvent",
- "type": "object",
- "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }]
-}
diff --git a/itests/src/test/resources/schemas/schema-dummy-properties-updated.json b/itests/src/test/resources/schemas/schema-dummy-properties-updated.json
new file mode 100644
index 000000000..f92c2f9d2
--- /dev/null
+++ b/itests/src/test/resources/schemas/schema-dummy-properties-updated.json
@@ -0,0 +1,24 @@
+{
+ "$id": "https://unomi.apache.org/schemas/json/events/dummy/properties/1-0-0",
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "self": {
+ "vendor": "org.modules.jahia",
+ "name": "dummyProperties",
+ "format": "jsonschema",
+ "version": "1-0-0"
+ },
+ "title": "dummyProperties",
+ "type": "object",
+ "properties": {
+ "workspace": {
+ "type": "string"
+ },
+ "path": {
+ "type": "string"
+ },
+ "invalidPropName": {
+ "type": "string"
+ }
+ },
+ "unevaluatedProperties": false
+}
diff --git a/itests/src/test/resources/schemas/schema-dummy-properties.json b/itests/src/test/resources/schemas/schema-dummy-properties.json
new file mode 100644
index 000000000..498dd58aa
--- /dev/null
+++ b/itests/src/test/resources/schemas/schema-dummy-properties.json
@@ -0,0 +1,21 @@
+{
+ "$id": "https://unomi.apache.org/schemas/json/events/dummy/properties/1-0-0",
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "self": {
+ "vendor": "org.modules.jahia",
+ "name": "dummyProperties",
+ "format": "jsonschema",
+ "version": "1-0-0"
+ },
+ "title": "dummyProperties",
+ "type": "object",
+ "properties": {
+ "workspace": {
+ "type": "string"
+ },
+ "path": {
+ "type": "string"
+ }
+ },
+ "unevaluatedProperties": false
+}
diff --git a/itests/src/test/resources/schemas/schema-dummy.json b/itests/src/test/resources/schemas/schema-dummy.json
new file mode 100644
index 000000000..6e133b25f
--- /dev/null
+++ b/itests/src/test/resources/schemas/schema-dummy.json
@@ -0,0 +1,22 @@
+{
+ "$id": "https://unomi.apache.org/schemas/json/events/dummy/1-0-0",
+ "$schema": "https://json-schema.org/draft/2019-09/schema",
+ "self":{
+ "vendor":"org.apache.unomi",
+ "name":"dummy",
+ "format":"jsonschema",
+ "target":"events",
+ "version":"1-0-0"
+ },
+ "title": "DummyEvent",
+ "type": "object",
+ "allOf": [
+ { "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }
+ ],
+ "properties": {
+ "properties": {
+ "$ref": "https://unomi.apache.org/schemas/json/events/dummy/properties/1-0-0"
+ }
+ },
+ "unevaluatedProperties": false
+}
diff --git a/itests/src/test/resources/schemas/events/test-invalid-name.json b/itests/src/test/resources/schemas/schema-invalid-name.json
similarity index 100%
rename from itests/src/test/resources/schemas/events/test-invalid-name.json
rename to itests/src/test/resources/schemas/schema-invalid-name.json
diff --git a/itests/src/test/resources/schemas/events/test-invalid.json b/itests/src/test/resources/schemas/schema-invalid.json
similarity index 100%
rename from itests/src/test/resources/schemas/events/test-invalid.json
rename to itests/src/test/resources/schemas/schema-invalid.json
diff --git a/itests/src/test/resources/schemas/events/predefined-event-type.json b/itests/src/test/resources/schemas/schema-predefined.json
similarity index 79%
rename from itests/src/test/resources/schemas/events/predefined-event-type.json
rename to itests/src/test/resources/schemas/schema-predefined.json
index 8d9ffd967..b4da0ada6 100644
--- a/itests/src/test/resources/schemas/events/predefined-event-type.json
+++ b/itests/src/test/resources/schemas/schema-predefined.json
@@ -10,5 +10,7 @@
},
"title": "TestEvent",
"type": "object",
- "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }]
+ "allOf": [
+ { "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }
+ ]
}