You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@unomi.apache.org by sh...@apache.org on 2019/05/12 14:44:39 UTC

[unomi] 01/15: UNOMI-180 Implement CXS GraphQL API - Initial framework for CXS GraphQL API. Lots of stuff is just testing, please don't consider it as finalized in any way.

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

shuber pushed a commit to branch UNOMI-180-CXS-GRAPHQLAPI
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit 6676615ef2747602200475168a4e39d13373489f
Author: Serge Huber <sh...@apache.org>
AuthorDate: Thu May 3 12:42:32 2018 +0200

    UNOMI-180 Implement CXS GraphQL API
    - Initial framework for CXS GraphQL API. Lots of stuff is just testing, please don't consider it as finalized in any way.
    
    Signed-off-by: Serge Huber <sh...@apache.org>
---
 graphql/cxs-impl/pom.xml                           |  76 +++++++++
 .../java/org/apache/unomi/graphql/CXSEvent.java    |  59 +++++++
 .../org/apache/unomi/graphql/CXSEventType.java     |  26 +++
 .../java/org/apache/unomi/graphql/CXSGeoPoint.java |  29 ++++
 .../apache/unomi/graphql/CXSGraphQLProvider.java   |  21 +++
 .../org/apache/unomi/graphql/CXSProperties.java    |  28 +++
 .../org/apache/unomi/graphql/CXSPropertyType.java  |  32 ++++
 .../apache/unomi/graphql/CXSProviderManager.java   |  70 ++++++++
 .../graphql/internal/CXSGraphQLProviderImpl.java   | 188 +++++++++++++++++++++
 graphql/karaf-feature/pom.xml                      | 126 ++++++++++++++
 graphql/pom.xml                                    |  44 +++++
 pom.xml                                            |   1 +
 12 files changed, 700 insertions(+)

diff --git a/graphql/cxs-impl/pom.xml b/graphql/cxs-impl/pom.xml
new file mode 100644
index 0000000..ac3123d
--- /dev/null
+++ b/graphql/cxs-impl/pom.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.unomi</groupId>
+        <artifactId>unomi-graphql</artifactId>
+        <version>1.3.0-incubating-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>cxs-graphql-api-impl</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.graphql-java</groupId>
+            <artifactId>graphql-java-servlet</artifactId>
+            <version>${graphql.java.servlet.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.graphql-java</groupId>
+            <artifactId>graphql-java</artifactId>
+            <version>${graphql.java.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.github.graphql-java</groupId>
+            <artifactId>graphql-java-annotations</artifactId>
+            <version>${graphql.java.annotations.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.enterprise</artifactId>
+            <version>6.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+            <version>6.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.ds-annotations</artifactId>
+            <version>1.2.4</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.21</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSEvent.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSEvent.java
new file mode 100644
index 0000000..c278678
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSEvent.java
@@ -0,0 +1,59 @@
+/*
+ * 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.graphql;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class CXSEvent {
+
+    private String id;
+    private String eventType;
+    private long timeStamp;
+    private String subject;
+    private String object;
+    private Map<Object,Object> properties = new LinkedHashMap<>();
+    private CXSGeoPoint location;
+
+    public String getId() {
+        return id;
+    }
+
+    public String getEventType() {
+        return eventType;
+    }
+
+    public long getTimeStamp() {
+        return timeStamp;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public String getObject() {
+        return object;
+    }
+
+    public Map<Object, Object> getProperties() {
+        return properties;
+    }
+
+    public CXSGeoPoint getLocation() {
+        return location;
+    }
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSEventType.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSEventType.java
new file mode 100644
index 0000000..43f04fb
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSEventType.java
@@ -0,0 +1,26 @@
+/*
+ * 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.graphql;
+
+import graphql.annotations.annotationTypes.GraphQLField;
+
+public class CXSEventType {
+
+    @GraphQLField
+    public String id;
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSGeoPoint.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSGeoPoint.java
new file mode 100644
index 0000000..bfa7c24
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSGeoPoint.java
@@ -0,0 +1,29 @@
+/*
+ * 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.graphql;
+
+import graphql.annotations.annotationTypes.GraphQLField;
+
+public class CXSGeoPoint {
+
+    @GraphQLField
+    public double latitude;
+
+    @GraphQLField
+    public double longitude;
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSGraphQLProvider.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSGraphQLProvider.java
new file mode 100644
index 0000000..01f2636
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSGraphQLProvider.java
@@ -0,0 +1,21 @@
+/*
+ * 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.graphql;
+
+public interface CXSGraphQLProvider {
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSProperties.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSProperties.java
new file mode 100644
index 0000000..55a1b3e
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSProperties.java
@@ -0,0 +1,28 @@
+/*
+ * 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.graphql;
+
+import graphql.annotations.annotationTypes.GraphQLField;
+
+public class CXSProperties {
+
+    @GraphQLField
+    public String key;
+
+    @GraphQLField
+    public String value;
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSPropertyType.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSPropertyType.java
new file mode 100644
index 0000000..a55a04b
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSPropertyType.java
@@ -0,0 +1,32 @@
+/*
+ * 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.graphql;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+public class CXSPropertyType {
+
+    private String id;
+    private String name;
+    private int minOccurrences = 0;
+    private int maxOccurrences = 1;
+    private Set<String> tags = new LinkedHashSet<>();
+    private Set<String> systemTags = new LinkedHashSet<>();
+    private boolean personalData = false;
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSProviderManager.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSProviderManager.java
new file mode 100644
index 0000000..a341a9f
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/CXSProviderManager.java
@@ -0,0 +1,70 @@
+/*
+ * 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.graphql;
+
+import graphql.servlet.GraphQLMutationProvider;
+import graphql.servlet.GraphQLQueryProvider;
+import graphql.servlet.GraphQLTypesProvider;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+
+import java.util.Map;
+
+@Component(
+        name="CXSProviderManager",
+        immediate = true
+)
+public class CXSProviderManager {
+
+    @Reference(name = "CXSGraphQLProvider")
+    private CXSGraphQLProvider cxsGraphQLProvider;
+    private ServiceRegistration<?> providerSR;
+    private BundleContext bundleContext;
+
+    @Activate
+    void activate(
+            ComponentContext componentContext,
+            BundleContext bundleContext,
+            Map<String,Object> config) {
+        this.bundleContext = bundleContext;
+    }
+
+    @Deactivate
+    void deactivate(
+            ComponentContext componentContext,
+            BundleContext bundleContext,
+            Map<String,Object> config) {
+    }
+
+    void refreshProviders() {
+        if (providerSR != null) {
+            providerSR.unregister();
+            providerSR = null;
+            providerSR = bundleContext.registerService(new String[] {
+                    GraphQLQueryProvider.class.getName(),
+                    GraphQLTypesProvider.class.getName(),
+                    GraphQLMutationProvider.class.getName()
+            }, cxsGraphQLProvider, null);
+        }
+    }
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CXSGraphQLProviderImpl.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CXSGraphQLProviderImpl.java
new file mode 100644
index 0000000..e451dde
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CXSGraphQLProviderImpl.java
@@ -0,0 +1,188 @@
+/*
+ * 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.graphql.internal;
+
+import graphql.annotations.processor.GraphQLAnnotations;
+import graphql.schema.*;
+import graphql.servlet.GraphQLMutationProvider;
+import graphql.servlet.GraphQLQueryProvider;
+import graphql.servlet.GraphQLTypesProvider;
+import org.apache.unomi.graphql.*;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+
+import java.util.*;
+
+import static graphql.Scalars.*;
+import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
+import static graphql.schema.GraphQLObjectType.newObject;
+
+@Component(
+        name = "CXSGraphQLProvider",
+        immediate = true
+)
+public class CXSGraphQLProviderImpl implements CXSGraphQLProvider, GraphQLQueryProvider, GraphQLTypesProvider, GraphQLMutationProvider {
+
+    private Map<String,GraphQLOutputType> registeredOutputTypes = new TreeMap<>();
+
+    @Activate
+    void activate(
+            ComponentContext cc,
+            BundleContext bc,
+            Map<String,Object> config) {
+
+        registeredOutputTypes.put(CXSGeoPoint.class.getName(), GraphQLAnnotations.object(CXSGeoPoint.class));
+        registeredOutputTypes.put(CXSProperties.class.getName(), GraphQLAnnotations.object(CXSProperties.class));
+        registeredOutputTypes.put(CXSEventType.class.getName(), GraphQLAnnotations.object(CXSEventType.class));
+
+        registeredOutputTypes.put("CXS_Event", buildCXSEventOutputType());
+        registeredOutputTypes.put("CXS_Query", buildCXSQueryOutputType());
+    }
+
+    @Deactivate
+    void deactivate(
+            ComponentContext cc,
+            BundleContext bc,
+            Map<String,Object> config) {
+
+        registeredOutputTypes.clear();
+    }
+
+    @Override
+    public Collection<GraphQLFieldDefinition> getQueries() {
+        List<GraphQLFieldDefinition> fieldDefinitions = new ArrayList<GraphQLFieldDefinition>();
+        fieldDefinitions.add(newFieldDefinition()
+                .type(registeredOutputTypes.get("CXS_Query"))
+                .name("cxs")
+                .description("Root field for all CXS queries")
+                .dataFetcher(new DataFetcher() {
+                    public Object get(DataFetchingEnvironment environment) {
+                        Map<String,Object> map = environment.getContext();
+                        return map.keySet();
+                    }
+                }).build());
+        return fieldDefinitions;
+    }
+
+    @Override
+    public Collection<GraphQLType> getTypes() {
+        return new ArrayList<>();
+    }
+
+    @Override
+    public Collection<GraphQLFieldDefinition> getMutations() {
+        return new ArrayList<>();
+    }
+
+    private GraphQLOutputType buildCXSQueryOutputType() {
+        return newObject()
+                .name("CXS_Query")
+                .description("Root CXS query type")
+                .field(newFieldDefinition()
+                        .type(new GraphQLList(registeredOutputTypes.get(CXSEventType.class.getName())))
+                        .name("getEventTypes")
+                        .description("Retrieves the list of all the declared CXS event types in the Apache Unomi server")
+                )
+                .build();
+    }
+
+
+    private GraphQLOutputType buildCXSEventOutputType() {
+        return newObject()
+                .name("CXS_Event")
+                .description("An event is generated by user interacting with the Context Server")
+                .field(newFieldDefinition()
+                        .type(GraphQLID)
+                        .name("id")
+                        .description("A unique identifier for the event")
+                        .dataFetcher(new DataFetcher() {
+                            public Object get(DataFetchingEnvironment environment) {
+                                CXSEvent CXSEvent = environment.getSource();
+                                return CXSEvent.getId();
+                            }
+                        })
+                )
+                .field(newFieldDefinition()
+                        .type(GraphQLString)
+                        .name("eventType")
+                        .description("An identifier for the event type")
+                        .dataFetcher(new DataFetcher() {
+                            public Object get(DataFetchingEnvironment environment) {
+                                CXSEvent CXSEvent = environment.getSource();
+                                return CXSEvent.getEventType();
+                            }
+                        })
+                )
+                .field(newFieldDefinition()
+                        .type(GraphQLLong)
+                        .name("timestamp")
+                        .description("The difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC.")
+                        .dataFetcher(new DataFetcher() {
+                            public Object get(DataFetchingEnvironment environment) {
+                                CXSEvent CXSEvent = environment.getSource();
+                                return CXSEvent.getTimeStamp();
+                            }
+                        }))
+                .field(newFieldDefinition()
+                        .type(GraphQLString)
+                        .name("subject")
+                        .description("The entity that has fired the event (using the profile)")
+                        .dataFetcher(new DataFetcher() {
+                            public Object get(DataFetchingEnvironment environment) {
+                                CXSEvent CXSEvent = environment.getSource();
+                                return CXSEvent.getSubject();
+                            }
+                        }))
+                .field(newFieldDefinition()
+                        .type(GraphQLString)
+                        .name("object")
+                        .description("The object on which the event was fired.")
+                        .dataFetcher(new DataFetcher() {
+                            public Object get(DataFetchingEnvironment environment) {
+                                CXSEvent CXSEvent = environment.getSource();
+                                return CXSEvent.getObject();
+                            }
+                        })
+                )
+                .field(newFieldDefinition()
+                        .type(registeredOutputTypes.get(CXSGeoPoint.class.getName()))
+                        .name("location")
+                        .description("The geo-point location where the event was fired.")
+                        .dataFetcher(new DataFetcher() {
+                            public Object get(DataFetchingEnvironment environment) {
+                                CXSEvent CXSEvent = environment.getSource();
+                                return CXSEvent.getLocation();
+                            }
+                        })
+                )
+                .field(newFieldDefinition()
+                        .type(new GraphQLList(registeredOutputTypes.get(CXSProperties.class.getName())))
+                        .name("properties")
+                        .description("Generic properties for the event")
+                        .dataFetcher(new DataFetcher() {
+                            public Object get(DataFetchingEnvironment environment) {
+                                CXSEvent CXSEvent = environment.getSource();
+                                return new ArrayList<Map.Entry<Object,Object>>(CXSEvent.getProperties().entrySet());
+                            }
+                        })
+                )
+                .build();
+    }
+}
diff --git a/graphql/karaf-feature/pom.xml b/graphql/karaf-feature/pom.xml
new file mode 100644
index 0000000..011e1eb
--- /dev/null
+++ b/graphql/karaf-feature/pom.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>org.apache.unomi</groupId>
+        <artifactId>unomi-graphql</artifactId>
+        <version>1.3.0-incubating-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>feature</packaging>
+
+    <artifactId>cxs-graphql-feature</artifactId>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.8.4</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <version>2.8.4</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.8.4</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jdk8</artifactId>
+            <version>2.8.4</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>20.0</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+            <version>1.3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr4-runtime</artifactId>
+            <version>4.5.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.graphql-java</groupId>
+            <artifactId>graphql-java-servlet</artifactId>
+            <version>${graphql.java.servlet.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>javax.servlet</groupId>
+                    <artifactId>javax.servlet-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.graphql-java</groupId>
+            <artifactId>graphql-java</artifactId>
+            <version>${graphql.java.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>io.github.graphql-java</groupId>
+            <artifactId>graphql-java-annotations</artifactId>
+            <version>${graphql.java.annotations.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.unomi</groupId>
+                <artifactId>cxs-graphql-api-impl</artifactId>
+            <version>1.3.0-incubating-SNAPSHOT</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.karaf.tooling</groupId>
+                <artifactId>karaf-maven-plugin</artifactId>
+                <version>${version.karaf}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <startLevel>80</startLevel>
+                    <addTransitiveFeatures>true</addTransitiveFeatures>
+                    <includeTransitiveDependency>true</includeTransitiveDependency>
+                </configuration>
+            </plugin>
+        </plugins>
+
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/graphql/pom.xml b/graphql/pom.xml
new file mode 100644
index 0000000..bc03766
--- /dev/null
+++ b/graphql/pom.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.unomi</groupId>
+        <artifactId>unomi-root</artifactId>
+        <version>1.3.0-incubating-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>unomi-graphql</artifactId>
+    <name>Apache Unomi :: GraphQL API</name>
+    <description>Apache Unomi Context GraphQL API</description>
+    <packaging>pom</packaging>
+
+    <properties>
+        <graphql.java.servlet.version>4.7.0</graphql.java.servlet.version>
+        <graphql.java.version>6.0</graphql.java.version>
+        <graphql.java.annotations.version>5.1</graphql.java.annotations.version>
+    </properties>
+
+    <modules>
+        <module>cxs-impl</module>
+        <module>karaf-feature</module>
+    </modules>
+
+</project>
diff --git a/pom.xml b/pom.xml
index 8ba671b..172bb27 100644
--- a/pom.xml
+++ b/pom.xml
@@ -923,6 +923,7 @@
         <module>persistence-elasticsearch</module>
         <module>services</module>
         <module>rest</module>
+        <module>graphql</module>
         <module>wab</module>
         <module>plugins</module>
         <module>extensions</module>