This is an automated email from the ASF dual-hosted git repository. shuber pushed a commit to branch UNOMI-486-json-schema-graphql in repository https://gitbox.apache.org/repos/asf/unomi.git
commit 9f0e07d2aedd48dbb0898dc4a8421c93cef19a9b Author: Serge Huber <[email protected]> AuthorDate: Tue Feb 15 17:30:32 2022 +0100 JSON Schema GraphQL integration --- .../main/java/org/apache/unomi/api/EventType.java | 73 ------ .../main/java/org/apache/unomi/api/SchemaType.java | 60 ----- .../json/JSONArrayType.java} | 19 +- .../json/JSONBooleanType.java} | 20 +- .../json/JSONEnumType.java} | 20 +- .../json/JSONIntegerType.java} | 20 +- .../json/JSONNullType.java} | 20 +- .../json/JSONNumberType.java} | 20 +- .../unomi/api/schema/json/JSONObjectType.java | 52 ++++ .../apache/unomi/api/schema/json/JSONSchema.java | 107 +++++++++ .../json/JSONStringType.java} | 20 +- .../org/apache/unomi/api/schema/json/JSONType.java | 111 +++++++++ .../unomi/api/schema/json/JSONTypeFactory.java | 91 +++++++ .../apache/unomi/api/services/EventService.java | 16 +- .../unomi/api/services/EventTypeRegistry.java | 59 ----- .../apache/unomi/api/services/SchemaRegistry.java | 11 +- .../graphql/schema/GraphQLSchemaProvider.java | 198 +++++++++++----- .../unomi/graphql/schema/GraphQLSchemaUpdater.java | 10 +- .../unomi/graphql/schema/PropertyFilterUtils.java | 26 +- .../types/resolvers/CDPEventInterfaceResolver.java | 12 +- .../org/apache/unomi/itests/ContextServletIT.java | 105 +++------ .../schemas/events/float-property-type.json | 21 ++ .../resources/schemas/events/test-event-type.json | 13 + .../unomi/rest/endpoints/EventServiceEndpoint.java | 12 - .../services/impl/events/EventServiceImpl.java | 19 +- .../impl/events/EventTypeRegistryImpl.java | 261 --------------------- .../services/impl/schemas/SchemaRegistryImpl.java | 92 +++++--- .../resources/META-INF/cxs/schemas/condition.json | 2 +- .../META-INF/cxs/schemas/conditiontype.json | 6 +- .../resources/META-INF/cxs/schemas/consent.json | 2 +- .../META-INF/cxs/schemas/consentType.json | 2 +- .../resources/META-INF/cxs/schemas/customitem.json | 4 +- .../META-INF/cxs/schemas/customitems/page.json | 13 +- .../META-INF/cxs/schemas/customitems/site.json | 11 +- .../main/resources/META-INF/cxs/schemas/event.json | 4 +- .../META-INF/cxs/schemas/events/modifyConsent.json | 22 +- .../META-INF/cxs/schemas/events/view.json | 17 +- .../main/resources/META-INF/cxs/schemas/goal.json | 8 +- .../main/resources/META-INF/cxs/schemas/item.json | 2 +- .../resources/META-INF/cxs/schemas/metadata.json | 2 +- .../META-INF/cxs/schemas/metadataitem.json | 6 +- .../resources/META-INF/cxs/schemas/parameter.json | 2 +- .../resources/META-INF/cxs/schemas/profile.json | 4 +- .../resources/META-INF/cxs/schemas/session.json | 6 +- .../META-INF/cxs/schemas/timestampeditem.json | 4 +- .../META-INF/cxs/schemas/values/boolean.json | 2 +- .../META-INF/cxs/schemas/values/date.json | 2 +- .../META-INF/cxs/schemas/values/email.json | 2 +- .../META-INF/cxs/schemas/values/integer.json | 2 +- .../META-INF/cxs/schemas/values/long.json | 2 +- .../resources/META-INF/cxs/schemas/values/set.json | 2 +- .../META-INF/cxs/schemas/values/string.json | 2 +- .../resources/OSGI-INF/blueprint/blueprint.xml | 7 - 53 files changed, 792 insertions(+), 834 deletions(-) diff --git a/api/src/main/java/org/apache/unomi/api/EventType.java b/api/src/main/java/org/apache/unomi/api/EventType.java deleted file mode 100644 index 5ae05b8..0000000 --- a/api/src/main/java/org/apache/unomi/api/EventType.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.unomi.api; - -import java.util.Set; - -/** - * An event type definition, used to define the structure of accepted events - */ -public class EventType implements PluginType { - - private String type; - - private Set<PropertyType> propertyTypes; - - private long pluginId; - - public EventType() { - } - - public EventType(String type, Set<PropertyType> propertyTypes, long pluginId) { - this.type = type; - this.propertyTypes = propertyTypes; - this.pluginId = pluginId; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public Set<PropertyType> getPropertyTypes() { - return propertyTypes; - } - - public void setPropertyTypes(Set<PropertyType> propertyTypes) { - this.propertyTypes = propertyTypes; - } - - @Override - public long getPluginId() { - return pluginId; - } - - @Override - public void setPluginId(long pluginId) { - this.pluginId = pluginId; - } - - public void merge(final EventType source) { - if (source == null || source.getPropertyTypes() == null || source.getPropertyTypes().isEmpty()) { - return; - } - this.propertyTypes.addAll(source.getPropertyTypes()); - } -} diff --git a/api/src/main/java/org/apache/unomi/api/SchemaType.java b/api/src/main/java/org/apache/unomi/api/SchemaType.java deleted file mode 100644 index a3bd37a..0000000 --- a/api/src/main/java/org/apache/unomi/api/SchemaType.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.unomi.api; - -import java.util.Map; - -public class SchemaType implements PluginType { - - private transient long pluginId; - private String schemaId; - private String target; - private Map<String,Object> schemaTree; - - public long getPluginId() { - return pluginId; - } - - public void setPluginId(long pluginId) { - this.pluginId = pluginId; - } - - public String getSchemaId() { - return schemaId; - } - - public void setSchemaId(String schemaId) { - this.schemaId = schemaId; - } - - public String getTarget() { - return target; - } - - public void setTarget(String target) { - this.target = target; - } - - public Map<String, Object> getSchemaTree() { - return schemaTree; - } - - public void setSchemaTree(Map<String, Object> schemaTree) { - this.schemaTree = schemaTree; - } -} diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONArrayType.java similarity index 66% copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONArrayType.java index 03a234e..add106d 100644 --- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONArrayType.java @@ -14,19 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.unomi.api.schema.json; -package org.apache.unomi.api.services; - -import org.apache.unomi.api.SchemaType; +import org.apache.unomi.api.services.SchemaRegistry; import java.util.List; +import java.util.Map; -public interface SchemaRegistry { - - boolean isValid(Object object, String schemaId); - - SchemaType getSchema(String schemaId); +public class JSONArrayType extends JSONType { - List<SchemaType> getTargetSchemas(String target); + List<JSONType> items; + JSONType contains; + public JSONArrayType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + super(schemaTree, jsonTypeFactory, schemaRegistry); + setType("array"); + } } diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONBooleanType.java similarity index 67% copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONBooleanType.java index 03a234e..cfaa734 100644 --- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONBooleanType.java @@ -14,19 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.unomi.api.schema.json; -package org.apache.unomi.api.services; +import org.apache.unomi.api.services.SchemaRegistry; -import org.apache.unomi.api.SchemaType; - -import java.util.List; - -public interface SchemaRegistry { - - boolean isValid(Object object, String schemaId); - - SchemaType getSchema(String schemaId); - - List<SchemaType> getTargetSchemas(String target); +import java.util.Map; +public class JSONBooleanType extends JSONType { + public JSONBooleanType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + super(schemaTree, jsonTypeFactory, schemaRegistry); + setType("boolean"); + } } diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONEnumType.java similarity index 68% copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONEnumType.java index 03a234e..d2e18a0 100644 --- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONEnumType.java @@ -14,19 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.unomi.api.schema.json; -package org.apache.unomi.api.services; +import org.apache.unomi.api.services.SchemaRegistry; -import org.apache.unomi.api.SchemaType; - -import java.util.List; - -public interface SchemaRegistry { - - boolean isValid(Object object, String schemaId); - - SchemaType getSchema(String schemaId); - - List<SchemaType> getTargetSchemas(String target); +import java.util.Map; +public class JSONEnumType extends JSONType { + public JSONEnumType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + super(schemaTree, jsonTypeFactory, schemaRegistry); + setType("enum"); + } } diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONIntegerType.java similarity index 67% copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONIntegerType.java index 03a234e..6aa9a32 100644 --- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONIntegerType.java @@ -14,19 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.unomi.api.schema.json; -package org.apache.unomi.api.services; +import org.apache.unomi.api.services.SchemaRegistry; -import org.apache.unomi.api.SchemaType; - -import java.util.List; - -public interface SchemaRegistry { - - boolean isValid(Object object, String schemaId); - - SchemaType getSchema(String schemaId); - - List<SchemaType> getTargetSchemas(String target); +import java.util.Map; +public class JSONIntegerType extends JSONType { + public JSONIntegerType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + super(schemaTree, jsonTypeFactory, schemaRegistry); + setType("integer"); + } } diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONNullType.java similarity index 68% copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONNullType.java index 03a234e..ec0adde 100644 --- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONNullType.java @@ -14,19 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.unomi.api.schema.json; -package org.apache.unomi.api.services; +import org.apache.unomi.api.services.SchemaRegistry; -import org.apache.unomi.api.SchemaType; - -import java.util.List; - -public interface SchemaRegistry { - - boolean isValid(Object object, String schemaId); - - SchemaType getSchema(String schemaId); - - List<SchemaType> getTargetSchemas(String target); +import java.util.Map; +public class JSONNullType extends JSONType { + public JSONNullType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + super(schemaTree, jsonTypeFactory, schemaRegistry); + setType("null"); + } } diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONNumberType.java similarity index 67% copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONNumberType.java index 03a234e..bb6bf13 100644 --- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONNumberType.java @@ -14,19 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.unomi.api.schema.json; -package org.apache.unomi.api.services; +import org.apache.unomi.api.services.SchemaRegistry; -import org.apache.unomi.api.SchemaType; - -import java.util.List; - -public interface SchemaRegistry { - - boolean isValid(Object object, String schemaId); - - SchemaType getSchema(String schemaId); - - List<SchemaType> getTargetSchemas(String target); +import java.util.Map; +public class JSONNumberType extends JSONType { + public JSONNumberType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + super(schemaTree, jsonTypeFactory, schemaRegistry); + setType("number"); + } } diff --git a/api/src/main/java/org/apache/unomi/api/schema/json/JSONObjectType.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONObjectType.java new file mode 100644 index 0000000..45b25e0 --- /dev/null +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONObjectType.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.unomi.api.schema.json; + +import org.apache.unomi.api.services.SchemaRegistry; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class JSONObjectType extends JSONType { + + Map<String,List<JSONType>> properties = new HashMap<>(); + JSONType additionalProperties; + Map<String,List<JSONType>> patternProperties = new HashMap<>(); + JSONType propertyNames; + + int maxProperties; + + public JSONObjectType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + super(schemaTree, jsonTypeFactory, schemaRegistry); + setType("object"); + Map<String,Object> propertiesTree = (Map<String,Object>) schemaTree.get("properties"); + if (propertiesTree != null) { + propertiesTree.entrySet().forEach(entry -> { + properties.put(entry.getKey(), jsonTypeFactory.getTypes((Map<String,Object>)entry.getValue())); + }); + } + } + + public Map<String,List<JSONType>> getProperties() { + return properties; + } + + public void setProperties(Map<String,List<JSONType>> properties) { + this.properties = properties; + } +} diff --git a/api/src/main/java/org/apache/unomi/api/schema/json/JSONSchema.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONSchema.java new file mode 100644 index 0000000..544d009 --- /dev/null +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONSchema.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.unomi.api.schema.json; + +import org.apache.unomi.api.PluginType; +import org.apache.unomi.api.services.SchemaRegistry; + +import java.util.List; +import java.util.Map; + +public class JSONSchema extends JSONType implements PluginType { + + private transient long pluginId; + private String schemaId; + private String target; + private List<JSONType> rootTypes; + + private String vendor; + private String name; + private String version; + + public JSONSchema(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + super(schemaTree, jsonTypeFactory, schemaRegistry); + schemaId = (String) schemaTree.get("$id"); + if (schemaTree.containsKey("self")) { + Map<String,Object> self = (Map<String,Object>) schemaTree.get("self"); + name = (String) self.get("name"); + vendor = (String) self.get("vendor"); + version = (String) self.get("version"); + target = (String) self.get("target"); + } + } + + public String getVendor() { + return vendor; + } + + public void setVendor(String vendor) { + this.vendor = vendor; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public long getPluginId() { + return pluginId; + } + + public void setPluginId(long pluginId) { + this.pluginId = pluginId; + } + + public String getSchemaId() { + return schemaId; + } + + public void setSchemaId(String schemaId) { + this.schemaId = schemaId; + } + + public String getTarget() { + return target; + } + + public void setTarget(String target) { + this.target = target; + } + + public List<JSONType> getRootTypes() { + if (rootTypes == null) { + buildRootTypes(); + } + return rootTypes; + } + + private void buildRootTypes() { + rootTypes = jsonTypeFactory.getTypes(schemaTree); + } +} diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONStringType.java similarity index 67% copy from api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java copy to api/src/main/java/org/apache/unomi/api/schema/json/JSONStringType.java index 03a234e..c1b9c10 100644 --- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONStringType.java @@ -14,19 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.apache.unomi.api.schema.json; -package org.apache.unomi.api.services; +import org.apache.unomi.api.services.SchemaRegistry; -import org.apache.unomi.api.SchemaType; - -import java.util.List; - -public interface SchemaRegistry { - - boolean isValid(Object object, String schemaId); - - SchemaType getSchema(String schemaId); - - List<SchemaType> getTargetSchemas(String target); +import java.util.Map; +public class JSONStringType extends JSONType { + public JSONStringType(Map<String, Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + super(schemaTree, jsonTypeFactory, schemaRegistry); + setType("string"); + } } diff --git a/api/src/main/java/org/apache/unomi/api/schema/json/JSONType.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONType.java new file mode 100644 index 0000000..3b60b0f --- /dev/null +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONType.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.unomi.api.schema.json; + +import org.apache.unomi.api.services.SchemaRegistry; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class JSONType { + + String type; + String name; + List<String> required; + String ref; + List<JSONType> anyOf; + List<JSONType> oneOf; + + Map<String,Object> customKeywords; + + protected Map<String,Object> schemaTree; + + protected JSONTypeFactory jsonTypeFactory; + + protected SchemaRegistry schemaRegistry; + + public JSONType(Map<String,Object> schemaTree, JSONTypeFactory jsonTypeFactory, SchemaRegistry schemaRegistry) { + this.schemaTree = schemaTree; + this.jsonTypeFactory = jsonTypeFactory; + this.schemaRegistry = schemaRegistry; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Map<String, Object> getSchemaTree() { + return schemaTree; + } + + public JSONTypeFactory getJsonTypeFactory() { + return jsonTypeFactory; + } + + public SchemaRegistry getSchemaRegistry() { + return schemaRegistry; + } + + public String getRef() { + ref = (String) schemaTree.get("$ref"); + return ref; + } + + public List<JSONType> getAllOf() { + List<Map<String,Object>> allOfTree = (List<Map<String,Object>>) schemaTree.get("allOf"); + List<JSONType> allOfTypes = new ArrayList<>(); + if (allOfTree != null) { + for (Map<String,Object> allOfEntry : allOfTree) { + List<JSONType> entryTypes = jsonTypeFactory.getTypes(allOfEntry); + allOfTypes.addAll(entryTypes); + } + } + return allOfTypes; + } + + public List<JSONType> getAnyOf() { + return anyOf; + } + + public List<JSONType> getOneOf() { + return oneOf; + } + + public Map<String, Object> getCustomKeywords() { + return customKeywords; + } + + public boolean merge(JSONType anotherType) { + if (!anotherType.getType().equals(getType())) { + return false; + } + return true; + } +} diff --git a/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java b/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java new file mode 100644 index 0000000..da79016 --- /dev/null +++ b/api/src/main/java/org/apache/unomi/api/schema/json/JSONTypeFactory.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.unomi.api.schema.json; + +import org.apache.unomi.api.services.SchemaRegistry; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class JSONTypeFactory { + + Map<String, Class<? extends JSONType>> jsonTypes = new HashMap<>(); + + SchemaRegistry schemaRegistry; + + public JSONTypeFactory(SchemaRegistry schemaRegistry) { + this.schemaRegistry = schemaRegistry; + jsonTypes.put("object", JSONObjectType.class); + jsonTypes.put("string", JSONStringType.class); + jsonTypes.put("array", JSONArrayType.class); + jsonTypes.put("number", JSONNumberType.class); + jsonTypes.put("integer", JSONIntegerType.class); + jsonTypes.put("boolean", JSONBooleanType.class); + jsonTypes.put("null", JSONNullType.class); + } + + List<JSONType> getTypes(Map<String,Object> schemaTree) { + if (schemaTree.containsKey("$ref")) { + String schemaId = (String) schemaTree.get("$ref"); + JSONSchema refSchema = schemaRegistry.getSchema(schemaId); + if (refSchema != null) { + schemaTree = refSchema.getSchemaTree(); + } else { + System.err.println("Couldn't find schema for ref " + schemaId); + } + } + if (schemaTree.containsKey("enum")) { + List<JSONType> result = new ArrayList<>(); + result.add(new JSONEnumType(schemaTree, this, schemaRegistry)); + return result; + } + Object typeObject = schemaTree.get("type"); + if (typeObject == null) { + return new ArrayList<>(); + } + List<String> types = null; + if (typeObject instanceof String) { + types = new ArrayList<>(); + types.add((String) typeObject); + } else { + types = (List<String>) typeObject; + } + List<JSONType> resultJsonTypes = new ArrayList<>(); + for (String type : types) { + if (type == null) { + continue; + } + if (!jsonTypes.containsKey(type)) { + continue; + } + Class<? extends JSONType> typeClass = jsonTypes.get(type); + Constructor<? extends JSONType> constructor = null; + try { + constructor = typeClass.getConstructor(Map.class, JSONTypeFactory.class, SchemaRegistry.class); + resultJsonTypes.add(constructor.newInstance(schemaTree, this, schemaRegistry)); + } catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + } + return resultJsonTypes; + } + +} 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 c6136a3..4dde0a9 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 @@ -19,7 +19,6 @@ package org.apache.unomi.api.services; import org.apache.unomi.api.Event; import org.apache.unomi.api.EventProperty; -import org.apache.unomi.api.EventType; import org.apache.unomi.api.PartialList; import org.apache.unomi.api.Session; import org.apache.unomi.api.actions.ActionPostExecutor; @@ -72,7 +71,7 @@ public interface EventService { /** - * Check if event fields complies with corresponding {@link EventType} definition + * Check if event fields complies with corresponding event JSON schema definition * * @param event event to test * @return true if the event is valid @@ -97,19 +96,6 @@ public interface EventService { List<EventProperty> getEventProperties(); /** - * Retrieves an event type - * @param typeName the name identifier for the event type - * @return the EventType object corresponding to the name, or null if not found. - */ - EventType getEventType(String typeName); - - /** - * Registers event type - * @param eventType event type to register - */ - void registerEventType(EventType eventType); - - /** * Retrieves the set of known event type identifiers. * * @return the set of known event type identifiers. diff --git a/api/src/main/java/org/apache/unomi/api/services/EventTypeRegistry.java b/api/src/main/java/org/apache/unomi/api/services/EventTypeRegistry.java deleted file mode 100644 index c81668c..0000000 --- a/api/src/main/java/org/apache/unomi/api/services/EventTypeRegistry.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.unomi.api.services; - -import org.apache.unomi.api.Event; -import org.apache.unomi.api.EventType; - -import java.util.Collection; - -/** - * An event types registry service. - */ -public interface EventTypeRegistry { - - /** - * Retrieve event type definition - * - * @param typeName name of the event type - * @return {@link EventType} definition - */ - EventType get(String typeName); - - /** - * Adds event type definition to registry - * - * @param eventType {@link EventType} definition - */ - void register(EventType eventType); - - /** - * Checks if event complies with {@link EventType} definition - * - * @param event the event to validate - * @return result of validation - */ - boolean isValid(Event event); - - /** - * List all known event types - * - * @return Lists all known {@link EventType}s - */ - Collection<EventType> getAll(); -} diff --git a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java b/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java index 03a234e..1bdea07 100644 --- a/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java +++ b/api/src/main/java/org/apache/unomi/api/services/SchemaRegistry.java @@ -17,16 +17,21 @@ package org.apache.unomi.api.services; -import org.apache.unomi.api.SchemaType; +import org.apache.unomi.api.schema.json.JSONSchema; +import java.io.InputStream; import java.util.List; public interface SchemaRegistry { boolean isValid(Object object, String schemaId); - SchemaType getSchema(String schemaId); + JSONSchema getSchema(String schemaId); - List<SchemaType> getTargetSchemas(String target); + List<JSONSchema> getTargetSchemas(String target); + + String registerSchema(String target, InputStream jsonSchemaInputStream); + + boolean unregisterSchema(String target, String schemaId); } diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java index 1f2d9bb..38358d0 100644 --- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java +++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaProvider.java @@ -33,10 +33,12 @@ import graphql.schema.GraphQLOutputType; import graphql.schema.GraphQLSchema; import graphql.schema.GraphQLType; import graphql.schema.visibility.GraphqlFieldVisibility; -import org.apache.unomi.api.EventType; import org.apache.unomi.api.PropertyType; -import org.apache.unomi.api.services.EventTypeRegistry; +import org.apache.unomi.api.schema.json.JSONObjectType; +import org.apache.unomi.api.schema.json.JSONSchema; +import org.apache.unomi.api.schema.json.JSONType; import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.SchemaRegistry; import org.apache.unomi.graphql.CDPGraphQLConstants; import org.apache.unomi.graphql.converters.UnomiToGraphQLConverter; import org.apache.unomi.graphql.fetchers.CustomEventOrSetPropertyDataFetcher; @@ -72,13 +74,7 @@ import org.apache.unomi.graphql.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; import static graphql.schema.FieldCoordinates.coordinates; @@ -92,7 +88,7 @@ public class GraphQLSchemaProvider { private final ProfileService profileService; - private final EventTypeRegistry eventTypeRegistry; + private final SchemaRegistry schemaRegistry; private final List<GraphQLTypeFunctionProvider> typeFunctionProviders; @@ -116,9 +112,83 @@ public class GraphQLSchemaProvider { private Set<Class<?>> additionalTypes = new HashSet<>(); + public interface DefinitionType { + String getTypeId(); + String getName(); + boolean hasSubTypes(); + List<DefinitionType> getSubTypes(); + } + + public class PropertyTypeDefinitionType implements DefinitionType { + + private PropertyType propertyType; + + public PropertyTypeDefinitionType(PropertyType propertyType) { + this.propertyType = propertyType; + } + + @Override + public String getTypeId() { + return propertyType.getValueTypeId(); + } + + @Override + public String getName() { + return propertyType.getItemId(); + } + + @Override + public boolean hasSubTypes() { + return "set".equals(propertyType.getValueTypeId()); + } + + @Override + public List<DefinitionType> getSubTypes() { + return propertyType.getChildPropertyTypes().stream().map(PropertyTypeDefinitionType::new).collect(Collectors.toList()); + } + } + + public class JSONTypeDefinitionType implements DefinitionType { + private List<JSONType> jsonTypes; + private JSONType firstNonNullType; + private String name; + + public JSONTypeDefinitionType(String name, List<JSONType> jsonTypes) { + this.name = name; + this.jsonTypes = jsonTypes; + Optional<JSONType> firstNonNullType = jsonTypes.stream().filter(jsonType -> !"null".equals(jsonType.getType())).findFirst(); + if (firstNonNullType.isPresent()) { + this.firstNonNullType = firstNonNullType.get(); + } + } + + @Override + public String getTypeId() { + return firstNonNullType.getType(); + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean hasSubTypes() { + return firstNonNullType instanceof JSONObjectType && ((JSONObjectType) firstNonNullType).getProperties() != null; + } + + @Override + public List<DefinitionType> getSubTypes() { + if (!hasSubTypes()) { + return new ArrayList<>(); + } + return ((JSONObjectType) firstNonNullType).getProperties().entrySet().stream().map(entry -> new JSONTypeDefinitionType(entry.getKey(), entry.getValue())).collect(Collectors.toList()); + } + } + private GraphQLSchemaProvider(final Builder builder) { this.profileService = builder.profileService; - this.eventTypeRegistry = builder.eventTypeRegistry; + this.schemaRegistry = builder.schemaRegistry; this.eventPublisher = builder.eventPublisher; this.typeFunctionProviders = builder.typeFunctionProviders; this.extensionsProviders = builder.extensionsProviders; @@ -238,20 +308,21 @@ public class GraphQLSchemaProvider { } } - final Collection<PropertyType> propertyTypes = profileService.getTargetPropertyTypes("profiles"); + final Collection<PropertyType> profilePropertyTypes = profileService.getTargetPropertyTypes("profiles"); + final Collection<DefinitionType> profileDefinitionTypes = profilePropertyTypes.stream().map(PropertyTypeDefinitionType::new).collect(Collectors.toList()); // Profile - registerDynamicInputFilterFields(CDPProfilePropertiesFilterInput.TYPE_NAME, CDPProfilePropertiesFilterInput.class, propertyTypes); - registerDynamicInputFilterFields(CDPProfileUpdateEventFilterInput.TYPE_NAME, CDPProfileUpdateEventFilterInput.class, propertyTypes); - registerDynamicInputFields(CDPProfileUpdateEventInput.TYPE_NAME, CDPProfileUpdateEventInput.class, propertyTypes); + registerDynamicInputFilterFields(CDPProfilePropertiesFilterInput.TYPE_NAME, CDPProfilePropertiesFilterInput.class, profileDefinitionTypes); + registerDynamicInputFilterFields(CDPProfileUpdateEventFilterInput.TYPE_NAME, CDPProfileUpdateEventFilterInput.class, profileDefinitionTypes); + registerDynamicInputFields(CDPProfileUpdateEventInput.TYPE_NAME, CDPProfileUpdateEventInput.class, profileDefinitionTypes); registerDynamicEventFilterInputFields(); // Profile - registerDynamicOutputFields(CDPProfile.TYPE_NAME, CDPProfile.class, CustomerPropertyDataFetcher.class, propertyTypes); + registerDynamicOutputFields(CDPProfile.TYPE_NAME, CDPProfile.class, CustomerPropertyDataFetcher.class, profileDefinitionTypes); // Persona - registerDynamicInputFields(CDPPersonaInput.TYPE_NAME, CDPPersonaInput.class, propertyTypes); - registerDynamicOutputFields(CDPPersona.TYPE_NAME, CDPPersona.class, CustomerPropertyDataFetcher.class, propertyTypes); + registerDynamicInputFields(CDPPersonaInput.TYPE_NAME, CDPPersonaInput.class, profileDefinitionTypes); + registerDynamicOutputFields(CDPPersona.TYPE_NAME, CDPPersona.class, CustomerPropertyDataFetcher.class, profileDefinitionTypes); // Events registerDynamicUnomiInputEvents(schemaBuilder); @@ -260,18 +331,18 @@ public class GraphQLSchemaProvider { } private void registerDynamicUnomiInputEvents(GraphQLSchema.Builder schemaBuilder) { - final Collection<EventType> unomiEventTypes = eventTypeRegistry.getAll(); + final List<JSONSchema> unomiEventTypes = schemaRegistry.getTargetSchemas("events"); if (!unomiEventTypes.isEmpty()) { - for (EventType unomiEventType : unomiEventTypes) { - final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getType()) + "Input"; + for (JSONSchema unomiEventType : unomiEventTypes) { + final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getName()) + "Input"; final GraphQLInputObjectType objectType; if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) { - objectType = createDynamicEventInputType(unomiEventType); + objectType = createDynamicEventInputType(new JSONTypeDefinitionType(unomiEventType.getName(), unomiEventType.getRootTypes())); } else { objectType = (GraphQLInputObjectType) getFromTypeRegistry(typeName); - registerDynamicInputFields(typeName, objectType, unomiEventType.getPropertyTypes()); + registerDynamicInputFields(typeName, objectType, new JSONTypeDefinitionType(unomiEventType.getName(), unomiEventType.getRootTypes()).getSubTypes()); } if (objectType != null) { @@ -282,20 +353,20 @@ public class GraphQLSchemaProvider { } private void registerDynamicUnomiOutputEvents(GraphQLSchema.Builder schemaBuilder) { - final Collection<EventType> unomiEventTypes = eventTypeRegistry.getAll(); + final List<JSONSchema> unomiEventTypes = schemaRegistry.getTargetSchemas("events"); if (!unomiEventTypes.isEmpty()) { final GraphQLCodeRegistry.Builder codeRegisterBuilder = graphQLAnnotations.getContainer().getCodeRegistryBuilder(); - for (EventType unomiEventType : unomiEventTypes) { - final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getType()); + for (JSONSchema unomiEventType : unomiEventTypes) { + final String typeName = UnomiToGraphQLConverter.convertEventType(unomiEventType.getSchemaId()); final GraphQLObjectType objectType; if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) { - objectType = createDynamicEventOutputType(unomiEventType, codeRegisterBuilder); + objectType = createDynamicEventOutputType(new JSONTypeDefinitionType(unomiEventType.getName(), unomiEventType.getRootTypes()), codeRegisterBuilder); } else { objectType = (GraphQLObjectType) getFromTypeRegistry(typeName); - registerDynamicOutputFields(typeName, objectType, CustomerPropertyDataFetcher.class, unomiEventType.getPropertyTypes()); + registerDynamicOutputFields(typeName, objectType, CustomerPropertyDataFetcher.class, new JSONTypeDefinitionType(unomiEventType.getName(), unomiEventType.getRootTypes()).getSubTypes()); } if (objectType != null) { @@ -307,7 +378,7 @@ public class GraphQLSchemaProvider { private void registerDynamicInputFilterFields(final String typeName, final Class<?> annotatedClass, - final Collection<PropertyType> propertyTypes) { + final Collection<DefinitionType> propertyTypes) { final GraphQLInputObjectType originalObject = getInputObjectType(annotatedClass); final List<GraphQLInputObjectField> inputObjectFields = @@ -322,7 +393,7 @@ public class GraphQLSchemaProvider { private void registerDynamicOutputFields(final String graphQLTypeName, final Class<?> annotatedClass, final Class<? extends DynamicFieldDataFetcher> fetcherClass, - final Collection<PropertyType> propertyTypes) { + final Collection<DefinitionType> propertyTypes) { final GraphQLObjectType objectType = graphQLAnnotations.object(annotatedClass); registerDynamicOutputFields(graphQLTypeName, objectType, fetcherClass, propertyTypes); } @@ -330,15 +401,15 @@ public class GraphQLSchemaProvider { private void registerDynamicOutputFields(final String graphQLTypeName, final GraphQLObjectType graphQLObjectType, final Class<? extends DynamicFieldDataFetcher> fetcherClass, - final Collection<PropertyType> propertyTypes) { + final Collection<DefinitionType> propertyTypes) { final GraphQLCodeRegistry.Builder codeRegisterBuilder = graphQLAnnotations.getContainer().getCodeRegistryBuilder(); final List<GraphQLFieldDefinition> fieldDefinitions = new ArrayList<>(); propertyTypes.forEach(propertyType -> { - final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getItemId()); + final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getName()); - if ("set".equals(propertyType.getValueTypeId())) { + if (propertyType.hasSubTypes()) { final String typeName = StringUtils.capitalize(propertyName); if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) { @@ -355,12 +426,12 @@ public class GraphQLSchemaProvider { } } else { fieldDefinitions.add(GraphQLFieldDefinition.newFieldDefinition() - .type((GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getValueTypeId())) + .type((GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getTypeId())) .name(propertyName).build()); } try { - final DataFetcher dataFetcher = fetcherClass.getConstructor(String.class, String.class).newInstance(propertyName, propertyType.getValueTypeId()); + final DataFetcher dataFetcher = fetcherClass.getConstructor(String.class, String.class).newInstance(propertyName, propertyType.getTypeId()); codeRegisterBuilder.dataFetcher(FieldCoordinates.coordinates(graphQLTypeName, propertyName), dataFetcher); } catch (Exception e) { throw new RuntimeException(String.format("Error creating a data fetcher with class %s for field %s", fetcherClass.getName(), propertyName), e); @@ -375,20 +446,20 @@ public class GraphQLSchemaProvider { } private GraphQLObjectType createDynamicSetOutputType( - final PropertyType propertyType, final GraphQLCodeRegistry.Builder codeRegisterBuilder, final String parentName) { + final DefinitionType propertyType, final GraphQLCodeRegistry.Builder codeRegisterBuilder, final String parentName) { - return createDynamicOutputType(parentName != null ? parentName : propertyType.getItemId(), propertyType.getChildPropertyTypes(), null, codeRegisterBuilder); + return createDynamicOutputType(parentName != null ? parentName : propertyType.getName(), propertyType.getSubTypes(), null, codeRegisterBuilder); } private GraphQLObjectType createDynamicEventOutputType( - final EventType eventType, final GraphQLCodeRegistry.Builder codeRegisterBuilder) { + final DefinitionType eventType, final GraphQLCodeRegistry.Builder codeRegisterBuilder) { final Set<Class> interfaces = new HashSet<>(); interfaces.add(CDPEventInterface.class); - return createDynamicOutputType(UnomiToGraphQLConverter.convertEventType(eventType.getType()), eventType.getPropertyTypes(), interfaces, codeRegisterBuilder); + return createDynamicOutputType(UnomiToGraphQLConverter.convertEventType(eventType.getName()), eventType.getSubTypes(), interfaces, codeRegisterBuilder); } - private GraphQLObjectType createDynamicOutputType(final String name, final Set<PropertyType> propertyTypes, final Set<Class> interfaces, final GraphQLCodeRegistry.Builder codeRegisterBuilder) { + private GraphQLObjectType createDynamicOutputType(final String name, final List<DefinitionType> propertyTypes, final Set<Class> interfaces, final GraphQLCodeRegistry.Builder codeRegisterBuilder) { final String typeName = StringUtils.capitalize(PropertyNameTranslator.translateFromUnomiToGraphQL(name)); final GraphQLObjectType.Builder dynamicTypeBuilder = GraphQLObjectType.newObject() @@ -413,15 +484,16 @@ public class GraphQLSchemaProvider { } if (propertyTypes != null && !propertyTypes.isEmpty()) { + // propertyTypes.forEach(childPropertyType -> { - final boolean isSet = "set".equals(childPropertyType.getValueTypeId()); - String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getItemId()); + final boolean isSet = childPropertyType.hasSubTypes(); + String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getName()); GraphQLOutputType objectType = null; if (isSet) { objectType = createDynamicSetOutputType(childPropertyType, codeRegisterBuilder, typeName + "_" + childPropertyName); } else { - objectType = (GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getValueTypeId()); + objectType = (GraphQLOutputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getTypeId()); } if (objectType != null) { @@ -446,15 +518,15 @@ public class GraphQLSchemaProvider { return null; } - private GraphQLInputObjectType createDynamicEventInputType(final EventType eventType) { - return createDynamicInputType(UnomiToGraphQLConverter.convertEventType(eventType.getType()), eventType.getPropertyTypes(), true); + private GraphQLInputObjectType createDynamicEventInputType(final DefinitionType eventType) { + return createDynamicInputType(UnomiToGraphQLConverter.convertEventType(eventType.getName()), eventType.getSubTypes(), true); } - private GraphQLInputObjectType createDynamicSetInputType(final PropertyType propertyType, final String parentName) { - return createDynamicInputType(parentName != null ? parentName : propertyType.getItemId(), propertyType.getChildPropertyTypes(), false); + private GraphQLInputObjectType createDynamicSetInputType(final DefinitionType propertyType, final String parentName) { + return createDynamicInputType(parentName != null ? parentName : propertyType.getName(), propertyType.getSubTypes(), false); } - private GraphQLInputObjectType createDynamicInputType(final String name, final Set<PropertyType> propertyTypes, final boolean isEvent) { + private GraphQLInputObjectType createDynamicInputType(final String name, final List<DefinitionType> propertyTypes, final boolean isEvent) { final String typeName = StringUtils.capitalize(PropertyNameTranslator.translateFromUnomiToGraphQL(name)) + "Input"; final GraphQLInputObjectType.Builder dynamicTypeBuilder = GraphQLInputObjectType.newInputObject() @@ -470,14 +542,14 @@ public class GraphQLSchemaProvider { if (propertyTypes != null && !propertyTypes.isEmpty()) { propertyTypes.forEach(childPropertyType -> { - final boolean isSet = "set".equals(childPropertyType.getValueTypeId()); - String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getItemId()); + final boolean isSet = childPropertyType.hasSubTypes(); + String childPropertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(childPropertyType.getName()); GraphQLInputType objectType; if (isSet) { objectType = createDynamicSetInputType(childPropertyType, typeName + "_" + childPropertyName); } else { - objectType = (GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getValueTypeId()); + objectType = (GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(childPropertyType.getTypeId()); } if (objectType != null) { @@ -501,20 +573,20 @@ public class GraphQLSchemaProvider { private void registerDynamicInputFields(final String graphQLTypeName, final Class<?> clazz, - final Collection<PropertyType> propertyTypes) { + final Collection<DefinitionType> propertyTypes) { final GraphQLInputObjectType inputObjectType = getInputObjectType(clazz); registerDynamicInputFields(graphQLTypeName, inputObjectType, propertyTypes); } private void registerDynamicInputFields(final String graphQLTypeName, final GraphQLInputObjectType graphQLInputObjectType, - final Collection<PropertyType> propertyTypes) { + final Collection<DefinitionType> propertyTypes) { final List<GraphQLInputObjectField> fieldDefinitions = new ArrayList<>(); propertyTypes.forEach(propertyType -> { - final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getItemId()); + final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getName()); - if ("set".equals(propertyType.getValueTypeId())) { + if (propertyType.hasSubTypes()) { final String typeName = StringUtils.capitalize(propertyName) + "Input"; if (!graphQLAnnotations.getContainer().getTypeRegistry().containsKey(typeName)) { @@ -533,7 +605,7 @@ public class GraphQLSchemaProvider { } } else { fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField() - .type((GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getValueTypeId())) + .type((GraphQLInputType) UnomiToGraphQLConverter.convertPropertyType(propertyType.getTypeId())) .name(propertyName) .build()); } @@ -578,9 +650,9 @@ public class GraphQLSchemaProvider { } // now add all unomi defined event types - final Collection<EventType> unomiEventTypes = eventTypeRegistry.getAll(); + final List<JSONSchema> unomiEventTypes = schemaRegistry.getTargetSchemas("events"); unomiEventTypes.forEach(eventType -> { - final String typeName = UnomiToGraphQLConverter.convertEventType(eventType.getType()); + final String typeName = UnomiToGraphQLConverter.convertEventType(eventType.getSchemaId()); final GraphQLInputType eventInputType = (GraphQLInputType) getFromTypeRegistry(typeName + "Input"); if (eventInputType == null) { logger.warn("Couldn't find event input type {}", typeName + "Input, will not add it as a field."); @@ -740,15 +812,15 @@ public class GraphQLSchemaProvider { .getGraphQLType(annotatedClass, graphQLAnnotations.getContainer(), false); } - public static Builder create(final ProfileService profileService, final EventTypeRegistry eventTypeRegistry) { - return new Builder(profileService, eventTypeRegistry); + public static Builder create(final ProfileService profileService, final SchemaRegistry schemaRegistry) { + return new Builder(profileService, schemaRegistry); } static class Builder { final ProfileService profileService; - final EventTypeRegistry eventTypeRegistry; + final SchemaRegistry schemaRegistry; List<GraphQLTypeFunctionProvider> typeFunctionProviders; @@ -768,9 +840,9 @@ public class GraphQLSchemaProvider { UnomiEventPublisher eventPublisher; - private Builder(final ProfileService profileService, final EventTypeRegistry eventTypeRegistry) { + private Builder(final ProfileService profileService, final SchemaRegistry schemaRegistry) { this.profileService = profileService; - this.eventTypeRegistry = eventTypeRegistry; + this.schemaRegistry = schemaRegistry; } public Builder typeFunctionProviders(List<GraphQLTypeFunctionProvider> typeFunctionProviders) { diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java index af5d992..24fb973 100644 --- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java +++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/GraphQLSchemaUpdater.java @@ -20,8 +20,8 @@ import graphql.GraphQL; import graphql.execution.SubscriptionExecutionStrategy; import graphql.schema.GraphQLCodeRegistry; import graphql.schema.GraphQLSchema; -import org.apache.unomi.api.services.EventTypeRegistry; import org.apache.unomi.api.services.ProfileService; +import org.apache.unomi.api.services.SchemaRegistry; import org.apache.unomi.graphql.fetchers.event.UnomiEventPublisher; import org.apache.unomi.graphql.providers.GraphQLAdditionalTypesProvider; import org.apache.unomi.graphql.providers.GraphQLCodeRegistryProvider; @@ -83,7 +83,7 @@ public class GraphQLSchemaUpdater { private ProfileService profileService; - private EventTypeRegistry eventTypeRegistry; + private SchemaRegistry schemaRegistry; private CDPEventInterfaceRegister eventInterfaceRegister; @@ -131,8 +131,8 @@ public class GraphQLSchemaUpdater { } @Reference - public void setEventTypeRegistry(EventTypeRegistry eventTypeRegistry) { - this.eventTypeRegistry = eventTypeRegistry; + public void setSchemaRegistry(SchemaRegistry schemaRegistry) { + this.schemaRegistry = schemaRegistry; } @Reference @@ -330,7 +330,7 @@ public class GraphQLSchemaUpdater { @SuppressWarnings("unchecked") private GraphQLSchema createGraphQLSchema() { - final GraphQLSchemaProvider schemaProvider = GraphQLSchemaProvider.create(profileService, eventTypeRegistry) + final GraphQLSchemaProvider schemaProvider = GraphQLSchemaProvider.create(profileService, schemaRegistry) .typeFunctionProviders(typeFunctionProviders) .extensionsProviders(extensionsProviders) .additionalTypesProviders(additionalTypesProviders) diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/PropertyFilterUtils.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/PropertyFilterUtils.java index 436193a..49e0741 100644 --- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/PropertyFilterUtils.java +++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/schema/PropertyFilterUtils.java @@ -35,7 +35,7 @@ import java.util.List; public class PropertyFilterUtils { - public static List<GraphQLInputObjectField> buildInputPropertyFilters(final Collection<PropertyType> propertyTypes, final GraphQLAnnotations graphQLAnnotations) { + public static List<GraphQLInputObjectField> buildInputPropertyFilters(final Collection<GraphQLSchemaProvider.DefinitionType> propertyTypes, final GraphQLAnnotations graphQLAnnotations) { if (propertyTypes == null || propertyTypes.isEmpty()) { return Collections.emptyList(); } @@ -47,10 +47,10 @@ public class PropertyFilterUtils { return fieldDefinitions; } - private static void addFilters(final List<GraphQLInputObjectField> fieldDefinitions, final PropertyType propertyType, final GraphQLAnnotations graphQLAnnotations) { - final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getItemId()); + private static void addFilters(final List<GraphQLInputObjectField> fieldDefinitions, final GraphQLSchemaProvider.DefinitionType propertyType, final GraphQLAnnotations graphQLAnnotations) { + final String propertyName = PropertyNameTranslator.translateFromUnomiToGraphQL(propertyType.getName()); - if ("integer".equals(propertyType.getValueTypeId())) { + if ("integer".equals(propertyType.getTypeId())) { fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField() .name(propertyName + "_equals") .type(Scalars.GraphQLInt) @@ -71,7 +71,7 @@ public class PropertyFilterUtils { .name(propertyName + "_gte") .type(Scalars.GraphQLInt) .build()); - } else if ("long".equals(propertyType.getValueTypeId())) { + } else if ("long".equals(propertyType.getTypeId())) { fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField() .name(propertyName + "_equals") .type(Scalars.GraphQLLong) @@ -92,7 +92,7 @@ public class PropertyFilterUtils { .name(propertyName + "_gte") .type(Scalars.GraphQLLong) .build()); - } else if ("float".equals(propertyType.getValueTypeId())) { + } else if ("float".equals(propertyType.getTypeId())) { fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField() .name(propertyName + "_equals") @@ -114,7 +114,7 @@ public class PropertyFilterUtils { .name(propertyName + "_gte") .type(Scalars.GraphQLFloat) .build()); - } else if ("date".equals(propertyType.getValueTypeId())) { + } else if ("date".equals(propertyType.getTypeId())) { fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField() .name(propertyName + "_equals") .type(DateTimeFunction.DATE_TIME_SCALAR) @@ -135,18 +135,18 @@ public class PropertyFilterUtils { .name(propertyName + "_gte") .type(DateTimeFunction.DATE_TIME_SCALAR) .build()); - } else if ("boolean".equals(propertyType.getValueTypeId())) { + } else if ("boolean".equals(propertyType.getTypeId())) { fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField() .name(propertyName + "_equals") .type(Scalars.GraphQLBoolean) .build()); - } else if ("id".equals(propertyType.getValueTypeId())) { + } else if ("id".equals(propertyType.getTypeId())) { fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField() .name(propertyName + "_equals") .type(Scalars.GraphQLString) .build()); - } else if ("set".equals(propertyType.getValueTypeId())) { - if (propertyType.getChildPropertyTypes() != null && !propertyType.getChildPropertyTypes().isEmpty()) { + } else if ("set".equals(propertyType.getTypeId())) { + if (propertyType.hasSubTypes()) { final String typeName = StringUtils.capitalize(propertyName) + "FilterInput"; GraphQLInputObjectType inputObjectType; @@ -156,7 +156,7 @@ public class PropertyFilterUtils { final List<GraphQLInputObjectField> setFieldDefinitions = new ArrayList<>(); - propertyType.getChildPropertyTypes().forEach(childPropertyType -> + propertyType.getSubTypes().forEach(childPropertyType -> addFilters(setFieldDefinitions, childPropertyType, graphQLAnnotations)); dynamicTypeBuilder.fields(setFieldDefinitions); @@ -173,7 +173,7 @@ public class PropertyFilterUtils { .type(inputObjectType) .build()); } - } else if ("geopoint".equals(propertyType.getValueTypeId())) { + } else if ("geopoint".equals(propertyType.getTypeId())) { fieldDefinitions.add(GraphQLInputObjectField.newInputObjectField() .name(propertyName + "_equals") diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java index f766175..fc15ed4 100644 --- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java +++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/resolvers/CDPEventInterfaceResolver.java @@ -18,8 +18,8 @@ package org.apache.unomi.graphql.types.resolvers; import graphql.TypeResolutionEnvironment; import graphql.schema.GraphQLObjectType; -import org.apache.unomi.api.EventType; -import org.apache.unomi.api.services.EventTypeRegistry; +import org.apache.unomi.api.schema.json.JSONSchema; +import org.apache.unomi.api.services.SchemaRegistry; import org.apache.unomi.graphql.converters.UnomiToGraphQLConverter; import org.apache.unomi.graphql.services.ServiceManager; import org.apache.unomi.graphql.types.output.CDPEventInterface; @@ -29,12 +29,12 @@ public class CDPEventInterfaceResolver extends BaseTypeResolver { @Override public GraphQLObjectType getType(TypeResolutionEnvironment env) { final ServiceManager serviceManager = env.getContext(); - final EventTypeRegistry eventTypeRegistry = serviceManager.getService(EventTypeRegistry.class); + SchemaRegistry schemaRegistry = serviceManager.getService(SchemaRegistry.class); final CDPEventInterface eventInterface = env.getObject(); - final EventType eventType = eventTypeRegistry.get(eventInterface.getEvent().getEventType()); - if (eventType != null) { - final String typeName = UnomiToGraphQLConverter.convertEventType(eventType.getType()); + final JSONSchema eventSchema = schemaRegistry.getSchema("https://unomi.apache.org/schemas/json/events/" + eventInterface.getEvent().getEventType() + "/1-0-0"); + if (eventSchema != null) { + final String typeName = UnomiToGraphQLConverter.convertEventType(eventSchema.getSchemaId()); return env.getSchema().getObjectType(typeName); } else { return super.getType(env); 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 2df03c5..469464c 100644 --- a/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java +++ b/itests/src/test/java/org/apache/unomi/itests/ContextServletIT.java @@ -25,10 +25,7 @@ import org.apache.unomi.api.*; import org.apache.unomi.api.conditions.Condition; import org.apache.unomi.api.segments.Scoring; import org.apache.unomi.api.segments.Segment; -import org.apache.unomi.api.services.DefinitionsService; -import org.apache.unomi.api.services.EventService; -import org.apache.unomi.api.services.ProfileService; -import org.apache.unomi.api.services.SegmentService; +import org.apache.unomi.api.services.*; import org.apache.unomi.persistence.spi.CustomObjectMapper; import org.apache.unomi.persistence.spi.PersistenceService; import org.junit.After; @@ -43,6 +40,7 @@ import org.ops4j.pax.exam.util.Filter; import javax.inject.Inject; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.time.LocalDateTime; import java.time.ZoneId; @@ -62,7 +60,10 @@ import static org.junit.Assert.*; public class ContextServletIT extends BaseIT { private final static String CONTEXT_URL = "/cxs/context.json"; private final static String THIRD_PARTY_HEADER_NAME = "X-Unomi-Peer"; - private final static String SEGMENT_EVENT_TYPE = "test-event-type"; + private final static String TEST_EVENT_TYPE = "test-event-type"; + private final static String TEST_EVENT_TYPE_SCHEMA = "test-event-type.json"; + private final static String FLOAT_PROPERTY_EVENT_TYPE = "float-property-type"; + private final static String FLOAT_PROPERTY_EVENT_TYPE_SCHEMA = "float-property-type.json"; private final static String SEGMENT_ID = "test-segment-id"; private final static int SEGMENT_NUMBER_OF_DAYS = 30; @@ -88,11 +89,16 @@ public class ContextServletIT extends BaseIT { @Filter(timeout = 600000) protected SegmentService segmentService; + @Inject + @Filter(timeout = 600000) + protected SchemaRegistry schemaRegistry; + private Profile profile; @Before public void setUp() throws InterruptedException { - this.registerEventType(SEGMENT_EVENT_TYPE); + this.registerEventType(TEST_EVENT_TYPE_SCHEMA); + this.registerEventType(FLOAT_PROPERTY_EVENT_TYPE_SCHEMA); //Create a past-event segment Metadata segmentMetadata = new Metadata(SEGMENT_ID); @@ -101,7 +107,7 @@ public class ContextServletIT extends BaseIT { segmentCondition.setParameter("minimumEventCount", 2); segmentCondition.setParameter("numberOfDays", SEGMENT_NUMBER_OF_DAYS); Condition pastEventEventCondition = new Condition(definitionsService.getConditionType("eventTypeCondition")); - pastEventEventCondition.setParameter("eventTypeId", SEGMENT_EVENT_TYPE); + pastEventEventCondition.setParameter("eventTypeId", TEST_EVENT_TYPE); segmentCondition.setParameter("eventCondition", pastEventEventCondition); segment.setCondition(segmentCondition); segmentService.setSegmentDefinition(segment); @@ -120,38 +126,14 @@ public class ContextServletIT extends BaseIT { TestUtils.removeAllProfiles(definitionsService, persistenceService); profileService.delete(profile.getItemId(), false); segmentService.removeSegmentDefinition(SEGMENT_ID, false); - } - private void registerEventType(final String type) { - final Set<PropertyType> props = new HashSet<>(); - registerEventType(type, props, null, null); + schemaRegistry.unregisterSchema("events", TEST_EVENT_TYPE); + schemaRegistry.unregisterSchema("events", FLOAT_PROPERTY_EVENT_TYPE); } - private void registerEventType(final String type, final Set<PropertyType> properties, final Set<PropertyType> source, final Set<PropertyType> target) { - final Set<PropertyType> typeProps = new HashSet<>(); - if (properties != null) { - PropertyType propertiesPropType = new PropertyType(); - propertiesPropType.setItemId("properties"); - propertiesPropType.setValueTypeId("set"); - propertiesPropType.setChildPropertyTypes(properties); - typeProps.add(propertiesPropType); - } - if (source != null) { - PropertyType sourcePropType = new PropertyType(); - sourcePropType.setItemId("source"); - sourcePropType.setValueTypeId("set"); - sourcePropType.setChildPropertyTypes(source); - typeProps.add(sourcePropType); - } - if (target != null) { - PropertyType targetPropType = new PropertyType(); - targetPropType.setItemId("target"); - targetPropType.setValueTypeId("set"); - targetPropType.setChildPropertyTypes(target); - typeProps.add(targetPropType); - } - final EventType eventType = new EventType(type, typeProps, 1); - eventService.registerEventType(eventType); + private void registerEventType(String jsonSchemaFileName) { + InputStream jsonSchemaInputStream = this.getClass().getClassLoader().getResourceAsStream("schemas/events/" + jsonSchemaFileName); + schemaRegistry.registerSchema("events", jsonSchemaInputStream); } @Test @@ -162,7 +144,7 @@ public class ContextServletIT extends BaseIT { String sessionId = "test-session-id"; String scope = "test-scope"; String eventTypeOriginal = "test-event-type-original"; - String eventTypeUpdated = "test-event-type-updated"; + String eventTypeUpdated = TEST_EVENT_TYPE; Profile profile = new Profile(profileId); Session session = new Session(sessionId, profile, new Date(), scope); Event event = new Event(eventId, eventTypeOriginal, session, profile, scope, null, null, new Date()); @@ -172,8 +154,6 @@ public class ContextServletIT extends BaseIT { Thread.sleep(2000); event.setEventType(eventTypeUpdated); //change the event so we can see the update effect - this.registerEventType(eventTypeUpdated); - //Act ContextRequest contextRequest = new ContextRequest(); contextRequest.setSessionId(session.getItemId()); @@ -199,7 +179,7 @@ public class ContextServletIT extends BaseIT { String sessionId = "test-session-id"; String scope = "test-scope"; String eventTypeOriginal = "test-event-type-original"; - String eventTypeUpdated = "test-event-type-updated"; + String eventTypeUpdated = TEST_EVENT_TYPE; Profile profile = new Profile(profileId); Session session = new Session(sessionId, profile, new Date(), scope); Event event = new Event(eventId, eventTypeOriginal, session, profile, scope, null, null, new Date()); @@ -209,8 +189,6 @@ public class ContextServletIT extends BaseIT { Thread.sleep(2000); event.setEventType(eventTypeUpdated); //change the event so we can see the update effect - this.registerEventType(eventTypeUpdated); - //Act ContextRequest contextRequest = new ContextRequest(); contextRequest.setSessionId(session.getItemId()); @@ -235,7 +213,7 @@ public class ContextServletIT extends BaseIT { String sessionId = "test-session-id"; String scope = "test-scope"; String eventTypeOriginal = "test-event-type-original"; - String eventTypeUpdated = "test-event-type-updated"; + String eventTypeUpdated = TEST_EVENT_TYPE; Session session = new Session(sessionId, profile, new Date(), scope); Event event = new Event(eventId, eventTypeOriginal, session, profile, scope, null, null, new Date()); this.eventService.send(event); @@ -243,8 +221,6 @@ public class ContextServletIT extends BaseIT { Thread.sleep(2000); event.setEventType(eventTypeUpdated); //change the event so we can see the update effect - this.registerEventType(eventTypeUpdated); - //Act ContextRequest contextRequest = new ContextRequest(); contextRequest.setSessionId(session.getItemId()); @@ -267,7 +243,7 @@ public class ContextServletIT extends BaseIT { String sessionId = "test-session-id"; String scope = "test-scope"; Event event = new Event(); - event.setEventType(SEGMENT_EVENT_TYPE); + event.setEventType(TEST_EVENT_TYPE); event.setScope(scope); //Act @@ -298,7 +274,7 @@ public class ContextServletIT extends BaseIT { String sessionId = "test-session-id"; String scope = "test-scope"; Event event = new Event(); - event.setEventType(SEGMENT_EVENT_TYPE); + event.setEventType(TEST_EVENT_TYPE); event.setScope(scope); String regularURI = URL + CONTEXT_URL; long oldTimestamp = LocalDateTime.now(ZoneId.of("UTC")).minusDays(SEGMENT_NUMBER_OF_DAYS + 1).toInstant(ZoneOffset.UTC).toEpochMilli(); @@ -330,7 +306,7 @@ public class ContextServletIT extends BaseIT { String sessionId = "test-session-id"; String scope = "test-scope"; Event event = new Event(); - event.setEventType(SEGMENT_EVENT_TYPE); + event.setEventType(TEST_EVENT_TYPE); event.setScope(scope); String regularURI = URL + CONTEXT_URL; long futureTimestamp = LocalDateTime.now(ZoneId.of("UTC")).plusDays(1).toInstant(ZoneOffset.UTC).toEpochMilli(); @@ -371,8 +347,6 @@ public class ContextServletIT extends BaseIT { contextRequest.setProfileId(profileId); contextRequest.setEvents(Arrays.asList(event)); - this.registerEventType(eventType); - //Act HttpPost request = new HttpPost(URL + CONTEXT_URL); request.addHeader(THIRD_PARTY_HEADER_NAME, UNOMI_KEY); @@ -391,7 +365,7 @@ public class ContextServletIT extends BaseIT { //Arrange String eventId = "valid-event-id-" + System.currentTimeMillis(); String profileId = "valid-profile-id"; - String eventType = "valid-event-type"; + String eventType = FLOAT_PROPERTY_EVENT_TYPE; Event event = new Event(); event.setEventType(eventType); event.setItemId(eventId); @@ -403,13 +377,6 @@ public class ContextServletIT extends BaseIT { contextRequest.setProfileId(profileId); contextRequest.setEvents(Arrays.asList(event)); - final Set<PropertyType> propertiesPropTypes = new HashSet<>(); - PropertyType floatProp = new PropertyType(); - floatProp.setItemId("floatProperty"); - floatProp.setValueTypeId("float"); - propertiesPropTypes.add(floatProp); - this.registerEventType(eventType, propertiesPropTypes, null, null); - //Act HttpPost request = new HttpPost(URL + CONTEXT_URL); request.addHeader(THIRD_PARTY_HEADER_NAME, UNOMI_KEY); @@ -429,7 +396,7 @@ public class ContextServletIT extends BaseIT { //Arrange String eventId = "invalid-event-value-id-" + System.currentTimeMillis(); String profileId = "invalid-profile-id"; - String eventType = "invalid-event-value-type"; + String eventType = FLOAT_PROPERTY_EVENT_TYPE; Event event = new Event(); event.setEventType(eventType); event.setItemId(eventId); @@ -441,13 +408,6 @@ public class ContextServletIT extends BaseIT { contextRequest.setProfileId(profileId); contextRequest.setEvents(Arrays.asList(event)); - final Set<PropertyType> propertiesPropTypes = new HashSet<>(); - PropertyType floatProp = new PropertyType(); - floatProp.setItemId("floatProperty"); - floatProp.setValueTypeId("float"); - propertiesPropTypes.add(floatProp); - this.registerEventType(eventType, propertiesPropTypes, null, null); - //Act HttpPost request = new HttpPost(URL + CONTEXT_URL); request.addHeader(THIRD_PARTY_HEADER_NAME, UNOMI_KEY); @@ -466,7 +426,7 @@ public class ContextServletIT extends BaseIT { //Arrange String eventId = "invalid-event-prop-id-" + System.currentTimeMillis(); String profileId = "invalid-profile-id"; - String eventType = "invalid-event-prop-type"; + String eventType = FLOAT_PROPERTY_EVENT_TYPE; Event event = new Event(); event.setEventType(eventType); event.setItemId(eventId); @@ -478,17 +438,6 @@ public class ContextServletIT extends BaseIT { contextRequest.setProfileId(profileId); contextRequest.setEvents(Arrays.asList(event)); - final Set<PropertyType> propertiesPropTypes = new HashSet<>(); - PropertyType floatProp = new PropertyType(); - floatProp.setItemId("floatProperty"); - floatProp.setValueTypeId("float"); - propertiesPropTypes.add(floatProp); - PropertyType geopointProp = new PropertyType(); - geopointProp.setItemId("geopointProperty"); - geopointProp.setValueTypeId("geopoint"); - propertiesPropTypes.add(geopointProp); - this.registerEventType(eventType, propertiesPropTypes, null, null); - //Act HttpPost request = new HttpPost(URL + CONTEXT_URL); request.addHeader(THIRD_PARTY_HEADER_NAME, UNOMI_KEY); diff --git a/itests/src/test/resources/schemas/events/float-property-type.json b/itests/src/test/resources/schemas/events/float-property-type.json new file mode 100644 index 0000000..a44061e --- /dev/null +++ b/itests/src/test/resources/schemas/events/float-property-type.json @@ -0,0 +1,21 @@ +{ + "$id": "https://unomi.apache.org/schemas/json/events/float-property-type/1-0-0", + "$schema": "https://json-schema.org/draft/2019-09/schema", + "self":{ + "vendor":"org.apache.unomi", + "name":"events/float-property-type", + "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" } + } + } + } +} \ No newline at end of file diff --git a/itests/src/test/resources/schemas/events/test-event-type.json b/itests/src/test/resources/schemas/events/test-event-type.json new file mode 100644 index 0000000..46b56e2 --- /dev/null +++ b/itests/src/test/resources/schemas/events/test-event-type.json @@ -0,0 +1,13 @@ +{ + "$id": "https://unomi.apache.org/schemas/json/events/test-event-type/1-0-0", + "$schema": "https://json-schema.org/draft/2019-09/schema", + "self":{ + "vendor":"org.apache.unomi", + "name":"events/test-event-type", + "format":"jsonschema", + "version":"1-0-0" + }, + "title": "TestEvent", + "type": "object", + "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }] +} \ No newline at end of file diff --git a/rest/src/main/java/org/apache/unomi/rest/endpoints/EventServiceEndpoint.java b/rest/src/main/java/org/apache/unomi/rest/endpoints/EventServiceEndpoint.java index 710ba11..f1bac4d 100644 --- a/rest/src/main/java/org/apache/unomi/rest/endpoints/EventServiceEndpoint.java +++ b/rest/src/main/java/org/apache/unomi/rest/endpoints/EventServiceEndpoint.java @@ -18,7 +18,6 @@ package org.apache.unomi.rest.endpoints; import org.apache.cxf.rs.security.cors.CrossOriginResourceSharing; import org.apache.unomi.api.Event; -import org.apache.unomi.api.EventType; import org.apache.unomi.api.PartialList; import org.apache.unomi.api.query.Query; import org.apache.unomi.api.services.EventService; @@ -91,15 +90,4 @@ public class EventServiceEndpoint { return eventService.getEventTypeIds(); } - /** - * Returns the list of event properties - * @param typeName the type name identifier - * @return a List of EventProperty objects that make up the properties that the server has seen. - */ - @GET - @Path("types/{typeName}") - public EventType getEventType(@PathParam("typeName") String typeName) { - return eventService.getEventType(typeName); - } - } 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 7686797..be5ac44 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 @@ -22,7 +22,6 @@ import inet.ipaddr.IPAddressString; import org.apache.commons.lang3.StringUtils; import org.apache.unomi.api.Event; import org.apache.unomi.api.EventProperty; -import org.apache.unomi.api.EventType; import org.apache.unomi.api.Metadata; import org.apache.unomi.api.PartialList; import org.apache.unomi.api.PropertyType; @@ -64,8 +63,6 @@ public class EventServiceImpl implements EventService { private BundleContext bundleContext; - private EventTypeRegistry eventTypeRegistry; - private SchemaRegistry schemaRegistry; private Set<String> predefinedEventTypeIds = new LinkedHashSet<String>(); @@ -115,10 +112,6 @@ public class EventServiceImpl implements EventService { this.shouldBeCheckedEventSourceId = shouldBeCheckedEventSourceId; } - public void setEventTypeRegistry(EventTypeRegistry eventTypeRegistry) { - this.eventTypeRegistry = eventTypeRegistry; - } - public void setSchemaRegistry(SchemaRegistry schemaRegistry) { this.schemaRegistry = schemaRegistry; } @@ -147,8 +140,7 @@ public class EventServiceImpl implements EventService { } public boolean isEventValid(Event event) { - this.schemaRegistry.isValid(event, "https://unomi.apache.org/schemas/json/events/" + event.getEventType() + ".json"); - return this.eventTypeRegistry.isValid(event); + return this.schemaRegistry.isValid(event, "https://unomi.apache.org/schemas/json/events/" + event.getEventType() + "/1-0-0"); } public String authenticateThirdPartyServer(String key, String ip) { @@ -228,15 +220,6 @@ public class EventServiceImpl implements EventService { } @Override - public EventType getEventType(String typeName) { - return eventTypeRegistry.get(typeName); - } - - public void registerEventType(final EventType eventType) { - eventTypeRegistry.register(eventType); - } - - @Override public List<EventProperty> getEventProperties() { Map<String, Map<String, Object>> mappings = persistenceService.getPropertiesMapping(Event.ITEM_TYPE); List<EventProperty> props = new ArrayList<>(mappings.size()); diff --git a/services/src/main/java/org/apache/unomi/services/impl/events/EventTypeRegistryImpl.java b/services/src/main/java/org/apache/unomi/services/impl/events/EventTypeRegistryImpl.java deleted file mode 100644 index a6327a0..0000000 --- a/services/src/main/java/org/apache/unomi/services/impl/events/EventTypeRegistryImpl.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * 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.services.impl.events; - -import org.apache.commons.beanutils.PropertyUtils; -import org.apache.unomi.api.*; -import org.apache.unomi.api.services.EventTypeRegistry; -import org.apache.unomi.persistence.spi.CustomObjectMapper; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleEvent; -import org.osgi.framework.SynchronousBundleListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.beans.PropertyDescriptor; -import java.lang.reflect.InvocationTargetException; -import java.net.URL; -import java.util.*; - -public class EventTypeRegistryImpl implements EventTypeRegistry, SynchronousBundleListener { - - private static final Logger logger = LoggerFactory.getLogger(EventTypeRegistryImpl.class.getName()); - - private final Map<Long, List<EventType>> eventTypesByBundle = new HashMap<>(); - - private final Map<String, EventType> eventTypesById = new LinkedHashMap<>(); - - private BundleContext bundleContext; - - public void bundleChanged(BundleEvent event) { - switch (event.getType()) { - case BundleEvent.STARTED: - processBundleStartup(event.getBundle().getBundleContext()); - break; - case BundleEvent.STOPPING: - processBundleStop(event.getBundle().getBundleContext()); - break; - } - } - - public void init() { - processBundleStartup(bundleContext); - - // process already started bundles - for (Bundle bundle : bundleContext.getBundles()) { - if (bundle.getBundleContext() != null && bundle.getBundleId() != bundleContext.getBundle().getBundleId()) { - processBundleStartup(bundle.getBundleContext()); - } - } - - bundleContext.addBundleListener(this); - logger.info("Event registry initialized."); - } - - public void destroy() { - bundleContext.removeBundleListener(this); - logger.info("Event registry shutdown."); - } - - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } - - public EventType get(String typeName) { - return eventTypesById.get(typeName); - } - - public void register(EventType eventType) { - eventTypesById.put(eventType.getType(), eventType); - } - - @Override - public boolean isValid(Event event) { - if (event == null) { - return false; - } - final EventType eventType = this.get(event.getEventType()); - if (eventType == null) { - return false; - } - - Set<PropertyType> propertiesPropertyTypes = findChildPropertyTypesById("properties", eventType.getPropertyTypes()); - Set<PropertyType> sourcePropertyTypes = findChildPropertyTypesById("source", eventType.getPropertyTypes()); - Set<PropertyType> targetPropertyTypes = findChildPropertyTypesById("target", eventType.getPropertyTypes()); - - return areObjectPropertiesValid(event.getProperties(), propertiesPropertyTypes) && - areObjectPropertiesValid(event.getSource(), sourcePropertyTypes) && - areObjectPropertiesValid(event.getTarget(), targetPropertyTypes); - } - - /** - * Checks that all properties from map are defined in the property type set. - * Does not require all defined properties to be present in map. - * - * @param props map of properties to validate - * @param types set of a predefined event type properties - * @return boolean result of validation - */ - private boolean areMapPropertiesValid(Map<Object, Object> props, Set<PropertyType> types) { - if (props == null || props.isEmpty() || types == null || types.isEmpty()) { - return true; - } - return props.entrySet().stream().allMatch(entry -> { - return types.stream().anyMatch(type -> { - if (!type.getItemId().equals(entry.getKey().toString())) { - return false; - } - final Set<PropertyType> childTypes = type.getChildPropertyTypes(); - if (childTypes.size() > 0 && entry.getValue() != null) { - try { - return areObjectPropertiesValid(entry.getValue(), childTypes); - } catch (ClassCastException e) { - logger.error("Event property '{}' value is invalid: {}", entry.getKey(), e.getCause()); - return false; - } - } else { - boolean valueTypeValid = testValueType(entry.getValue(), type.getValueTypeId()); - if (!valueTypeValid) { - logger.warn("Event type validation error: value type for property {} is not valid", entry.getKey().toString()); - } - return valueTypeValid; - } - }); - }); - } - - private boolean areObjectPropertiesValid(Object object, Set<PropertyType> types) { - if (object == null) { - return true; - } - if (object instanceof Map) { - return areMapPropertiesValid((Map<Object,Object>) object, types); - } - PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(object); - return Arrays.stream(propertyDescriptors).allMatch(propertyDescriptor -> { - PropertyType propertyType = findPropertyTypeById(propertyDescriptor.getName(), types); - if (propertyType == null) { - logger.warn("Event type validation error: couldn't find property type for property {}", propertyDescriptor.getName()); - return false; - } - if ("set".equals(propertyType.getValueTypeId())) { - boolean setPropertiesValid = false; - try { - setPropertiesValid = areObjectPropertiesValid(PropertyUtils.getProperty(object, propertyDescriptor.getName()), propertyType.getChildPropertyTypes()); - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - logger.error("Error accessing property {} on object {}: {}", propertyDescriptor.getName(), object.toString(), e); - return false; - } - if (!setPropertiesValid) { - logger.warn("Event type validation error: set property for property {} are not valid", propertyDescriptor.getName()); - return false; - } - } - return true; - }); - } - - private Set<PropertyType> findChildPropertyTypesById(String id, Set<PropertyType> types) { - PropertyType propertyType = findPropertyTypeById(id, types); - if (propertyType == null) { - return new HashSet<>(); - } else { - return propertyType.getChildPropertyTypes(); - } - } - - private PropertyType findPropertyTypeById(String id, Set<PropertyType> types) { - Optional<PropertyType> optionalPropertyType = types.stream().filter(propertyType -> propertyType.getItemId().equals(id)).findFirst(); - return optionalPropertyType.orElse(null); - - } - - private boolean testValueType(final Object value, final String valueTypeId) { - switch (valueTypeId) { - case "integer": - return value instanceof Integer; - case "long": - return value instanceof Long; - case "float": - return value instanceof Double; - case "set": - case "json": - return value instanceof Map; - case "geopoint": - return value instanceof GeoPoint; - case "date": - return value instanceof Date; - case "boolean": - return value instanceof Boolean; - case "id": - case "string": - return value instanceof String; - default: - // return true if type is unknown cuz it may be custom - return true; - } - } - - public Collection<EventType> getAll() { - return this.eventTypesById.values(); - } - - private void loadPredefinedEventTypes(BundleContext bundleContext) { - Enumeration<URL> predefinedEventTypes = bundleContext.getBundle().findEntries("META-INF/cxs/events", "*.json", true); - if (predefinedEventTypes == null) { - return; - } - List<EventType> bundleEventTypes = this.eventTypesByBundle.get(bundleContext.getBundle().getBundleId()); - - while (predefinedEventTypes.hasMoreElements()) { - URL predefinedEventTypeURL = predefinedEventTypes.nextElement(); - logger.debug("Found predefined event type at " + predefinedEventTypeURL + ", loading... "); - - try { - EventType eventType = CustomObjectMapper.getObjectMapper().readValue(predefinedEventTypeURL, EventType.class); - eventType.setPluginId(bundleContext.getBundle().getBundleId()); - register(eventType); - bundleEventTypes.add(eventType); - } catch (Exception e) { - logger.error("Error while loading event type definition " + predefinedEventTypeURL, e); - } - } - - } - - private void processBundleStartup(BundleContext bundleContext) { - if (bundleContext == null) { - return; - } - eventTypesByBundle.put(bundleContext.getBundle().getBundleId(), new ArrayList<>()); - loadPredefinedEventTypes(bundleContext); - } - - private void processBundleStop(BundleContext bundleContext) { - if (bundleContext == null) { - return; - } - List<EventType> eventTypes = eventTypesByBundle.remove(bundleContext.getBundle().getBundleId()); - if (eventTypes != null) { - for (EventType eventType : eventTypes) { - eventTypesById.remove(eventType.getType()); - } - } - } -} diff --git a/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java b/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java index 3e93519..289bdec 100644 --- a/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java +++ b/services/src/main/java/org/apache/unomi/services/impl/schemas/SchemaRegistryImpl.java @@ -17,12 +17,14 @@ package org.apache.unomi.services.impl.schemas; +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.lang3.StringUtils; -import org.apache.unomi.api.SchemaType; +import org.apache.unomi.api.schema.json.JSONSchema; +import org.apache.unomi.api.schema.json.JSONTypeFactory; import org.apache.unomi.api.services.ProfileService; import org.apache.unomi.api.services.SchemaRegistry; import org.apache.unomi.persistence.spi.CustomObjectMapper; @@ -44,8 +46,8 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList private static final Logger logger = LoggerFactory.getLogger(SchemaRegistryImpl.class.getName()); - private final Map<Long, List<SchemaType>> schemaTypesByBundle = new HashMap<>(); - private final Map<String, SchemaType> schemaTypesById = new HashMap<>(); + private final Map<Long, List<JSONSchema>> schemaTypesByBundle = new HashMap<>(); + private final Map<String, JSONSchema> schemaTypesById = new HashMap<>(); private final Map<String, JsonSchema> jsonSchemasById = new LinkedHashMap<>(); @@ -55,6 +57,8 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList private ProfileService profileService; + private JsonSchemaFactory jsonSchemaFactory; + ObjectMapper objectMapper = new ObjectMapper(); public void bundleChanged(BundleEvent event) { @@ -69,6 +73,14 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList } public void init() { + + JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder(URI, JsonMetaSchema.getV201909()) + .addKeyword(new PropertyTypeKeyword(profileService, this)).build(); + jsonSchemaFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)) + .addMetaSchema(jsonMetaSchema) + .defaultMetaSchemaURI(URI) + .uriFetcher(getBundleUriFetcher(bundleContext), "https", "http").build(); + processBundleStartup(bundleContext); // process already started bundles @@ -112,12 +124,12 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList } @Override - public List<SchemaType> getTargetSchemas(String target) { - return schemaTypesById.values().stream().filter(schemaType -> schemaType.getTarget().equals(target)).collect(Collectors.toList()); + public List<JSONSchema> getTargetSchemas(String target) { + return schemaTypesById.values().stream().filter(jsonSchema -> jsonSchema.getTarget() != null && jsonSchema.getTarget().equals(target)).collect(Collectors.toList()); } @Override - public SchemaType getSchema(String schemaId) { + public JSONSchema getSchema(String schemaId) { return schemaTypesById.get(schemaId); } @@ -127,37 +139,23 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList return; } - List<SchemaType> schemaTypes = this.schemaTypesByBundle.get(bundleContext.getBundle().getBundleId()); + List<JSONSchema> jsonSchemas = this.schemaTypesByBundle.get(bundleContext.getBundle().getBundleId()); while (predefinedSchemas.hasMoreElements()) { URL predefinedSchemaURL = predefinedSchemas.nextElement(); logger.debug("Found predefined JSON schema at " + predefinedSchemaURL + ", loading... "); - JsonMetaSchema jsonMetaSchema = JsonMetaSchema.builder(URI, JsonMetaSchema.getV201909()) - .addKeyword(new PropertyTypeKeyword(profileService, this)).build(); - JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.builder(JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V201909)) - .addMetaSchema(jsonMetaSchema) - .defaultMetaSchemaURI(URI) - .uriFetcher(getBundleUriFetcher(bundleContext), "https", "http").build(); try (InputStream schemaInputStream = predefinedSchemaURL.openStream()) { JsonSchema jsonSchema = jsonSchemaFactory.getSchema(schemaInputStream); - String schemaId = jsonSchema.getSchemaNode().get("$id").asText(); - jsonSchemasById.put(schemaId, jsonSchema); - bundleIdBySchemaId.put(schemaId, bundleContext.getBundle().getBundleId()); - SchemaType schemaType = new SchemaType(); - schemaType.setPluginId(bundleContext.getBundle().getBundleId()); - schemaType.setSchemaId(schemaId); - Map<String, Object> schemaTree = (Map<String, Object>) objectMapper.treeToValue(jsonSchema.getSchemaNode(), Map.class); - schemaType.setSchemaTree(schemaTree); + String schemaTarget = null; String[] splitPath = predefinedSchemaURL.getPath().split("/"); if (splitPath.length > 5) { String target = splitPath[4]; if (StringUtils.isNotBlank(target)) { - schemaType.setTarget(target); + schemaTarget = target; } } - schemaTypes.add(schemaType); - schemaTypesById.put(schemaId, schemaType); + registerSchema(bundleContext.getBundle().getBundleId(), jsonSchemas, schemaTarget, jsonSchema); } catch (Exception e) { logger.error("Error while loading schema definition " + predefinedSchemaURL, e); } @@ -165,6 +163,40 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList } + public String registerSchema(String target, InputStream jsonSchemaInputStream) { + JsonSchema jsonSchema = jsonSchemaFactory.getSchema(jsonSchemaInputStream); + try { + return registerSchema(null, null, target, jsonSchema); + } catch (JsonProcessingException e) { + logger.error("Error registering JSON schema", e); + return null; + } + } + + public boolean unregisterSchema(String target, String schemaId) { + jsonSchemasById.remove(schemaId); + schemaTypesById.remove(schemaId); + return true; + } + + private String registerSchema(Long bundleId, List<JSONSchema> jsonSchemas, String target, JsonSchema jsonSchema) throws JsonProcessingException { + String schemaId = jsonSchema.getSchemaNode().get("$id").asText(); + jsonSchemasById.put(schemaId, jsonSchema); + if (bundleContext != null) { + bundleIdBySchemaId.put(schemaId, bundleId); + } + Map<String, Object> schemaTree = (Map<String, Object>) objectMapper.treeToValue(jsonSchema.getSchemaNode(), Map.class); + JSONSchema unomiJsonSchema = new JSONSchema(schemaTree, new JSONTypeFactory(this), this); + unomiJsonSchema.setPluginId(bundleId); + unomiJsonSchema.setSchemaId(schemaId); + unomiJsonSchema.setTarget(target); + if (jsonSchemas != null) { + jsonSchemas.add(unomiJsonSchema); + } + schemaTypesById.put(schemaId, unomiJsonSchema); + return schemaId; + } + private URIFetcher getBundleUriFetcher(BundleContext bundleContext) { return uri -> { logger.debug("Fetching schema {}", uri); @@ -196,12 +228,12 @@ public class SchemaRegistryImpl implements SchemaRegistry, SynchronousBundleList if (bundleContext == null) { return; } - List<SchemaType> schemaTypes = schemaTypesByBundle.remove(bundleContext.getBundle().getBundleId()); - if (schemaTypes != null) { - for (SchemaType schemaType : schemaTypes) { - jsonSchemasById.remove(schemaType.getSchemaId()); - bundleIdBySchemaId.remove(schemaType.getSchemaId()); - schemaTypesById.remove(schemaType.getSchemaId()); + List<JSONSchema> JSONSchemas = schemaTypesByBundle.remove(bundleContext.getBundle().getBundleId()); + if (JSONSchemas != null) { + for (JSONSchema JSONSchema : JSONSchemas) { + jsonSchemasById.remove(JSONSchema.getSchemaId()); + bundleIdBySchemaId.remove(JSONSchema.getSchemaId()); + schemaTypesById.remove(JSONSchema.getSchemaId()); } } } diff --git a/services/src/main/resources/META-INF/cxs/schemas/condition.json b/services/src/main/resources/META-INF/cxs/schemas/condition.json index 000ee1d..71dbe42 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/condition.json +++ b/services/src/main/resources/META-INF/cxs/schemas/condition.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/condition.json", + "$id": "https://unomi.apache.org/schemas/json/condition/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Condition", "type": "object", diff --git a/services/src/main/resources/META-INF/cxs/schemas/conditiontype.json b/services/src/main/resources/META-INF/cxs/schemas/conditiontype.json index 85e78c8..22e1ad0 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/conditiontype.json +++ b/services/src/main/resources/META-INF/cxs/schemas/conditiontype.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/conditiontype.json", + "$id": "https://unomi.apache.org/schemas/json/conditiontype/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "ConditionType", "type": "object", @@ -11,11 +11,11 @@ "type" : "string" }, "parentCondition" : { - "$ref" : "https://unomi.apache.org/schemas/json/condition.json" + "$ref" : "https://unomi.apache.org/schemas/json/condition/1-0-0" }, "parameters" : { "type" : "object", - "additionalProperties": { "$ref" : "https://unomi.apache.org/schemas/json/parameter.json" }, + "additionalProperties": { "$ref" : "https://unomi.apache.org/schemas/json/parameter/1-0-0" }, "maxProperties": 50 } } diff --git a/services/src/main/resources/META-INF/cxs/schemas/consent.json b/services/src/main/resources/META-INF/cxs/schemas/consent.json index c1eb229..bb357fe 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/consent.json +++ b/services/src/main/resources/META-INF/cxs/schemas/consent.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/consent.json", + "$id": "https://unomi.apache.org/schemas/json/consent/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Consent", "type": "object", diff --git a/services/src/main/resources/META-INF/cxs/schemas/consentType.json b/services/src/main/resources/META-INF/cxs/schemas/consentType.json index 19f4bef..034a531 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/consentType.json +++ b/services/src/main/resources/META-INF/cxs/schemas/consentType.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/consentType.json", + "$id": "https://unomi.apache.org/schemas/json/consentType/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "ConsentType", "type": "object", diff --git a/services/src/main/resources/META-INF/cxs/schemas/customitem.json b/services/src/main/resources/META-INF/cxs/schemas/customitem.json index 0c59480..3ae685a 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/customitem.json +++ b/services/src/main/resources/META-INF/cxs/schemas/customitem.json @@ -1,11 +1,11 @@ { - "$id": "https://unomi.apache.org/schemas/json/customitem.json", + "$id": "https://unomi.apache.org/schemas/json/customitem/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "CustomItem", "type": "object", "allOf": [ { - "$ref": "https://unomi.apache.org/schemas/json/item.json" + "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0" } ], "properties": { diff --git a/services/src/main/resources/META-INF/cxs/schemas/customitems/page.json b/services/src/main/resources/META-INF/cxs/schemas/customitems/page.json index f05ccb6..fb2874f 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/customitems/page.json +++ b/services/src/main/resources/META-INF/cxs/schemas/customitems/page.json @@ -1,11 +1,18 @@ { - "$id": "https://unomi.apache.org/schemas/json/customitems/page.json", + "$id": "https://unomi.apache.org/schemas/json/customitems/page/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", + "self":{ + "vendor":"org.apache.unomi", + "target" : "customitems", + "name":"page", + "format":"jsonschema", + "version":"1-0-0" + }, "title": "PageCustomItem", "type": "object", "allOf": [ { - "$ref": "https://unomi.apache.org/schemas/json/customitem.json" + "$ref": "https://unomi.apache.org/schemas/json/customitem/1-0-0" } ], "properties": { @@ -59,7 +66,7 @@ "consentTypes": { "type" : ["null", "array"], "items" : { - "$href" : "https://unomi.apache.org/schemas/json/consentType.json" + "$href" : "https://unomi.apache.org/schemas/json/consentType/1-0-0" } } } diff --git a/services/src/main/resources/META-INF/cxs/schemas/customitems/site.json b/services/src/main/resources/META-INF/cxs/schemas/customitems/site.json index b6de454..2d67e75 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/customitems/site.json +++ b/services/src/main/resources/META-INF/cxs/schemas/customitems/site.json @@ -1,11 +1,18 @@ { - "$id": "https://unomi.apache.org/schemas/json/customitems/site.json", + "$id": "https://unomi.apache.org/schemas/json/customitems/site/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", + "self":{ + "vendor":"org.apache.unomi", + "target" : "customitems", + "name": "site", + "format":"jsonschema", + "version":"1-0-0" + }, "title": "SiteCustomItem", "type": "object", "allOf": [ { - "$ref": "https://unomi.apache.org/schemas/json/customitem.json" + "$ref": "https://unomi.apache.org/schemas/json/customitem/1-0-0" } ], "properties": { 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 1b4a03e..66cb8ad 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/event.json +++ b/services/src/main/resources/META-INF/cxs/schemas/event.json @@ -1,9 +1,9 @@ { - "$id": "https://unomi.apache.org/schemas/json/event.json", + "$id": "https://unomi.apache.org/schemas/json/event/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Event", "type": "object", - "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/timestampeditem.json" }], + "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/timestampeditem/1-0-0" }], "properties" : { "eventType" : { "type" : "string", diff --git a/services/src/main/resources/META-INF/cxs/schemas/events/modifyConsent.json b/services/src/main/resources/META-INF/cxs/schemas/events/modifyConsent.json index e203d47..1f748e0 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/events/modifyConsent.json +++ b/services/src/main/resources/META-INF/cxs/schemas/events/modifyConsent.json @@ -1,20 +1,30 @@ { - "$id": "https://unomi.apache.org/schemas/json/events/modifyConsent.json", + "$id": "https://unomi.apache.org/schemas/json/events/modifyConsent/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", + "self":{ + "vendor":"org.apache.unomi", + "target" : "events", + "name": "modifyConsent", + "format":"jsonschema", + "version":"1-0-0" + }, "title": "ModifyConsentEvent", "type": "object", - "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event.json" }], + "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }], "properties" : { "properties" : { - "consent" : { - "$ref" : "https://unomi.apache.org/schemas/json/consent.json" + "type" : "object", + "properties" : { + "consent" : { + "$ref" : "https://unomi.apache.org/schemas/json/consent/1-0-0" + } } }, "source" : { - "$ref" : "https://unomi.apache.org/schemas/json/customitems/page.json" + "$ref" : "https://unomi.apache.org/schemas/json/customitems/page/1-0-0" }, "target" : { - "$ref" : "https://unomi.apache.org/schemas/json/customitem.json" + "$ref" : "https://unomi.apache.org/schemas/json/customitem/1-0-0" } } } \ No newline at end of file diff --git a/services/src/main/resources/META-INF/cxs/schemas/events/view.json b/services/src/main/resources/META-INF/cxs/schemas/events/view.json index 5ea14a9..a85188a 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/events/view.json +++ b/services/src/main/resources/META-INF/cxs/schemas/events/view.json @@ -1,20 +1,27 @@ { - "$id": "https://unomi.apache.org/schemas/json/events/view.json", + "$id": "https://unomi.apache.org/schemas/json/events/view/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", + "self":{ + "vendor":"org.apache.unomi", + "target" : "events", + "name": "view", + "format":"jsonschema", + "version":"1-0-0" + }, "title": "ViewEvent", "type": "object", - "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event.json" }], + "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/event/1-0-0" }], "properties" : { "properties" : { "type" : "object", - "propertyTypes" : [ "events" ], + "unomiPropertyTypes" : [ "events" ], "maxProperties": 50 }, "source" : { - "$ref" : "https://unomi.apache.org/schemas/json/customitems/site.json" + "$ref" : "https://unomi.apache.org/schemas/json/customitems/site/1-0-0" }, "target" : { - "$ref" : "https://unomi.apache.org/schemas/json/customitems/page.json" + "$ref" : "https://unomi.apache.org/schemas/json/customitems/page/1-0-0" } } } \ No newline at end of file diff --git a/services/src/main/resources/META-INF/cxs/schemas/goal.json b/services/src/main/resources/META-INF/cxs/schemas/goal.json index ee7c715..57d922b 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/goal.json +++ b/services/src/main/resources/META-INF/cxs/schemas/goal.json @@ -1,15 +1,15 @@ { - "$id": "https://unomi.apache.org/schemas/json/goal.json", + "$id": "https://unomi.apache.org/schemas/json/goal/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Goal", "type": "object", - "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/metadataitem.json" }], + "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/metadataitem/1-0-0" }], "properties" : { "startEvent" : { - "$ref" : "https://unomi.apache.org/schemas/json/condition.json" + "$ref" : "https://unomi.apache.org/schemas/json/condition/1-0-0" }, "targetEvent" : { - "$ref" : "https://unomi.apache.org/schemas/json/condition.json" + "$ref" : "https://unomi.apache.org/schemas/json/condition/1-0-0" }, "campaignId" : { "type" : "string" diff --git a/services/src/main/resources/META-INF/cxs/schemas/item.json b/services/src/main/resources/META-INF/cxs/schemas/item.json index b4d9f8a..400b144 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/item.json +++ b/services/src/main/resources/META-INF/cxs/schemas/item.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/item.json", + "$id": "https://unomi.apache.org/schemas/json/item/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Item", "type": "object", diff --git a/services/src/main/resources/META-INF/cxs/schemas/metadata.json b/services/src/main/resources/META-INF/cxs/schemas/metadata.json index 2116bba..03d4f71 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/metadata.json +++ b/services/src/main/resources/META-INF/cxs/schemas/metadata.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/metadata.json", + "$id": "https://unomi.apache.org/schemas/json/metadata/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Metadata", "type": "object", diff --git a/services/src/main/resources/META-INF/cxs/schemas/metadataitem.json b/services/src/main/resources/META-INF/cxs/schemas/metadataitem.json index 325dafe..fcdbe1c 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/metadataitem.json +++ b/services/src/main/resources/META-INF/cxs/schemas/metadataitem.json @@ -1,14 +1,14 @@ { - "$id": "https://unomi.apache.org/schemas/json/metadataitem.json", + "$id": "https://unomi.apache.org/schemas/json/metadataitem/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "MetadataItem", "type": "object", "allOf": [ - { "$ref": "https://unomi.apache.org/schemas/json/item.json" } + { "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0" } ], "properties" : { "metadata" : { - "$ref" : "https://unomi.apache.org/schemas/json/metadata.json" + "$ref" : "https://unomi.apache.org/schemas/json/metadata/1-0-0" } } } \ No newline at end of file diff --git a/services/src/main/resources/META-INF/cxs/schemas/parameter.json b/services/src/main/resources/META-INF/cxs/schemas/parameter.json index abea6ae..cba8c6d 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/parameter.json +++ b/services/src/main/resources/META-INF/cxs/schemas/parameter.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/parameter.json", + "$id": "https://unomi.apache.org/schemas/json/parameter/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Parameter", "type": "object", diff --git a/services/src/main/resources/META-INF/cxs/schemas/profile.json b/services/src/main/resources/META-INF/cxs/schemas/profile.json index 2381b81..3bf8c81 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/profile.json +++ b/services/src/main/resources/META-INF/cxs/schemas/profile.json @@ -1,11 +1,11 @@ { - "$id": "https://unomi.apache.org/schemas/json/profile.json", + "$id": "https://unomi.apache.org/schemas/json/profile/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Profile", "type": "object", "allOf": [ { - "$ref": "https://unomi.apache.org/schemas/json/item.json" + "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0" } ], "properties": { diff --git a/services/src/main/resources/META-INF/cxs/schemas/session.json b/services/src/main/resources/META-INF/cxs/schemas/session.json index b2534b4..61d6fed 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/session.json +++ b/services/src/main/resources/META-INF/cxs/schemas/session.json @@ -1,11 +1,11 @@ { - "$id": "https://unomi.apache.org/schemas/json/session.json", + "$id": "https://unomi.apache.org/schemas/json/session/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Session", "type": "object", "allOf": [ { - "$ref": "https://unomi.apache.org/schemas/json/timestampeditem.json" + "$ref": "https://unomi.apache.org/schemas/json/timestampeditem/1-0-0" } ], "properties": { @@ -13,7 +13,7 @@ "type" : "string" }, "profile" : { - "$ref" : "https://unomi.apache.org/schemas/json/profile.json" + "$ref" : "https://unomi.apache.org/schemas/json/profile/1-0-0" }, "properties" : { "type" : "object", 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 bee6c8f..1d7c6ad 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json +++ b/services/src/main/resources/META-INF/cxs/schemas/timestampeditem.json @@ -1,9 +1,9 @@ { - "$id": "https://unomi.apache.org/schemas/json/timestampeditem.json", + "$id": "https://unomi.apache.org/schemas/json/timestampeditem/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "TimestampedItem", "type": "object", - "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/item.json" }], + "allOf": [{ "$ref": "https://unomi.apache.org/schemas/json/item/1-0-0" }], "properties" : { "timeStamp" : { "type" : ["null","string"], diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/boolean.json b/services/src/main/resources/META-INF/cxs/schemas/values/boolean.json index 8a3ed95..752057b 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/values/boolean.json +++ b/services/src/main/resources/META-INF/cxs/schemas/values/boolean.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/values/boolean.json", + "$id": "https://unomi.apache.org/schemas/json/values/boolean/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Boolean", "type": "boolean" diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/date.json b/services/src/main/resources/META-INF/cxs/schemas/values/date.json index 7a39489..2ad0739 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/values/date.json +++ b/services/src/main/resources/META-INF/cxs/schemas/values/date.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/values/date.json", + "$id": "https://unomi.apache.org/schemas/json/values/date/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Date", "type": "string", diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/email.json b/services/src/main/resources/META-INF/cxs/schemas/values/email.json index 705f2f6..d425eff 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/values/email.json +++ b/services/src/main/resources/META-INF/cxs/schemas/values/email.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/values/email.json", + "$id": "https://unomi.apache.org/schemas/json/values/email/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Email", "type": "string", diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/integer.json b/services/src/main/resources/META-INF/cxs/schemas/values/integer.json index f5cb7b9..b3c68a6 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/values/integer.json +++ b/services/src/main/resources/META-INF/cxs/schemas/values/integer.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/values/integer.json", + "$id": "https://unomi.apache.org/schemas/json/values/integer/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Integer", "type": "integer" diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/long.json b/services/src/main/resources/META-INF/cxs/schemas/values/long.json index 769c78a..9eb7c8d 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/values/long.json +++ b/services/src/main/resources/META-INF/cxs/schemas/values/long.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/values/long.json", + "$id": "https://unomi.apache.org/schemas/json/values/long/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Long", "type": "integer" diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/set.json b/services/src/main/resources/META-INF/cxs/schemas/values/set.json index 34b8611..9f43666 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/values/set.json +++ b/services/src/main/resources/META-INF/cxs/schemas/values/set.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/values/set.json", + "$id": "https://unomi.apache.org/schemas/json/values/set/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "Set", "type": "object", diff --git a/services/src/main/resources/META-INF/cxs/schemas/values/string.json b/services/src/main/resources/META-INF/cxs/schemas/values/string.json index 6d5e0e8..f0b9c30 100644 --- a/services/src/main/resources/META-INF/cxs/schemas/values/string.json +++ b/services/src/main/resources/META-INF/cxs/schemas/values/string.json @@ -1,5 +1,5 @@ { - "$id": "https://unomi.apache.org/schemas/json/values/string.json", + "$id": "https://unomi.apache.org/schemas/json/values/string/1-0-0", "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "String", "type": "string" diff --git a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml index 932b7d1..a8fa903 100644 --- a/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml +++ b/services/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -101,12 +101,6 @@ </interfaces> </service> - <bean id="eventTypeRegistryImpl" class="org.apache.unomi.services.impl.events.EventTypeRegistryImpl" init-method="init" - destroy-method="destroy"> - <property name="bundleContext" ref="blueprintBundleContext"/> - </bean> - <service id="eventTypeRegistry" ref="eventTypeRegistryImpl" interface="org.apache.unomi.api.services.EventTypeRegistry"/> - <bean id="schemaRegistryImpl" class="org.apache.unomi.services.impl.schemas.SchemaRegistryImpl" init-method="init" destroy-method="destroy"> <property name="bundleContext" ref="blueprintBundleContext"/> @@ -119,7 +113,6 @@ <property name="definitionsService" ref="definitionsServiceImpl"/> <property name="sourceService" ref="sourceServiceImpl"/> <property name="bundleContext" ref="blueprintBundleContext"/> - <property name="eventTypeRegistry" ref="eventTypeRegistryImpl"/> <property name="schemaRegistry" ref="schemaRegistryImpl" /> <property name="predefinedEventTypeIds"> <set>
