Merge pull request #32 from enonic/UNOMI-293

UNOMI-293: Implement cdp_sessionStateEvent & processing
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/actions/CDPSessionAction.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/actions/CDPSessionAction.java
new file mode 100644
index 0000000..75025f4
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/actions/CDPSessionAction.java
@@ -0,0 +1,93 @@
+/*
+ * 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.actions;
+
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.PartialList;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.api.Session;
+import org.apache.unomi.api.actions.Action;
+import org.apache.unomi.api.actions.ActionExecutor;
+import org.apache.unomi.api.services.EventService;
+import org.apache.unomi.api.services.ProfileService;
+import org.apache.unomi.graphql.types.output.CDPSessionState;
+
+import java.util.Date;
+import java.util.Objects;
+import java.util.Optional;
+
+public class CDPSessionAction implements ActionExecutor {
+
+    private EventService eventService;
+
+    private ProfileService profileService;
+
+    public void setEventService(EventService eventService) {
+        this.eventService = eventService;
+    }
+
+    public void setProfileService(ProfileService profileService) {
+        this.profileService = profileService;
+    }
+
+    @Override
+    public int execute(Action action, Event event) {
+        final CDPSessionState state = CDPSessionState.valueOf((String) event.getProperty("state"));
+        final String sessionId = (String) event.getProperty("sessionId");
+        final String scope = (String) event.getProperty("scope");
+
+        final Profile profile = event.getProfile();
+
+        if (profile == null) {
+            return EventService.NO_CHANGE;
+        }
+
+        if (state == CDPSessionState.START) {
+            final Session session = new Session(sessionId, profile, new Date(), scope);
+            session.setProperty("state", state);
+
+            final Event sessionCreated =
+                    new Event("sessionCreated", session, profile, scope, null, session, event.getTimeStamp());
+
+            int eventCode = eventService.send(sessionCreated);
+
+            profileService.saveSession(session);
+
+            return eventCode;
+        } else {
+            final PartialList<Session> sessionList = profileService.findProfileSessions(profile.getItemId());
+
+            if (sessionList != null) {
+                final Optional<Session> sessionOp = sessionList.getList().stream()
+                        .filter(session -> Objects.equals(session.getItemId(), sessionId) && Objects.equals(session.getScope(), scope))
+                        .findFirst();
+
+                if (sessionOp.isPresent()) {
+                    final Session sessionToUpdate = sessionOp.get();
+
+                    sessionToUpdate.setProperty("state", state);
+                    profileService.saveSession(sessionToUpdate);
+
+                    return EventService.SESSION_UPDATED;
+                }
+            }
+        }
+
+        return EventService.NO_CHANGE;
+    }
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/ProcessEventsCommand.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/ProcessEventsCommand.java
index 33d9517..33ef1ff 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/ProcessEventsCommand.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/ProcessEventsCommand.java
@@ -26,6 +26,7 @@
 import org.apache.unomi.graphql.types.input.CDPEventInput;
 import org.apache.unomi.graphql.types.input.CDPEventProcessor;
 import org.apache.unomi.graphql.types.input.CDPListsUpdateEventInput;
+import org.apache.unomi.graphql.types.input.CDPSessionEventInput;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,6 +56,7 @@
     static {
         STATIC_FIELDS.add(CDPConsentUpdateEventInput.EVENT_NAME);
         STATIC_FIELDS.add(CDPListsUpdateEventInput.EVENT_NAME);
+        STATIC_FIELDS.add(CDPSessionEventInput.EVENT_NAME);
     }
 
     private ProcessEventsCommand(final Builder builder) {
@@ -91,6 +93,7 @@
         final List<CDPEventProcessor> eventProcessors = new ArrayList<>();
         eventProcessors.add(eventInput.getCdp_consentUpdateEvent());
         eventProcessors.add(eventInput.getCdp_listUpdateEvent());
+        eventProcessors.add(eventInput.getCdp_sessionEvent());
 
         eventProcessors.stream()
                 .filter(Objects::nonNull)
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/segments/CreateOrUpdateSegmentCommand.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/segments/CreateOrUpdateSegmentCommand.java
index 0d4a2be..bb70aa0 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/segments/CreateOrUpdateSegmentCommand.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/commands/segments/CreateOrUpdateSegmentCommand.java
@@ -36,6 +36,7 @@
 import org.apache.unomi.graphql.types.input.CDPProfileFilterInput;
 import org.apache.unomi.graphql.types.input.CDPProfilePropertiesFilterInput;
 import org.apache.unomi.graphql.types.input.CDPSegmentInput;
+import org.apache.unomi.graphql.types.input.CDPSessionEventFilterInput;
 import org.apache.unomi.graphql.types.output.CDPSegment;
 import org.apache.unomi.graphql.utils.ConditionBuilder;
 
@@ -417,6 +418,10 @@
             subConditions.add(createCdpConsentUpdateEventCondition(eventFilterInput.getCdp_consentUpdateEvent()));
         }
 
+        if (eventFilterInput.getCdp_sessionEvent() != null) {
+            subConditions.add(createCdpSessionEventCondition(eventFilterInput.getCdp_sessionEvent()));
+        }
+
         createConditionBasedOnFilterWithSubFilters(
                 subConditions, eventFilterInput.getAnd(), this::createEventPropertyCondition, "and");
 
@@ -442,6 +447,33 @@
         return ConditionBuilder.builder(booleanConditionType).buildBooleanCondition("and", subConditions);
     }
 
+    public Condition createCdpSessionEventCondition(final CDPSessionEventFilterInput eventFilterInput) {
+        final List<Condition> subConditions = new ArrayList<>();
+
+        if (eventFilterInput.getState_equals() != null) {
+            subConditions.add(ConditionBuilder.builder(eventPropertyConditionType)
+                    .setPropertyName("properties.state")
+                    .setComparisonOperator("equals")
+                    .setPropertyValue(eventFilterInput.getState_equals().name()).build());
+        }
+
+        if (eventFilterInput.getUnomi_scope_equals() != null) {
+            subConditions.add(ConditionBuilder.builder(eventPropertyConditionType)
+                    .setPropertyName("properties.scope")
+                    .setComparisonOperator("equals")
+                    .setPropertyValue(eventFilterInput.getUnomi_scope_equals()).build());
+        }
+
+        if (eventFilterInput.getUnomi_sessionId_equals() != null) {
+            subConditions.add(ConditionBuilder.builder(eventPropertyConditionType)
+                    .setPropertyName("properties.sessionId")
+                    .setComparisonOperator("equals")
+                    .setPropertyValue(eventFilterInput.getUnomi_sessionId_equals()).build());
+        }
+
+        return ConditionBuilder.builder(booleanConditionType).buildBooleanCondition("and", subConditions);
+    }
+
     final List<Condition> subConditions = new ArrayList<>();
 
     private Condition createProfileEventsCondition(final CDPProfileEventsFilterInput eventsFilterInput) {
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPEventFilterInput.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPEventFilterInput.java
index ad35e9b..3be1aac 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPEventFilterInput.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPEventFilterInput.java
@@ -65,6 +65,9 @@
     @GraphQLField
     private CDPConsentUpdateEventFilterInput cdp_consentUpdateEvent;
 
+    @GraphQLField
+    private CDPSessionEventFilterInput cdp_sessionEvent;
+
     public CDPEventFilterInput(
             final @GraphQLName("and") List<CDPEventFilterInput> and,
             final @GraphQLName("or") List<CDPEventFilterInput> or,
@@ -78,7 +81,8 @@
             final @GraphQLName("cdp_timestamp_gt") OffsetDateTime cdp_timestamp_gt,
             final @GraphQLName("cdp_timestamp_gte") OffsetDateTime cdp_timestamp_gte,
             final @GraphQLName("cdp_consentUpdateEvent") CDPConsentUpdateEventFilterInput cdp_consentUpdateEvent,
-            final @GraphQLName("cdp_listsUpdateEvent") CDPListsUpdateEventFilterInput cdp_listsUpdateEvent) {
+            final @GraphQLName("cdp_listsUpdateEvent") CDPListsUpdateEventFilterInput cdp_listsUpdateEvent,
+            final @GraphQLName("cdp_sessionEvent") CDPSessionEventFilterInput cdp_sessionEvent) {
         this.and = and;
         this.or = or;
         this.id_equals = id_equals;
@@ -92,10 +96,11 @@
         this.cdp_timestamp_gte = cdp_timestamp_gte;
         this.cdp_listsUpdateEvent = cdp_listsUpdateEvent;
         this.cdp_consentUpdateEvent = cdp_consentUpdateEvent;
+        this.cdp_sessionEvent = cdp_sessionEvent;
     }
 
     public static CDPEventFilterInput from(final String cdp_profileID_equals) {
-        return new CDPEventFilterInput(null, null, null, null, null, cdp_profileID_equals, null, null, null, null, null, null, null);
+        return new CDPEventFilterInput(null, null, null, null, null, cdp_profileID_equals, null, null, null, null, null, null, null, null);
     }
 
     public List<CDPEventFilterInput> getAnd() {
@@ -209,4 +214,13 @@
         return this;
     }
 
+
+    public CDPSessionEventFilterInput getCdp_sessionEvent() {
+        return cdp_sessionEvent;
+    }
+
+    public CDPEventFilterInput setCdp_sessionEvent(CDPSessionEventFilterInput cdp_sessionEvent) {
+        this.cdp_sessionEvent = cdp_sessionEvent;
+        return this;
+    }
 }
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPEventInput.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPEventInput.java
index 1126362..a8229d7 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPEventInput.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPEventInput.java
@@ -48,19 +48,24 @@
     @GraphQLField
     private CDPListsUpdateEventInput cdp_listUpdateEvent;
 
+    @GraphQLField
+    private CDPSessionEventInput cdp_sessionEvent;
+
     public CDPEventInput(
             final @GraphQLID @GraphQLName("id") String id,
             final @GraphQLName("cdp_sourceID") String cdp_sourceID,
             final @GraphQLNonNull @GraphQLName("cdp_profileID") CDPProfileIDInput cdp_profileID,
             final @GraphQLID @GraphQLNonNull @GraphQLName("cdp_objectID") String cdp_objectID,
             final @GraphQLName("cdp_consentUpdateEvent") CDPConsentUpdateEventInput cdp_consentUpdateEvent,
-            final @GraphQLName("cdp_listUpdateEvent") CDPListsUpdateEventInput cdp_listUpdateEvent) {
+            final @GraphQLName("cdp_listUpdateEvent") CDPListsUpdateEventInput cdp_listUpdateEvent,
+            final @GraphQLName("cdp_sessionEvent") CDPSessionEventInput cdp_sessionEvent) {
         this.id = id;
         this.cdp_sourceID = cdp_sourceID;
         this.cdp_profileID = cdp_profileID;
         this.cdp_objectID = cdp_objectID;
         this.cdp_consentUpdateEvent = cdp_consentUpdateEvent;
         this.cdp_listUpdateEvent = cdp_listUpdateEvent;
+        this.cdp_sessionEvent = cdp_sessionEvent;
     }
 
     public String getId() {
@@ -112,4 +117,14 @@
         this.cdp_listUpdateEvent = cdp_listUpdateEvent;
         return this;
     }
+
+    public CDPSessionEventInput getCdp_sessionEvent() {
+        return cdp_sessionEvent;
+    }
+
+    public CDPEventInput setCdp_sessionEvent(CDPSessionEventInput cdp_sessionEvent) {
+        this.cdp_sessionEvent = cdp_sessionEvent;
+        return this;
+    }
+
 }
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPSessionEventFilterInput.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPSessionEventFilterInput.java
new file mode 100644
index 0000000..a012848
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPSessionEventFilterInput.java
@@ -0,0 +1,62 @@
+/*
+ * 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.types.input;
+
+import graphql.annotations.annotationTypes.GraphQLField;
+import graphql.annotations.annotationTypes.GraphQLName;
+import org.apache.unomi.graphql.types.output.CDPSessionState;
+
+import static org.apache.unomi.graphql.types.input.CDPSessionEventFilterInput.TYPE_NAME_INTERNAL;
+
+@GraphQLName(TYPE_NAME_INTERNAL)
+public class CDPSessionEventFilterInput {
+
+    public static final String TYPE_NAME_INTERNAL = "CDP_SessionEventFilter";
+
+    public static final String TYPE_NAME = TYPE_NAME_INTERNAL + "Input";
+
+    @GraphQLField
+    private CDPSessionState state_equals;
+
+    @GraphQLField
+    private String unomi_sessionId_equals;
+
+    @GraphQLField
+    private String unomi_scope_equals;
+
+    public CDPSessionEventFilterInput(
+            final @GraphQLName("state_equals") CDPSessionState state_equals,
+            final @GraphQLName("unomi_sessionId_equals") String unomi_sessionId_equals,
+            final @GraphQLName("unomi_scope_equals") String unomi_scope_equals) {
+        this.state_equals = state_equals;
+        this.unomi_sessionId_equals = unomi_sessionId_equals;
+        this.unomi_scope_equals = unomi_scope_equals;
+    }
+
+    public CDPSessionState getState_equals() {
+        return state_equals;
+    }
+
+    public String getUnomi_sessionId_equals() {
+        return unomi_sessionId_equals;
+    }
+
+    public String getUnomi_scope_equals() {
+        return unomi_scope_equals;
+    }
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPSessionEventInput.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPSessionEventInput.java
new file mode 100644
index 0000000..254a147
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/input/CDPSessionEventInput.java
@@ -0,0 +1,90 @@
+/*
+ * 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.types.input;
+
+import graphql.annotations.annotationTypes.GraphQLField;
+import graphql.annotations.annotationTypes.GraphQLName;
+import graphql.schema.DataFetchingEnvironment;
+import org.apache.unomi.api.Event;
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.graphql.types.output.CDPSessionState;
+
+import java.util.LinkedHashMap;
+
+import static org.apache.unomi.graphql.types.input.CDPSessionEventInput.TYPE_NAME_INTERNAL;
+
+@GraphQLName(TYPE_NAME_INTERNAL)
+public class CDPSessionEventInput extends BaseProfileEventProcessor {
+
+    public static final String TYPE_NAME_INTERNAL = "CDP_SessionEvent";
+
+    public static final String TYPE_NAME = TYPE_NAME_INTERNAL + "Input";
+
+    public static final String EVENT_NAME = "cdp_sessionEvent";
+
+    @GraphQLField
+    private CDPSessionState state;
+
+    @GraphQLField
+    private String unomi_sessionId;
+
+    @GraphQLField
+    private String unomi_scope;
+
+    public CDPSessionEventInput(
+            final @GraphQLName("state") CDPSessionState state,
+            final @GraphQLName("unomi_sessionId") String unomi_sessionId,
+            final @GraphQLName("unomi_scope") String unomi_scope) {
+        this.state = state;
+        this.unomi_sessionId = unomi_sessionId;
+        this.unomi_scope = unomi_scope;
+    }
+
+    public CDPSessionState getState() {
+        return state;
+    }
+
+    public String getUnomi_sessionId() {
+        return unomi_sessionId;
+    }
+
+    public String getUnomi_scope() {
+        return unomi_scope;
+    }
+
+    @Override
+    public Event buildEvent(LinkedHashMap<String, Object> eventInputAsMap, DataFetchingEnvironment environment) {
+        final Profile profile = loadProfile(eventInputAsMap, environment);
+
+        if (profile == null) {
+            return null;
+        }
+
+        return eventBuilder(EVENT_NAME, profile)
+                .setPersistent(true)
+                .setProperty("state", state.name())
+                .setProperty("sessionId", unomi_sessionId)
+                .setProperty("scope", unomi_scope)
+                .build();
+    }
+
+    @Override
+    public String getFieldName() {
+        return EVENT_NAME;
+    }
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPEventFilter.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPEventFilter.java
index fb269e1..d28ab7a 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPEventFilter.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPEventFilter.java
@@ -113,6 +113,11 @@
         return new CDPConsentUpdateEventFilter();
     }
 
+    @GraphQLField
+    public CDPSessionEventFilter cdp_sessionEvent(final DataFetchingEnvironment environment) {
+        return new CDPSessionEventFilter();
+    }
+
     private <T> T getValueOrNull(final Condition condition) {
         return getValueOrNull(condition, "propertyValue");
     }
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPEventInterface.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPEventInterface.java
index 8e94b62..d2ec85a 100644
--- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPEventInterface.java
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPEventInterface.java
@@ -42,7 +42,7 @@
     private List<CDPTopic> cdp_topics;
 
     public CDPEventInterface(
-            @GraphQLID @GraphQLNonNull String id,
+            @GraphQLID @GraphQLNonNull @GraphQLName("id") String id,
             @GraphQLName("cdp_source") CDPSource cdp_source,
             @GraphQLName("cdp_client") CDPClient cdp_client,
             @GraphQLNonNull @GraphQLName("cdp_profileID") CDPProfileID cdp_profileID,
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPSessionEvent.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPSessionEvent.java
new file mode 100644
index 0000000..c6b0c63
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPSessionEvent.java
@@ -0,0 +1,62 @@
+/*
+ * 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.types.output;
+
+import graphql.annotations.annotationTypes.GraphQLField;
+import graphql.annotations.annotationTypes.GraphQLID;
+import graphql.annotations.annotationTypes.GraphQLName;
+import graphql.annotations.annotationTypes.GraphQLNonNull;
+
+import java.time.OffsetDateTime;
+import java.util.List;
+
+import static org.apache.unomi.graphql.types.output.CDPSessionEvent.TYPE_NAME;
+
+@GraphQLName(TYPE_NAME)
+public class CDPSessionEvent extends CDPEventInterface {
+
+    public static final String TYPE_NAME = "CDP_SessionEvent";
+
+    @GraphQLField
+    private CDPSessionState state;
+
+    public CDPSessionEvent(
+            final @GraphQLID @GraphQLNonNull @GraphQLName("id") String id,
+            final @GraphQLName("cdp_source") CDPSource cdp_source,
+            final @GraphQLName("cdp_client") CDPClient cdp_client,
+            final @GraphQLNonNull @GraphQLName("cdp_profileID") CDPProfileID cdp_profileID,
+            final @GraphQLNonNull @GraphQLName("cdp_profile") CDPProfile cdp_profile,
+            final @GraphQLNonNull @GraphQLName("cdp_object") CDPObject cdp_object,
+            final @GraphQLName("cdp_location") CDPGeoPoint cdp_location,
+            final @GraphQLName("cdp_timestamp") OffsetDateTime cdp_timestamp,
+            final @GraphQLName("cdp_topics") List<CDPTopic> cdp_topics,
+            final @GraphQLName("state") CDPSessionState state) {
+        super(id, cdp_source, cdp_client, cdp_profileID, cdp_profile, cdp_object, cdp_location, cdp_timestamp, cdp_topics);
+
+        this.state = state;
+    }
+
+    public CDPSessionState getState() {
+        return state;
+    }
+
+    public CDPSessionEvent setState(CDPSessionState state) {
+        this.state = state;
+        return this;
+    }
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPSessionEventFilter.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPSessionEventFilter.java
new file mode 100644
index 0000000..8f37800
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPSessionEventFilter.java
@@ -0,0 +1,65 @@
+/*
+ * 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.types.output;
+
+import graphql.annotations.annotationTypes.GraphQLField;
+import graphql.annotations.annotationTypes.GraphQLName;
+
+import static org.apache.unomi.graphql.types.output.CDPSessionEventFilter.TYPE_NAME;
+
+@GraphQLName(TYPE_NAME)
+public class CDPSessionEventFilter {
+
+    public static final String TYPE_NAME = "CDP_SessionEventFilter";
+
+    @GraphQLField
+    private CDPSessionState state_equals;
+
+    @GraphQLField
+    private String unomi_sessionId_equals;
+
+    @GraphQLField
+    private String unomi_scope_equals;
+
+    public CDPSessionState getState_equals() {
+        return state_equals;
+    }
+
+    public CDPSessionEventFilter setState_equals(CDPSessionState state_equals) {
+        this.state_equals = state_equals;
+        return this;
+    }
+
+    public String getUnomi_sessionId_equals() {
+        return unomi_sessionId_equals;
+    }
+
+    public CDPSessionEventFilter setUnomi_sessionId_equals(String unomi_sessionId_equals) {
+        this.unomi_sessionId_equals = unomi_sessionId_equals;
+        return this;
+    }
+
+    public String getUnomi_scope_equals() {
+        return unomi_scope_equals;
+    }
+
+    public CDPSessionEventFilter setUnomi_scope_equals(String unomi_scope_equals) {
+        this.unomi_scope_equals = unomi_scope_equals;
+        return this;
+    }
+
+}
diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPSessionState.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPSessionState.java
new file mode 100644
index 0000000..c24c30f
--- /dev/null
+++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/types/output/CDPSessionState.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.types.output;
+
+import graphql.annotations.annotationTypes.GraphQLName;
+
+@GraphQLName("CDP_SessionState")
+public enum CDPSessionState {
+
+    START,
+    STOP,
+    PAUSE,
+    RESUME
+
+}
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 ce41cb0..40ef836 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
@@ -21,6 +21,7 @@
 import graphql.schema.TypeResolver;
 import org.apache.unomi.graphql.types.output.CDPConsentUpdateEvent;
 import org.apache.unomi.graphql.types.output.CDPProfileUpdateEvent;
+import org.apache.unomi.graphql.types.output.CDPSessionEvent;
 
 public class CDPEventInterfaceResolver implements TypeResolver {
 
@@ -32,9 +33,11 @@
             return env.getSchema().getObjectType(CDPConsentUpdateEvent.TYPE_NAME);
         } else if (obj instanceof CDPProfileUpdateEvent) {
             return env.getSchema().getObjectType(CDPProfileUpdateEvent.TYPE_NAME);
+        } else if (obj instanceof CDPSessionEvent) {
+            return env.getSchema().getObjectType(CDPSessionEvent.TYPE_NAME);
+        } else {
+            return null;
         }
-
-        return null;
     }
 
 }
diff --git a/graphql/cxs-impl/src/main/resources/META-INF/cxs/actions/cdpSessionEvent.json b/graphql/cxs-impl/src/main/resources/META-INF/cxs/actions/cdpSessionEvent.json
new file mode 100644
index 0000000..835f7ec
--- /dev/null
+++ b/graphql/cxs-impl/src/main/resources/META-INF/cxs/actions/cdpSessionEvent.json
@@ -0,0 +1,31 @@
+{
+  "metadata": {
+    "id": "cdpSessionEventAction",
+    "name": "cdpSessionEventAction",
+    "description": "",
+    "systemTags": [
+      "profileTags",
+      "demographic",
+      "availableToEndUser"
+    ],
+    "readOnly": true
+  },
+  "actionExecutor": "cdp_sessionEvent",
+  "parameters": [
+    {
+      "id": "state",
+      "type": "string",
+      "multivalued": false
+    },
+    {
+      "id": "sessionId",
+      "type": "string",
+      "multivalued": false
+    },
+    {
+      "id": "scope",
+      "type": "string",
+      "multivalued": false
+    }
+  ]
+}
diff --git a/graphql/cxs-impl/src/main/resources/META-INF/cxs/conditions/cdpSessionEvent.json b/graphql/cxs-impl/src/main/resources/META-INF/cxs/conditions/cdpSessionEvent.json
new file mode 100644
index 0000000..6212f92
--- /dev/null
+++ b/graphql/cxs-impl/src/main/resources/META-INF/cxs/conditions/cdpSessionEvent.json
@@ -0,0 +1,23 @@
+{
+  "metadata": {
+    "id": "cdpSessionEventCondition",
+    "name": "cdpSessionEventCondition",
+    "description": "",
+    "systemTags": [
+      "profileTags",
+      "event",
+      "condition",
+      "eventCondition"
+    ],
+    "readOnly": true
+  },
+  "parentCondition": {
+    "type": "eventTypeCondition",
+    "parameterValues": {
+      "eventTypeId": "cdp_sessionEvent"
+    }
+  },
+
+  "parameters": [
+  ]
+}
diff --git a/graphql/cxs-impl/src/main/resources/META-INF/cxs/rules/cdpSessionEvent.json b/graphql/cxs-impl/src/main/resources/META-INF/cxs/rules/cdpSessionEvent.json
new file mode 100644
index 0000000..664c464
--- /dev/null
+++ b/graphql/cxs-impl/src/main/resources/META-INF/cxs/rules/cdpSessionEvent.json
@@ -0,0 +1,24 @@
+{
+  "metadata" : {
+    "id": "cdp_sessionEvent",
+    "name": "Update session",
+    "description" : "Update session",
+    "readOnly":true
+  },
+
+  "condition" : {
+    "type": "cdpSessionEventCondition",
+    "parameterValues": {
+    }
+  },
+
+  "actions" : [
+    {
+      "type": "cdpSessionEventAction",
+      "parameterValues": {
+
+      }
+    }
+  ]
+
+}
diff --git a/graphql/cxs-impl/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/graphql/cxs-impl/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index c14f5ba..3a9b6e1 100644
--- a/graphql/cxs-impl/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/graphql/cxs-impl/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -21,6 +21,8 @@
 
     <reference id="eventService" interface="org.apache.unomi.api.services.EventService"/>
 
+    <reference id="profileService" interface="org.apache.unomi.api.services.ProfileService"/>
+
     <!-- Action executors -->
 
     <service interface="org.apache.unomi.api.actions.ActionExecutor">
@@ -41,4 +43,14 @@
         </bean>
     </service>
 
+    <service interface="org.apache.unomi.api.actions.ActionExecutor">
+        <service-properties>
+            <entry key="actionExecutorId" value="cdp_sessionEvent"/>
+        </service-properties>
+        <bean class="org.apache.unomi.graphql.actions.CDPSessionAction">
+            <property name="eventService" ref="eventService"/>
+            <property name="profileService" ref="profileService"/>
+        </bean>
+    </service>
+
 </blueprint>