This is an automated email from the ASF dual-hosted git repository.

dgriffon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/unomi.git


The following commit(s) were added to refs/heads/master by this push:
     new a374c88c9 UNOMI-562 (#407)
a374c88c9 is described below

commit a374c88c945771aa04a975315e4b32a410dc7915
Author: David Griffon <[email protected]>
AuthorDate: Tue Apr 26 17:24:23 2022 +0200

    UNOMI-562 (#407)
    
    * DMF-5359 :
    - Add schema to contextRequest object
    - Improve schema validation by using custom deserializers for 
contextRequest and eventCollectorRequest
    
    * improve deserialization
    
    * restore null option to schemas
    
    * send expected error
    
    * improve response in case of invalid object to match what is expected
    
    * code review changes
    
    * fix unit tests + add validation on event collector request object
    
    * fix session properties
    
    * improve github action
    
    * do log on integration test only
    
    * fix tests
    
    * restore fail on error
    
    * remove isEventValid as now done at json level
    
    * rebase master
    
    * finish rebase of master
---
 .github/workflows/unomi-ci-build-tests.yml         |  11 ++
 api/pom.xml                                        |   5 +
 .../apache/unomi/api/services/EventService.java    |   9 --
 .../apache/unomi/api/services/SchemaService.java   |   7 +-
 .../test/java/org/apache/unomi/itests/BaseIT.java  |   8 ++
 .../org/apache/unomi/itests/ContextServletIT.java  |   4 -
 .../org/apache/unomi/itests/InputValidationIT.java |   6 +
 .../resources/schemas/events/dummy-event-type.json |  14 +++
 .../unomi/persistence/spi/CustomObjectMapper.java  |   8 ++
 .../deserializers/ContextRequestDeserializer.java  | 133 +++++++++++++++++++++
 .../EventCollectorRequestDeserializer.java         |  72 +++++++++++
 .../org/apache/unomi/rest/server/RestServer.java   |  25 +++-
 .../RetroCompatibilityParamConverterProvider.java  |   5 +-
 .../rest/service/impl/RestServiceUtilsImpl.java    |   5 -
 .../services/impl/events/EventServiceImpl.java     |   6 +-
 .../services/impl/schemas/SchemaServiceImpl.java   |   4 +-
 .../META-INF/cxs/schemas/contextrequest.json       |  65 ++++++++++
 .../main/resources/META-INF/cxs/schemas/event.json |   8 +-
 .../cxs/schemas/eventscollectorrequest.json        |  23 ++++
 .../cxs/schemas/personalization/filter.json        |  21 ++++
 .../personalization/personalizationrequest.json    |  25 ++++
 .../personalization/personalizedcontent.json       |  22 ++++
 .../cxs/schemas/personalization/target.json        |  17 +++
 .../META-INF/cxs/schemas/timestampeditem.json      |   2 +-
 24 files changed, 466 insertions(+), 39 deletions(-)

diff --git a/.github/workflows/unomi-ci-build-tests.yml 
b/.github/workflows/unomi-ci-build-tests.yml
index 6a059f135..cb5f82463 100644
--- a/.github/workflows/unomi-ci-build-tests.yml
+++ b/.github/workflows/unomi-ci-build-tests.yml
@@ -41,3 +41,14 @@ jobs:
           cache: maven
       - name: Integration tests
         run: mvn -ntp clean install -Pintegration-tests
+      - name: Archive unomi logs
+        uses: actions/upload-artifact@v3
+        if: failure()
+        with:
+          name: unomi-${{ matrix.java }}-${{ github.run_number }}
+          path: itests/target/exam/**/data/log
+      - name: Publish Test Report
+        uses: mikepenz/action-junit-report@v3
+        if: failure()
+        with:
+          report_paths: 'itests/target/failsafe-reports/TEST-*.xml'
diff --git a/api/pom.xml b/api/pom.xml
index 75da098d3..fa706a4dd 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -57,6 +57,11 @@
             <groupId>commons-collections</groupId>
             <artifactId>commons-collections</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <reporting>
diff --git a/api/src/main/java/org/apache/unomi/api/services/EventService.java 
b/api/src/main/java/org/apache/unomi/api/services/EventService.java
index 4dde0a998..7c59b37fc 100644
--- a/api/src/main/java/org/apache/unomi/api/services/EventService.java
+++ b/api/src/main/java/org/apache/unomi/api/services/EventService.java
@@ -69,15 +69,6 @@ public interface EventService {
      */
     boolean isEventAllowed(Event event, String thirdPartyId);
 
-
-    /**
-     * Check if event fields complies with corresponding event JSON schema 
definition
-     *
-     * @param event        event to test
-     * @return true if the event is valid
-     */
-    boolean isEventValid(Event event);
-
     /**
      * Get the third party server name, if the request is originated from a 
known peer
      *
diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaService.java 
b/api/src/main/java/org/apache/unomi/api/services/SchemaService.java
index bbd6c9dfa..7d6e65480 100644
--- a/api/src/main/java/org/apache/unomi/api/services/SchemaService.java
+++ b/api/src/main/java/org/apache/unomi/api/services/SchemaService.java
@@ -17,6 +17,7 @@
 
 package org.apache.unomi.api.services;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import org.apache.unomi.api.Metadata;
 import org.apache.unomi.api.PartialList;
 import org.apache.unomi.api.schema.json.JSONSchema;
@@ -45,13 +46,13 @@ public interface SchemaService {
     PartialList<Metadata> getJsonSchemaMetadatas(int offset, int size, String 
sortBy);
 
     /**
-     * Verify if an object is valid against a schema
+     * Verify if a jsonNode is valid against a schema
      *
-     * @param object   to validate
+     * @param jsonNode   to validate
      * @param schemaId id of the schema used for the validation
      * @return true is the object is valid
      */
-    boolean isValid(Object object, String schemaId);
+    boolean isValid(JsonNode jsonNode, String schemaId);
 
     /**
      * Get a schema matching by a schema id
diff --git a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java 
b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
index 5bc8d0360..1007ff74f 100644
--- a/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/BaseIT.java
@@ -108,6 +108,7 @@ public abstract class BaseIT {
     protected static final int REQUEST_TIMEOUT = 60000;
     protected static final int DEFAULT_TRYING_TIMEOUT = 2000;
     protected static final int DEFAULT_TRYING_TRIES = 30;
+    private final static String JSONSCHEMA_URL = "/cxs/jsonSchema";
 
     @Inject
     @Filter(timeout = 600000)
@@ -584,4 +585,11 @@ public abstract class BaseIT {
         }
     }
 
+    void registerEventType(String jsonSchemaFileName) {
+        post(JSONSCHEMA_URL, "schemas/events/" + jsonSchemaFileName, 
ContentType.TEXT_PLAIN);
+    }
+    void unRegisterEventType(String jsonSchemaId) {
+        delete(JSONSCHEMA_URL + "/" + 
Base64.getEncoder().encodeToString(jsonSchemaId.getBytes()));
+    }
+
 }
diff --git a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java 
b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
index 5c54efcae..300eed58b 100644
--- a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java
@@ -163,10 +163,6 @@ public class ContextServletIT extends BaseIT {
         delete(JSONSCHEMA_URL + "/" + encodedString);
     }
 
-    private void registerEventType(String jsonSchemaFileName) {
-        post(JSONSCHEMA_URL, "schemas/events/" + jsonSchemaFileName, 
ContentType.TEXT_PLAIN);
-    }
-
     @Test
     public void testUpdateEventFromContextAuthorizedThirdParty_Success() 
throws IOException, InterruptedException {
         //Arrange
diff --git 
a/itests/src/test/java/org/apache/unomi/itests/InputValidationIT.java 
b/itests/src/test/java/org/apache/unomi/itests/InputValidationIT.java
index 6199caace..538b8b52a 100644
--- a/itests/src/test/java/org/apache/unomi/itests/InputValidationIT.java
+++ b/itests/src/test/java/org/apache/unomi/itests/InputValidationIT.java
@@ -24,6 +24,7 @@ import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.util.EntityUtils;
 import org.apache.unomi.itests.tools.httpclient.HttpClientThatWaitsForUnomi;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.junit.PaxExam;
@@ -45,6 +46,7 @@ public class InputValidationIT extends BaseIT {
     private final static String EVENT_COLLECTOR_URL = "/eventcollector";
     private final static String CONTEXT_JS_URL = "/context.js";
     private final static String CONTEXT_JSON_URL = "/context.json";
+    private final static String DUMMY_EVENT_TYPE_SCHEMA = 
"dummy-event-type.json";
 
     private final static String ERROR_MESSAGE_REQUEST_SIZE_LIMIT_EXCEEDED = 
"Request rejected by the server because: Request size exceed the limit";
     private final static String ERROR_MESSAGE_INVALID_DATA_RECEIVED = "Request 
rejected by the server because: Invalid received data";
@@ -69,8 +71,10 @@ public class InputValidationIT extends BaseIT {
 
     @Test
     public void test_eventCollector_valid() throws IOException {
+        registerEventType(DUMMY_EVENT_TYPE_SCHEMA);
         doPOSTRequestTest(EVENT_COLLECTOR_URL, null, 
"/validation/eventcollector_valid.json", 200, null);
         doGETRequestTest(EVENT_COLLECTOR_URL, null, 
"/validation/eventcollector_valid.json", 200, null);
+        
unRegisterEventType("https://unomi.apache.org/schemas/json/events/dummy_event_type/1-0-0";);
     }
 
     @Test
@@ -99,8 +103,10 @@ public class InputValidationIT extends BaseIT {
 
     @Test
     public void test_eventCollector_request_size_exceed_limit() throws 
IOException {
+        registerEventType(DUMMY_EVENT_TYPE_SCHEMA);
         doPOSTRequestTest(EVENT_COLLECTOR_URL, null, 
"/validation/eventcollector_request_size_invalid.json", 400, 
ERROR_MESSAGE_REQUEST_SIZE_LIMIT_EXCEEDED);
         doPOSTRequestTest(EVENT_COLLECTOR_URL, null, 
"/validation/eventcollector_request_size_valid.json", 200, null);
+        
unRegisterEventType("https://unomi.apache.org/schemas/json/events/dummy_event_type/1-0-0";);
     }
 
     @Test
diff --git a/itests/src/test/resources/schemas/events/dummy-event-type.json 
b/itests/src/test/resources/schemas/events/dummy-event-type.json
new file mode 100644
index 000000000..439f2f9f2
--- /dev/null
+++ b/itests/src/test/resources/schemas/events/dummy-event-type.json
@@ -0,0 +1,14 @@
+{
+  "$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":"events/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"; }]
+}
diff --git 
a/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/CustomObjectMapper.java
 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/CustomObjectMapper.java
index f5f28448c..9e23a2399 100644
--- 
a/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/CustomObjectMapper.java
+++ 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/CustomObjectMapper.java
@@ -20,6 +20,7 @@ package org.apache.unomi.persistence.spi;
 import com.fasterxml.jackson.core.Version;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
 import com.fasterxml.jackson.databind.module.SimpleModule;
 import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
 import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
@@ -50,6 +51,10 @@ public class CustomObjectMapper extends ObjectMapper {
     private ItemDeserializer itemDeserializer;
 
     public CustomObjectMapper() {
+        this(null);
+    }
+
+    public CustomObjectMapper(Map<Class, StdDeserializer<?>> deserializers) {
         super();
         super.registerModule(new JaxbAnnotationModule());
         configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
@@ -67,6 +72,9 @@ public class CustomObjectMapper extends ObjectMapper {
         itemDeserializer = new ItemDeserializer();
         deserializerModule.addDeserializer(Item.class, itemDeserializer);
 
+        if (deserializers != null) {
+            deserializers.forEach(deserializerModule::addDeserializer);
+        }
 
         builtinItemTypeClasses = new HashMap<>();
         builtinItemTypeClasses.put(Campaign.ITEM_TYPE, Campaign.class);
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
new file mode 100644
index 000000000..5e5488f3b
--- /dev/null
+++ 
b/rest/src/main/java/org/apache/unomi/rest/deserializers/ContextRequestDeserializer.java
@@ -0,0 +1,133 @@
+/*
+ * 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.deserializers;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import org.apache.unomi.api.ContextRequest;
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.services.PersonalizationService;
+import org.apache.unomi.api.services.SchemaService;
+import org.apache.unomi.rest.validation.request.InvalidRequestException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Custom deserializer for ContextRequest that do validate the object using 
JSON Schema
+ */
+public class ContextRequestDeserializer extends 
StdDeserializer<ContextRequest> {
+
+    private final SchemaService schemaService;
+
+    public ContextRequestDeserializer(SchemaService schemaRegistry) {
+        this(null, schemaRegistry);
+    }
+
+    public ContextRequestDeserializer(Class<ContextRequest> vc, SchemaService 
schemaRegistry) {
+        super(vc);
+        this.schemaService = schemaRegistry;
+    }
+
+    @Override
+    public ContextRequest deserialize(JsonParser jsonParser, 
DeserializationContext context) throws IOException, JsonProcessingException {
+        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+        // Validate schema on it
+        if (!schemaService.isValid(node, 
"https://unomi.apache.org/schemas/json/contextrequest/1-0-0";)) {
+            throw new InvalidRequestException("Invalid received data", 
"Invalid received data");
+        }
+        ContextRequest cr = new ContextRequest();
+        if (node.get("requireSegments") != null) {
+            cr.setRequireSegments(node.get("requireSegments").booleanValue());
+        }
+        final JsonNode requiredProfileProperties = 
node.get("requiredProfileProperties");
+        if (requiredProfileProperties instanceof ArrayNode) {
+            List<String> profileProperties = new ArrayList<>();
+            requiredProfileProperties.elements().forEachRemaining(el -> 
profileProperties.add(el.textValue()));
+            cr.setRequiredProfileProperties(profileProperties);
+        }
+        final JsonNode requiredSessionPropertiesNode = 
node.get("requiredSessionProperties");
+        if (requiredSessionPropertiesNode instanceof ArrayNode) {
+            List<String> requiredSessionProperties = new ArrayList<>();
+            requiredSessionPropertiesNode.elements().forEachRemaining(el -> 
requiredSessionProperties.add(el.textValue()));
+            cr.setRequiredSessionProperties(requiredSessionProperties);
+        }
+        if (node.get("requireScores") != null) {
+            cr.setRequireScores(node.get("requireScores").booleanValue());
+        }
+        final JsonNode eventsNode = node.get("events");
+        if (eventsNode instanceof ArrayNode) {
+            ArrayNode events = (ArrayNode) eventsNode;
+            List<Event> filteredEvents = new ArrayList<>();
+            for (JsonNode event : events) {
+                if (schemaService.isValid(event, 
"https://unomi.apache.org/schemas/json/events/"; + 
event.get("eventType").textValue() + "/1-0-0")) {
+                    
filteredEvents.add(jsonParser.getCodec().treeToValue(event, Event.class));
+                }
+            }
+            cr.setEvents(filteredEvents);
+        }
+        final JsonNode filtersNode = node.get("filters");
+        if (filtersNode instanceof ArrayNode) {
+            ArrayNode filters = (ArrayNode) filtersNode;
+            List<PersonalizationService.PersonalizedContent> f = new 
ArrayList<>();
+            filters.elements().forEachRemaining(el -> {
+                try {
+                    f.add(jsonParser.getCodec().treeToValue(el, 
PersonalizationService.PersonalizedContent.class));
+                } catch (JsonProcessingException e) {
+                    // Unable to deserialize, ignore the entry
+                }
+            });
+            cr.setFilters(f);
+        }
+        final JsonNode personalizationsNode = node.get("personalizations");
+        if (personalizationsNode instanceof ArrayNode) {
+            ArrayNode personalizations = (ArrayNode) personalizationsNode;
+            List<PersonalizationService.PersonalizationRequest> p = new 
ArrayList<>();
+            personalizations.elements().forEachRemaining(el -> {
+                try {
+                    p.add(jsonParser.getCodec().treeToValue(el, 
PersonalizationService.PersonalizationRequest.class));
+                } catch (JsonProcessingException e) {
+                    // Unable to deserialize, ignore the entry
+                }
+            });
+            cr.setPersonalizations(p);
+        }
+        if (node.get("profileOverrides") != null) {
+            
cr.setProfileOverrides(jsonParser.getCodec().treeToValue(node.get("profileOverrides"),
 Profile.class));
+        }
+        if (node.get("sessionPropertiesOverrides") != null) {
+            
jsonParser.getCodec().treeToValue(node.get("sessionPropertiesOverrides"), 
Map.class);
+        }
+        if (node.get("sessionId") != null) {
+            cr.setSessionId(node.get("sessionId").textValue());
+        }
+        if (node.get("profileId") != null) {
+            cr.setProfileId(node.get("profileId").textValue());
+        }
+        if (node.get("clientId") != null) {
+            cr.setClientId(node.get("clientId").textValue());
+        }
+        return cr;
+    }
+}
\ No newline at end of file
diff --git 
a/rest/src/main/java/org/apache/unomi/rest/deserializers/EventCollectorRequestDeserializer.java
 
b/rest/src/main/java/org/apache/unomi/rest/deserializers/EventCollectorRequestDeserializer.java
new file mode 100644
index 000000000..5e78fc0a9
--- /dev/null
+++ 
b/rest/src/main/java/org/apache/unomi/rest/deserializers/EventCollectorRequestDeserializer.java
@@ -0,0 +1,72 @@
+/*
+ * 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.deserializers;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.EventsCollectorRequest;
+import org.apache.unomi.api.services.SchemaService;
+import org.apache.unomi.rest.validation.request.InvalidRequestException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Custom deserializer for EventCollectorRequest that do validate the events 
using JSon Schema
+ */
+public class EventCollectorRequestDeserializer extends 
StdDeserializer<EventsCollectorRequest> {
+
+    private final SchemaService schemaService;
+
+    public EventCollectorRequestDeserializer(SchemaService schemaRegistry) {
+        this(null, schemaRegistry);
+    }
+
+    public EventCollectorRequestDeserializer(Class<EventsCollectorRequest> vc, 
SchemaService schemaService) {
+        super(vc);
+        this.schemaService = schemaService;
+    }
+
+    @Override
+    public EventsCollectorRequest deserialize(JsonParser jsonParser, 
DeserializationContext context) throws IOException, JsonProcessingException {
+        JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+        if (!schemaService.isValid(node, 
"https://unomi.apache.org/schemas/json/eventscollectorrequest/1-0-0";)) {
+            throw new InvalidRequestException("Invalid received data", 
"Invalid received data");
+        }
+
+        // Validate schema on each event
+        List<Event> filteredEvents = new ArrayList<>();
+        final JsonNode eventsNode = node.get("events");
+        if (eventsNode instanceof ArrayNode) {
+            for (JsonNode event : eventsNode) {
+                if (schemaService.isValid(event, 
"https://unomi.apache.org/schemas/json/events/"; + 
event.get("eventType").textValue() + "/1-0-0")) {
+                    
filteredEvents.add(jsonParser.getCodec().treeToValue(event, Event.class));
+                }
+            }
+        }
+        EventsCollectorRequest eventsCollectorRequest = new 
EventsCollectorRequest();
+        eventsCollectorRequest.setSessionId(node.get("sessionId").textValue());
+        eventsCollectorRequest.setEvents(filteredEvents);
+        return eventsCollectorRequest;
+    }
+}
diff --git a/rest/src/main/java/org/apache/unomi/rest/server/RestServer.java 
b/rest/src/main/java/org/apache/unomi/rest/server/RestServer.java
index c260ffee0..2d43dcb0d 100644
--- a/rest/src/main/java/org/apache/unomi/rest/server/RestServer.java
+++ b/rest/src/main/java/org/apache/unomi/rest/server/RestServer.java
@@ -17,6 +17,7 @@
 package org.apache.unomi.rest.server;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
 import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
 import org.apache.cxf.Bus;
 import org.apache.cxf.endpoint.Server;
@@ -28,10 +29,15 @@ import 
org.apache.cxf.jaxrs.security.SimpleAuthorizingFilter;
 import org.apache.cxf.jaxrs.validation.JAXRSBeanValidationInInterceptor;
 import org.apache.cxf.jaxrs.validation.JAXRSBeanValidationOutInterceptor;
 import org.apache.cxf.message.Message;
+import org.apache.unomi.api.ContextRequest;
+import org.apache.unomi.api.EventsCollectorRequest;
 import org.apache.unomi.api.services.ConfigSharingService;
+import org.apache.unomi.api.services.SchemaService;
 import org.apache.unomi.rest.authentication.AuthenticationFilter;
 import org.apache.unomi.rest.authentication.AuthorizingInterceptor;
 import org.apache.unomi.rest.authentication.RestAuthenticationConfig;
+import org.apache.unomi.rest.deserializers.ContextRequestDeserializer;
+import org.apache.unomi.rest.deserializers.EventCollectorRequestDeserializer;
 import 
org.apache.unomi.rest.server.provider.RetroCompatibilityParamConverterProvider;
 import 
org.apache.unomi.rest.validation.JAXRSBeanValidationInInterceptorOverride;
 import org.apache.unomi.rest.validation.BeanValidationService;
@@ -52,11 +58,7 @@ import org.slf4j.LoggerFactory;
 
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.xml.namespace.QName;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
+import java.util.*;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 @Component
@@ -75,6 +77,7 @@ public class RestServer {
     private List<ExceptionMapper> exceptionMappers = new ArrayList<>();
     private BeanValidationService beanValidationService;
     private ConfigSharingService configSharingService;
+    private SchemaService schemaService;
 
     // refresh
     private long timeOfLastUpdate = System.currentTimeMillis();
@@ -83,6 +86,11 @@ public class RestServer {
 
     private static final QName UNOMI_REST_SERVER_END_POINT_NAME = new 
QName("http://rest.unomi.apache.org/";, "UnomiRestServerEndPoint");
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    public void setSchemaService(SchemaService schemaService) {
+        this.schemaService = schemaService;
+    }
+
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     public void setServerBus(Bus serverBus) {
         this.serverBus = serverBus;
@@ -203,8 +211,13 @@ public class RestServer {
         List<Interceptor<? extends Message>> inInterceptors = new 
ArrayList<>();
         List<Interceptor<? extends Message>> outInterceptors = new 
ArrayList<>();
 
+        Map<Class, StdDeserializer<?>> desers = new HashMap<>();
+        desers.put(ContextRequest.class, new 
ContextRequestDeserializer(schemaService));
+        desers.put(EventsCollectorRequest.class, new 
EventCollectorRequestDeserializer(schemaService));
+
+
         // Build the server
-        ObjectMapper objectMapper = new 
org.apache.unomi.persistence.spi.CustomObjectMapper();
+        ObjectMapper objectMapper = new 
org.apache.unomi.persistence.spi.CustomObjectMapper(desers);
         JAXRSServerFactoryBean jaxrsServerFactoryBean = new 
JAXRSServerFactoryBean();
         jaxrsServerFactoryBean.setAddress("/");
         jaxrsServerFactoryBean.setBus(serverBus);
diff --git 
a/rest/src/main/java/org/apache/unomi/rest/server/provider/RetroCompatibilityParamConverterProvider.java
 
b/rest/src/main/java/org/apache/unomi/rest/server/provider/RetroCompatibilityParamConverterProvider.java
index 9dc65007d..d7b6f3e84 100644
--- 
a/rest/src/main/java/org/apache/unomi/rest/server/provider/RetroCompatibilityParamConverterProvider.java
+++ 
b/rest/src/main/java/org/apache/unomi/rest/server/provider/RetroCompatibilityParamConverterProvider.java
@@ -20,9 +20,12 @@ import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.unomi.api.ContextRequest;
 import org.apache.unomi.api.EventsCollectorRequest;
+import org.apache.unomi.rest.validation.request.InvalidRequestException;
 
+import javax.ws.rs.BadRequestException;
 import javax.ws.rs.ProcessingException;
 import javax.ws.rs.ext.*;
+import java.io.IOException;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
@@ -62,7 +65,7 @@ public class RetroCompatibilityParamConverterProvider 
implements ParamConverterP
                     try {
                         return 
objectMapper.readValue(factory.createParser(value), rawType);
                     } catch (Exception e) {
-                        throw new ProcessingException(e);
+                        throw new InvalidRequestException("Invalid received 
data", "Invalid received data");
                     }
                 }
 
diff --git 
a/rest/src/main/java/org/apache/unomi/rest/service/impl/RestServiceUtilsImpl.java
 
b/rest/src/main/java/org/apache/unomi/rest/service/impl/RestServiceUtilsImpl.java
index 35a3d92a0..9f05bd6be 100644
--- 
a/rest/src/main/java/org/apache/unomi/rest/service/impl/RestServiceUtilsImpl.java
+++ 
b/rest/src/main/java/org/apache/unomi/rest/service/impl/RestServiceUtilsImpl.java
@@ -87,11 +87,6 @@ public class RestServiceUtilsImpl implements 
RestServiceUtils {
             for (Event event : events) {
                 processedEventsCnt++;
                 if (event.getEventType() != null) {
-                    if (!eventService.isEventValid(event)) {
-                        logger.warn("Event is not valid : {}", 
event.getEventType());
-                        continue;
-                    }
-
                     Event eventToSend = new Event(event.getEventType(), 
session, profile, event.getSourceId(), event.getSource(),
                             event.getTarget(), event.getProperties(), 
timestamp, event.isPersistent());
                     if (!eventService.isEventAllowed(event, thirdPartyId)) {
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 20fbdfee2..736de11cb 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
@@ -17,6 +17,7 @@
 
 package org.apache.unomi.services.impl.events;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import inet.ipaddr.IPAddress;
 import inet.ipaddr.IPAddressString;
 import org.apache.commons.lang3.StringUtils;
@@ -31,6 +32,7 @@ import org.apache.unomi.api.actions.ActionPostExecutor;
 import org.apache.unomi.api.conditions.Condition;
 import org.apache.unomi.api.query.Query;
 import org.apache.unomi.api.services.*;
+import org.apache.unomi.persistence.spi.CustomObjectMapper;
 import org.apache.unomi.persistence.spi.PersistenceService;
 import org.apache.unomi.persistence.spi.aggregate.TermsAggregate;
 import org.apache.unomi.api.utils.ParserHelper;
@@ -138,10 +140,6 @@ public class EventServiceImpl implements EventService {
         return true;
     }
 
-    public boolean isEventValid(Event event) {
-        return schemaService.isValid(event, 
"https://unomi.apache.org/schemas/json/events/"; + event.getEventType() + 
"/1-0-0");
-    }
-
     public String authenticateThirdPartyServer(String key, String ip) {
         logger.debug("Authenticating third party server with key: " + key + " 
and IP: " + ip);
         if (key != null) {
diff --git 
a/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaServiceImpl.java
 
b/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaServiceImpl.java
index c9c1e96da..dc6a339b9 100644
--- 
a/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaServiceImpl.java
+++ 
b/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaServiceImpl.java
@@ -108,7 +108,7 @@ public class SchemaServiceImpl implements SchemaService {
     }
 
     @Override
-    public boolean isValid(Object object, String schemaId) {
+    public boolean isValid(JsonNode jsonNode, String schemaId) {
         String schemaAsString;
         JsonSchema jsonSchema = null;
         try {
@@ -124,7 +124,7 @@ public class SchemaServiceImpl implements SchemaService {
         }
 
         if (jsonSchema != null) {
-            JsonNode jsonNode = 
CustomObjectMapper.getObjectMapper().convertValue(object, JsonNode.class);
+
             Set<ValidationMessage> validationMessages = 
jsonSchema.validate(jsonNode);
             if (validationMessages == null || validationMessages.isEmpty()) {
                 return true;
diff --git 
a/services/src/main/resources/META-INF/cxs/schemas/contextrequest.json 
b/services/src/main/resources/META-INF/cxs/schemas/contextrequest.json
new file mode 100644
index 000000000..c81a4f765
--- /dev/null
+++ b/services/src/main/resources/META-INF/cxs/schemas/contextrequest.json
@@ -0,0 +1,65 @@
+{
+  "$id": "https://unomi.apache.org/schemas/json/contextrequest/1-0-0";,
+  "$schema": "https://json-schema.org/draft/2019-09/schema";,
+  "title": "ContextRequest",
+  "type": "object",
+  "properties": {
+    "source": {
+      "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0";
+    },
+    "requireSegments": {
+      "type": ["null", "boolean"]
+    },
+    "requiredProfileProperties": {
+      "type": ["null", "array"],
+      "items": {
+        "type": "string"
+      }
+    },
+    "requiredSessionProperties": {
+      "type": ["null", "array"],
+      "items": {
+        "type": "string"
+      }
+    },
+    "requireScores": {
+      "type": ["null", "boolean"]
+    },
+    "events": {
+      "type": ["null", "array"],
+      "items": {
+        "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0";
+      }
+    },
+    "filters": {
+      "type": ["null", "array"],
+      "items": {
+        "$ref": 
"https://unomi.apache.org/schemas/json/personalization/personalizedcontent/1-0-0";
+      }
+    },
+    "personalizations": {
+      "type": ["null", "array"],
+      "items": {
+        "$ref": 
"https://unomi.apache.org/schemas/json/personalization/personalizedrequest/1-0-0";
+      }
+    },
+    "profileOverrides": {
+      "$ref": "https://unomi.apache.org/schemas/json/profile/1-0-0";
+    },
+    "sessionPropertiesOverrides": {
+      "type": ["null", "object"],
+      "maxProperties": 50
+    },
+    "sessionId": {
+      "type": ["null", "string"],
+      "pattern" : "^(\\w|[-_@\\.]){0,60}$"
+    },
+    "profileId": {
+      "type": ["null", "string"],
+      "pattern" : "^(\\w|[-_@\\.]){0,60}$"
+    },
+    "clientId": {
+      "type": ["null", "string"]
+    }
+  }
+}
diff --git a/services/src/main/resources/META-INF/cxs/schemas/event.json 
b/services/src/main/resources/META-INF/cxs/schemas/event.json
index 66cb8ad85..7c3b5bfd1 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/event.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/event.json
@@ -10,19 +10,19 @@
       "pattern" : "^(\\w|[-_@\\.]){0,60}$"
     },
     "profileId" : {
-      "type" : [ "null", "string"],
+      "type" : [ "string"],
       "pattern" : "^(\\w|[-_@\\.]){0,60}$"
     },
     "sessionId" : {
-      "type" : [ "null", "string"],
+      "type" : [ "string"],
       "pattern" : "^(\\w|[-_@\\.]){0,60}$"
     },
     "scope" : {
-      "type" : [ "null", "string"],
+      "type" : [ "string"],
       "pattern" : "^(\\w|[-_@\\.]){0,60}$"
     },
     "sourceId" : {
-      "type" : [ "null", "string"],
+      "type" : [ "string"],
       "pattern" : "^(\\w|[-_@\\.]){0,60}$"
     }
   }
diff --git 
a/services/src/main/resources/META-INF/cxs/schemas/eventscollectorrequest.json 
b/services/src/main/resources/META-INF/cxs/schemas/eventscollectorrequest.json
new file mode 100644
index 000000000..39e98ff83
--- /dev/null
+++ 
b/services/src/main/resources/META-INF/cxs/schemas/eventscollectorrequest.json
@@ -0,0 +1,23 @@
+{
+  "$id": "https://unomi.apache.org/schemas/json/eventscollectorrequest/1-0-0";,
+  "$schema": "https://json-schema.org/draft/2019-09/schema";,
+  "title": "EventsCollectorRequest",
+  "type": "object",
+  "allOf": [
+    {
+      "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0";
+    }
+  ],
+  "properties": {
+    "events" : {
+      "type": ["null", "array"],
+      "items": {
+        "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0";
+      }
+    },
+    "sessionId" : {
+      "type": ["null", "string"],
+      "pattern" : "^(\\w|[-_@\\.]){0,60}$"
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/services/src/main/resources/META-INF/cxs/schemas/personalization/filter.json 
b/services/src/main/resources/META-INF/cxs/schemas/personalization/filter.json
new file mode 100644
index 000000000..112be929e
--- /dev/null
+++ 
b/services/src/main/resources/META-INF/cxs/schemas/personalization/filter.json
@@ -0,0 +1,21 @@
+{
+  "$id": "https://unomi.apache.org/schemas/json/personalization/filter/1-0-0";,
+  "$schema": "https://json-schema.org/draft/2019-09/schema";,
+  "title": "Filter",
+  "type": "object",
+  "properties": {
+    "appliesOn": {
+      "type": "array",
+      "items": {
+        "$ref": 
"https://unomi.apache.org/schemas/json/personalization/target/1-0-0";
+      }
+    },
+    "condition": {
+      "$ref": "https://unomi.apache.org/schemas/json/condition/1-0-0";
+    },
+    "properties": {
+      "type": "object",
+      "maxProperties": 50
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/services/src/main/resources/META-INF/cxs/schemas/personalization/personalizationrequest.json
 
b/services/src/main/resources/META-INF/cxs/schemas/personalization/personalizationrequest.json
new file mode 100644
index 000000000..37e99f71c
--- /dev/null
+++ 
b/services/src/main/resources/META-INF/cxs/schemas/personalization/personalizationrequest.json
@@ -0,0 +1,25 @@
+{
+  "$id": 
"https://unomi.apache.org/schemas/json/personalization/personalizedrequest/1-0-0";,
+  "$schema": "https://json-schema.org/draft/2019-09/schema";,
+  "title": "PersonalizationRequest",
+  "type": "object",
+  "properties": {
+    "id" : {
+      "type" : "string"
+    },
+    "strategy" : {
+      "type" : "string"
+    },
+    "strategyOptions" : {
+      "type": "object",
+      "maxProperties": 50
+    },
+    "contents" : {
+      "type" : "array",
+      "items": {
+        "$ref": 
"https://unomi.apache.org/schemas/json/personalization/personalizedcontent/1-0-0";
+      },
+      "maxProperties": 50
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/services/src/main/resources/META-INF/cxs/schemas/personalization/personalizedcontent.json
 
b/services/src/main/resources/META-INF/cxs/schemas/personalization/personalizedcontent.json
new file mode 100644
index 000000000..b8a29ef73
--- /dev/null
+++ 
b/services/src/main/resources/META-INF/cxs/schemas/personalization/personalizedcontent.json
@@ -0,0 +1,22 @@
+{
+  "$id": 
"https://unomi.apache.org/schemas/json/personalization/personalizedcontent/1-0-0";,
+  "$schema": "https://json-schema.org/draft/2019-09/schema";,
+  "title": "PersonalizedContent",
+  "type": "object",
+  "properties": {
+    "id": {
+      "type": "string"
+    },
+    "filters": {
+      "type": "array",
+      "items": {
+        "$ref": 
"https://unomi.apache.org/schemas/json/personalization/filter/1-0-0";
+      },
+      "maxProperties": 50
+    },
+    "properties": {
+      "type": "object",
+      "maxProperties": 50
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/services/src/main/resources/META-INF/cxs/schemas/personalization/target.json 
b/services/src/main/resources/META-INF/cxs/schemas/personalization/target.json
new file mode 100644
index 000000000..4de017a47
--- /dev/null
+++ 
b/services/src/main/resources/META-INF/cxs/schemas/personalization/target.json
@@ -0,0 +1,17 @@
+{
+  "$id": "https://unomi.apache.org/schemas/json/personalization/target/1-0-0";,
+  "$schema": "https://json-schema.org/draft/2019-09/schema";,
+  "title": "Target",
+  "type": "object",
+  "properties": {
+    "target" : {
+      "type" : "string"
+    },
+    "values" : {
+      "type" : "array",
+      "items": {
+        "type": "string"
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json 
b/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json
index 1d7c6ad3a..b4e1528d3 100644
--- a/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json
+++ b/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json
@@ -6,7 +6,7 @@
   "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0"; }],
   "properties" : {
     "timeStamp" : {
-      "type" : ["null","string"],
+      "type" : ["string"],
       "format" : "date-time"
     }
   }

Reply via email to