This is an automated email from the ASF dual-hosted git repository. jsinovassinnaik pushed a commit to branch UNOMI-598-validate-events-with-scope in repository https://gitbox.apache.org/repos/asf/unomi.git
commit 54be4d9e7aaa893ba6de80e7c407b437183e5544 Author: jsinovassin <[email protected]> AuthorDate: Tue Jun 28 15:55:21 2022 +0200 UNOMI-598 : add keyword to validate scopes --- .../apache/unomi/api/services/ScopeService.java | 1 - .../unomi/schema/impl/SchemaServiceImpl.java | 10 ++++ .../apache/unomi/schema/keyword/ScopeKeyword.java | 54 ++++++++-------------- .../unomi/schema/keyword/ScopeValidator.java | 54 ++++++++++++++++++++++ .../META-INF/cxs/schemas/events/event.json | 3 +- .../cxs/schemas/items/consent/consent.json | 5 +- .../resources/META-INF/cxs/schemas/items/item.json | 1 + .../resources/OSGI-INF/blueprint/blueprint.xml | 3 +- .../java/org/apache/unomi/itests/JSONSchemaIT.java | 21 ++++++++- .../resources/schemas/event-dummy-invalid-4.json | 8 ++++ .../deserializers/ContextRequestDeserializer.java | 1 - 11 files changed, 118 insertions(+), 43 deletions(-) diff --git a/api/src/main/java/org/apache/unomi/api/services/ScopeService.java b/api/src/main/java/org/apache/unomi/api/services/ScopeService.java index 5dddf6362..91980a407 100644 --- a/api/src/main/java/org/apache/unomi/api/services/ScopeService.java +++ b/api/src/main/java/org/apache/unomi/api/services/ScopeService.java @@ -17,7 +17,6 @@ package org.apache.unomi.api.services; -import org.apache.unomi.api.Metadata; import org.apache.unomi.api.Scope; import java.util.List; 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 d3fac549c..346cf9395 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 @@ -27,9 +27,12 @@ import com.networknt.schema.*; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.unomi.api.Item; +import org.apache.unomi.api.services.ScopeService; import org.apache.unomi.persistence.spi.PersistenceService; import org.apache.unomi.schema.api.JsonSchemaWrapper; import org.apache.unomi.schema.api.SchemaService; +import org.apache.unomi.schema.keyword.GroovyKeyword; +import org.apache.unomi.schema.keyword.ScopeKeyword; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,6 +69,8 @@ public class SchemaServiceImpl implements SchemaService { private ScheduledFuture<?> scheduledFuture; private PersistenceService persistenceService; + private ScopeService scopeService; + private JsonSchemaFactory jsonSchemaFactory; // TODO UNOMI-572: when fixing UNOMI-572 please remove the usage of the custom ScheduledExecutorService and re-introduce the Unomi Scheduler Service @@ -317,6 +322,7 @@ public class SchemaServiceImpl implements SchemaService { private void initJsonSchemaFactory() { jsonSchemaFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)) .addMetaSchema(JsonMetaSchema.builder(URI, JsonMetaSchema.getV201909()) + .addKeyword(new ScopeKeyword(scopeService)) .addKeyword(new NonValidationKeyword("self")) .build()) .defaultMetaSchemaURI(URI) @@ -358,6 +364,10 @@ public class SchemaServiceImpl implements SchemaService { this.persistenceService = persistenceService; } + public void setScopeService(ScopeService scopeService) { + this.scopeService = scopeService; + } + public void setJsonSchemaRefreshInterval(Integer jsonSchemaRefreshInterval) { this.jsonSchemaRefreshInterval = jsonSchemaRefreshInterval; } diff --git a/api/src/main/java/org/apache/unomi/api/services/ScopeService.java b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/keyword/ScopeKeyword.java similarity index 51% copy from api/src/main/java/org/apache/unomi/api/services/ScopeService.java copy to extensions/json-schema/services/src/main/java/org/apache/unomi/schema/keyword/ScopeKeyword.java index 5dddf6362..ebe15ce30 100644 --- a/api/src/main/java/org/apache/unomi/api/services/ScopeService.java +++ b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/keyword/ScopeKeyword.java @@ -14,45 +14,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.unomi.schema.keyword; -package org.apache.unomi.api.services; +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.AbstractKeyword; +import com.networknt.schema.JsonSchema; +import com.networknt.schema.JsonValidator; +import com.networknt.schema.ValidationContext; +import org.apache.unomi.api.services.ScopeService; -import org.apache.unomi.api.Metadata; -import org.apache.unomi.api.Scope; +public class ScopeKeyword extends AbstractKeyword { -import java.util.List; + private ScopeService scopeService; -/** - * A service to create, update and delete scope. - */ -public interface ScopeService { - - /** - * Retrieves all known scopes. - * - * @return the List of known scopes - */ - List<Scope> getScopes(); - - /** - * Save a scope - * - * @param scope to save - */ - void save(Scope scope); - - /** - * Delete a scope - * - * @param id of the scope - * @return true if scope is deleted - */ - boolean delete(String id); + public ScopeKeyword(ScopeService scopeService) { + super("scope"); + this.scopeService = scopeService; + } - /** - * Get a scope by its id - * - * @return Scope matching the id - */ - Scope getScope(String id); + @Override + public JsonValidator newValidator(String schemaPath, JsonNode schemaNode, JsonSchema parentSchema, + ValidationContext validationContext) { + return new ScopeValidator(scopeService); + } } diff --git a/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/keyword/ScopeValidator.java b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/keyword/ScopeValidator.java new file mode 100644 index 000000000..2f41d9b28 --- /dev/null +++ b/extensions/json-schema/services/src/main/java/org/apache/unomi/schema/keyword/ScopeValidator.java @@ -0,0 +1,54 @@ +/* + * 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.schema.keyword; + +import com.fasterxml.jackson.databind.JsonNode; +import com.networknt.schema.AbstractJsonValidator; +import com.networknt.schema.CustomErrorMessageType; +import com.networknt.schema.ValidationMessage; +import org.apache.unomi.api.services.ScopeService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; +import java.util.LinkedHashSet; +import java.util.Set; + +public class ScopeValidator extends AbstractJsonValidator { + private static final Logger logger = LoggerFactory.getLogger(ScopeValidator.class); + + private ScopeService scopeService; + + public ScopeValidator(ScopeService scopeService) { + super("scope"); + this.scopeService = scopeService; + } + + @Override + public Set<ValidationMessage> validate(JsonNode node, JsonNode rootNode, String at) { + if (logger.isDebugEnabled()) { + logger.debug("validate( {}, {}, {})", node, rootNode, at); + } + Set<ValidationMessage> errors = new LinkedHashSet(); + if (scopeService.getScope(node.textValue()) == null) { + errors.add(this.buildValidationMessage( + CustomErrorMessageType.of("1100", new MessageFormat("Unknown scope value at \"{0}\" for value {1}")), at, + node.textValue())); + } + return errors; + } +} diff --git a/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/events/event.json b/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/events/event.json index 29fa59c8f..3e0dcf346 100644 --- a/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/events/event.json +++ b/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/events/event.json @@ -25,6 +25,7 @@ }, "scope" : { "type" : [ "string"], + "scope": true, "pattern" : "^(\\w|[-_@\\.]){0,60}$" }, "sourceId" : { @@ -35,4 +36,4 @@ "type" : "boolean" } } -} \ No newline at end of file +} diff --git a/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/items/consent/consent.json b/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/items/consent/consent.json index 557bb25fb..5e35b89a0 100644 --- a/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/items/consent/consent.json +++ b/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/items/consent/consent.json @@ -11,7 +11,8 @@ "type": "object", "properties" : { "scope" : { - "type" : "string" + "type" : "string", + "scope": true }, "typeIdentifier" : { "type" : "string" @@ -29,4 +30,4 @@ } }, "unevaluatedProperties": false -} \ No newline at end of file +} diff --git a/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/items/item.json b/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/items/item.json index 5c71db49b..0c6e3d91e 100644 --- a/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/items/item.json +++ b/extensions/json-schema/services/src/main/resources/META-INF/cxs/schemas/items/item.json @@ -21,6 +21,7 @@ }, "scope" : { "type" : ["null","string"], + "scope": true, "description" : "The item's scope" }, "version" : { 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 88485b84b..9998ad930 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 @@ -27,13 +27,14 @@ </cm:default-properties> </cm:property-placeholder> - <reference id="profileService" interface="org.apache.unomi.api.services.ProfileService"/> + <reference id="scopeService" interface="org.apache.unomi.api.services.ScopeService"/> <reference id="persistenceService" interface="org.apache.unomi.persistence.spi.PersistenceService"/> <!--reference id="schedulerService" interface="org.apache.unomi.api.services.SchedulerService"/--> <bean id="schemaServiceImpl" class="org.apache.unomi.schema.impl.SchemaServiceImpl" init-method="init" destroy-method="destroy"> <property name="persistenceService" ref="persistenceService"/> + <property name="scopeService" ref="scopeService"/> <!--property name="schedulerService" ref="schedulerService"/--> <property name="jsonSchemaRefreshInterval" value="${json.schema.refresh.interval}"/> </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 5640f211e..8bf84165f 100644 --- a/itests/src/test/java/org/apache/unomi/itests/JSONSchemaIT.java +++ b/itests/src/test/java/org/apache/unomi/itests/JSONSchemaIT.java @@ -23,7 +23,10 @@ import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.apache.unomi.api.Event; +import org.apache.unomi.api.Metadata; +import org.apache.unomi.api.Scope; import org.apache.unomi.api.conditions.Condition; +import org.apache.unomi.api.services.ScopeService; import org.apache.unomi.itests.tools.httpclient.HttpClientThatWaitsForUnomi; import org.apache.unomi.schema.api.JsonSchemaWrapper; import org.apache.unomi.schema.api.SchemaService; @@ -61,15 +64,27 @@ public class JSONSchemaIT extends BaseIT { @Filter(timeout = 600000) protected SchemaService schemaService; + @Inject + @Filter(timeout = 6000000) + protected ScopeService scopeService; + @Before 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); + + Scope scope = new Scope(); + scope.setItemId("dummy_scope"); + Metadata metadata = new Metadata(); + metadata.setName("Dummy scope"); + metadata.setId("dummy_scope"); + scope.setMetadata(metadata); + scopeService.save(scope); } @After public void tearDown() throws InterruptedException { - removeItems(JsonSchemaWrapper.class, Event.class); + removeItems(JsonSchemaWrapper.class, Event.class, Scope.class); // ensure all schemas have been cleaned from schemaService. keepTrying("Should not find json schemas anymore", () -> schemaService.getInstalledJsonSchemaIds(), @@ -102,6 +117,10 @@ public class JSONSchemaIT extends BaseIT { assertFalse(schemaService.isEventValid(resourceAsString("schemas/event-dummy-invalid-3.json"), "dummy")); + // Event with unexisting scope: + assertFalse(schemaService.isEventValid(resourceAsString("schemas/event-dummy-invalid-4.json"), + "dummy")); + // remove one of the schema: assertTrue(schemaService.deleteSchema("https://vendor.test.com/schemas/json/events/dummy/properties/1-0-0")); keepTrying("Event should be invalid since of the schema have been deleted", () -> schemaService diff --git a/itests/src/test/resources/schemas/event-dummy-invalid-4.json b/itests/src/test/resources/schemas/event-dummy-invalid-4.json new file mode 100644 index 000000000..4f434731f --- /dev/null +++ b/itests/src/test/resources/schemas/event-dummy-invalid-4.json @@ -0,0 +1,8 @@ +{ + "eventType":"dummy", + "scope":"unknown_scope", + "properties": { + "workspace": "dummy_workspace", + "path": "dummy/path" + } +} diff --git a/rest/src/main/java/org/apache/unomi/rest/deserializers/ContextRequestDeserializer.java b/rest/src/main/java/org/apache/unomi/rest/deserializers/ContextRequestDeserializer.java index e43534155..c14ec89ef 100644 --- a/rest/src/main/java/org/apache/unomi/rest/deserializers/ContextRequestDeserializer.java +++ b/rest/src/main/java/org/apache/unomi/rest/deserializers/ContextRequestDeserializer.java @@ -28,7 +28,6 @@ import org.apache.unomi.api.Item; import org.apache.unomi.api.Profile; import org.apache.unomi.api.services.PersonalizationService; import org.apache.unomi.rest.exception.InvalidRequestException; -import org.apache.unomi.schema.api.JsonSchemaWrapper; import org.apache.unomi.schema.api.SchemaService; import java.io.IOException;
