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 2020/11/18 14:01:17 UTC

[unomi] branch unomi-1.4.x updated (586bf31 -> b75db81)

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

shuber pushed a change to branch unomi-1.4.x
in repository https://gitbox.apache.org/repos/asf/unomi.git.


    from 586bf31  UNOMI-399: Provide doc inside the custom.system.properties for scripting allow/forbid mechanism (#217)
     new c4d28ca  UNOMI-401 Fix missing base class in SecureFilteringClassLoader (#219)
     new b75db81  UNOMI-400 Refactoring of hardcoded property accessors (#218)

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../main/resources/etc/custom.system.properties    |   2 +-
 .../HardcodedPropertyAccessorRegistry.java         | 132 +++++++++++
 .../conditions/PropertyConditionEvaluator.java     | 256 +--------------------
 .../conditions/accessors/CampaignAccessor.java     |  44 ++++
 .../conditions/accessors/ConsentAccessor.java      |  44 ++++
 .../conditions/accessors/CustomItemAccessor.java   |  22 +-
 .../conditions/accessors/EventAccessor.java        |  56 +++++
 .../conditions/accessors/GoalAccessor.java         |  22 +-
 .../accessors/HardcodedPropertyAccessor.java       |  38 +++
 .../ItemAccessor.java}                             |  33 +--
 .../MapAccessor.java}                              |  26 ++-
 .../conditions/accessors/MetadataAccessor.java     |  53 +++++
 .../conditions/accessors/MetadataItemAccessor.java |  23 +-
 .../conditions/accessors/ProfileAccessor.java      |  50 ++++
 .../conditions/accessors/RuleAccessor.java         |  30 ++-
 .../conditions/accessors/SessionAccessor.java      |  53 +++++
 .../accessors/TimestampedItemAccessor.java         |  22 +-
 .../HardcodedPropertyAccessorRegistryTest.java     |  56 +++++
 .../conditions/PropertyConditionEvaluatorTest.java |   4 +-
 .../scripting/SecureFilteringClassLoader.java      |   2 +-
 20 files changed, 641 insertions(+), 327 deletions(-)
 create mode 100644 plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/HardcodedPropertyAccessorRegistry.java
 create mode 100644 plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/CampaignAccessor.java
 create mode 100644 plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ConsentAccessor.java
 copy metrics/src/main/java/org/apache/unomi/metrics/commands/DeactivateCommand.java => plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/CustomItemAccessor.java (55%)
 create mode 100644 plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/EventAccessor.java
 copy metrics/src/main/java/org/apache/unomi/metrics/commands/DeactivateCommand.java => plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/GoalAccessor.java (58%)
 create mode 100644 plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/HardcodedPropertyAccessor.java
 copy plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/{NotConditionEvaluator.java => accessors/ItemAccessor.java} (50%)
 copy plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/{MatchAllConditionESQueryBuilder.java => accessors/MapAccessor.java} (54%)
 create mode 100644 plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MetadataAccessor.java
 copy extensions/lists-extension/services/src/main/java/org/apache/unomi/lists/UserList.java => plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MetadataItemAccessor.java (58%)
 create mode 100644 plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ProfileAccessor.java
 copy api/src/main/java/org/apache/unomi/api/actions/ActionPostExecutor.java => plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/RuleAccessor.java (55%)
 create mode 100644 plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/SessionAccessor.java
 copy metrics/src/main/java/org/apache/unomi/metrics/commands/DeactivateCommand.java => plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/TimestampedItemAccessor.java (56%)
 create mode 100644 plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/HardcodedPropertyAccessorRegistryTest.java


[unomi] 01/02: UNOMI-401 Fix missing base class in SecureFilteringClassLoader (#219)

Posted by sh...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

shuber pushed a commit to branch unomi-1.4.x
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit c4d28ca6974ae9a6c1f406a508bb14ab910fbff0
Author: Serge Huber <sh...@jahia.com>
AuthorDate: Wed Nov 18 09:39:43 2020 +0100

    UNOMI-401 Fix missing base class in SecureFilteringClassLoader (#219)
    
    (cherry picked from commit 0d073658f454ff19e127c902d699fe51ffe8037d)
---
 package/src/main/resources/etc/custom.system.properties                 | 2 +-
 .../java/org/apache/unomi/scripting/SecureFilteringClassLoader.java     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/package/src/main/resources/etc/custom.system.properties b/package/src/main/resources/etc/custom.system.properties
index 43cd801..91f23d3 100644
--- a/package/src/main/resources/etc/custom.system.properties
+++ b/package/src/main/resources/etc/custom.system.properties
@@ -33,7 +33,7 @@ org.apache.unomi.hazelcast.network.port=${env:UNOMI_HAZELCAST_NETWORK_PORT:-5701
 org.apache.unomi.security.root.password=${env:UNOMI_ROOT_PASSWORD:-karaf}
 
 # These parameters control the list of classes that are allowed or forbidden when executing expressions.
-org.apache.unomi.scripting.allow=${env:UNOMI_ALLOW_SCRIPTING_CLASSES:-org.apache.unomi.api.Event,org.apache.unomi.api.Profile,org.apache.unomi.api.Session,org.apache.unomi.api.Item,org.apache.unomi.api.CustomItem,ognl.*,java.lang.Object,java.util.Map,java.util.HashMap,java.lang.Integer,org.mvel2.*}
+org.apache.unomi.scripting.allow=${env:UNOMI_ALLOW_SCRIPTING_CLASSES:-org.apache.unomi.api.Event,org.apache.unomi.api.Profile,org.apache.unomi.api.Session,org.apache.unomi.api.Item,org.apache.unomi.api.CustomItem,ognl.*,java.lang.Object,java.util.Map,java.util.HashMap,java.lang.Integer,org.mvel2.*,java.lang.String}
 org.apache.unomi.scripting.forbid=${env:UNOMI_FORBID_SCRIPTING_CLASSES:-}
 
 # This parameter controls the whole expression filtering system. It is not recommended to turn it off. The main reason
diff --git a/scripting/src/main/java/org/apache/unomi/scripting/SecureFilteringClassLoader.java b/scripting/src/main/java/org/apache/unomi/scripting/SecureFilteringClassLoader.java
index 028d637..4af57e1 100644
--- a/scripting/src/main/java/org/apache/unomi/scripting/SecureFilteringClassLoader.java
+++ b/scripting/src/main/java/org/apache/unomi/scripting/SecureFilteringClassLoader.java
@@ -34,7 +34,7 @@ public class SecureFilteringClassLoader extends ClassLoader {
 
     static {
         String systemAllowedClasses = System.getProperty("org.apache.unomi.scripting.allow",
-                "org.apache.unomi.api.Event,org.apache.unomi.api.Profile,org.apache.unomi.api.Session,org.apache.unomi.api.Item,org.apache.unomi.api.CustomItem,ognl.*,java.lang.Object,java.util.Map,java.util.HashMap,java.lang.Integer,org.mvel2.*");
+                "org.apache.unomi.api.Event,org.apache.unomi.api.Profile,org.apache.unomi.api.Session,org.apache.unomi.api.Item,org.apache.unomi.api.CustomItem,ognl.*,java.lang.Object,java.util.Map,java.util.HashMap,java.lang.Integer,org.mvel2.*,java.lang.String");
         if (systemAllowedClasses != null) {
             if ("all".equals(systemAllowedClasses.trim())) {
                 defaultAllowedClasses = null;


[unomi] 02/02: UNOMI-400 Refactoring of hardcoded property accessors (#218)

Posted by sh...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

shuber pushed a commit to branch unomi-1.4.x
in repository https://gitbox.apache.org/repos/asf/unomi.git

commit b75db8158c27f1136298df002842bca475b577a6
Author: Serge Huber <sh...@jahia.com>
AuthorDate: Wed Nov 18 14:54:42 2020 +0100

    UNOMI-400 Refactoring of hardcoded property accessors (#218)
    
    * UNOMI-400 Refactoring of hardcoded property accessors
    
    * UNOMI-400 More refactoring on property accessors & added unit test
    
    (cherry picked from commit 5de4cab84c003688fc72664a9fbda4c33143d880)
---
 .../HardcodedPropertyAccessorRegistry.java         | 132 +++++++++++
 .../conditions/PropertyConditionEvaluator.java     | 256 +--------------------
 .../conditions/accessors/CampaignAccessor.java     |  44 ++++
 .../conditions/accessors/ConsentAccessor.java      |  44 ++++
 .../conditions/accessors/CustomItemAccessor.java   |  35 +++
 .../conditions/accessors/EventAccessor.java        |  56 +++++
 .../conditions/accessors/GoalAccessor.java         |  35 +++
 .../accessors/HardcodedPropertyAccessor.java       |  38 +++
 .../conditions/accessors/ItemAccessor.java         |  44 ++++
 .../conditions/accessors/MapAccessor.java          |  40 ++++
 .../conditions/accessors/MetadataAccessor.java     |  53 +++++
 .../conditions/accessors/MetadataItemAccessor.java |  34 +++
 .../conditions/accessors/ProfileAccessor.java      |  50 ++++
 .../conditions/accessors/RuleAccessor.java         |  38 +++
 .../conditions/accessors/SessionAccessor.java      |  53 +++++
 .../accessors/TimestampedItemAccessor.java         |  35 +++
 .../HardcodedPropertyAccessorRegistryTest.java     |  56 +++++
 .../conditions/PropertyConditionEvaluatorTest.java |   4 +-
 18 files changed, 796 insertions(+), 251 deletions(-)

diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/HardcodedPropertyAccessorRegistry.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/HardcodedPropertyAccessorRegistry.java
new file mode 100644
index 0000000..59a70b5
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/HardcodedPropertyAccessorRegistry.java
@@ -0,0 +1,132 @@
+/*
+ * 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.plugins.baseplugin.conditions;
+
+import org.apache.unomi.api.*;
+import org.apache.unomi.api.campaigns.Campaign;
+import org.apache.unomi.api.goals.Goal;
+import org.apache.unomi.api.rules.Rule;
+import org.apache.unomi.plugins.baseplugin.conditions.accessors.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * This class contains the registry of all the hardcoded property accessors.
+ * For the moment this list of accessors is hardcoded, but in a future update it could be made dynamic.
+ */
+public class HardcodedPropertyAccessorRegistry {
+
+    private static final Logger logger = LoggerFactory.getLogger(HardcodedPropertyAccessorRegistry.class.getName());
+
+    Map<String, HardcodedPropertyAccessor> propertyAccessors = new HashMap<>();
+
+    public HardcodedPropertyAccessorRegistry() {
+        propertyAccessors.put(Item.class.getName(), new ItemAccessor(this));
+        propertyAccessors.put(MetadataItem.class.getName(), new MetadataItemAccessor(this));
+        propertyAccessors.put(Metadata.class.getName(), new MetadataAccessor(this));
+        propertyAccessors.put(TimestampedItem.class.getName(), new TimestampedItemAccessor(this));
+        propertyAccessors.put(Event.class.getName(), new EventAccessor(this));
+        propertyAccessors.put(Profile.class.getName(), new ProfileAccessor(this));
+        propertyAccessors.put(Consent.class.getName(), new ConsentAccessor(this));
+        propertyAccessors.put(Session.class.getName(), new SessionAccessor(this));
+        propertyAccessors.put(Rule.class.getName(), new RuleAccessor(this));
+        propertyAccessors.put(Goal.class.getName(), new GoalAccessor(this));
+        propertyAccessors.put(CustomItem.class.getName(), new CustomItemAccessor(this));
+        propertyAccessors.put(Campaign.class.getName(), new CampaignAccessor(this));
+        propertyAccessors.put(Map.class.getName(), new MapAccessor(this));
+    }
+
+    public static class NextTokens {
+        public String propertyName;
+        public String leftoverExpression;
+    }
+
+    protected NextTokens getNextTokens(String expression) {
+        if (expression.startsWith("[\"")) {
+            int lookupNameBeginPos = "[\"".length();
+            int lookupNameEndPos = expression.indexOf("\"]", lookupNameBeginPos);
+            return buildNextTokens(expression, lookupNameBeginPos, lookupNameEndPos, lookupNameEndPos+2);
+        } else if (expression.startsWith(".")) {
+            int lookupNameBeginPos = ".".length();
+            int lookupNameEndPos = findNextStartDelimiterPos(expression, lookupNameBeginPos);
+            return buildNextTokens(expression, lookupNameBeginPos, lookupNameEndPos, lookupNameEndPos);
+        } else {
+            int lookupNameBeginPos = 0;
+            int lookupNameEndPos = findNextStartDelimiterPos(expression, lookupNameBeginPos);
+            return buildNextTokens(expression, lookupNameBeginPos, lookupNameEndPos, lookupNameEndPos);
+        }
+    }
+
+    private NextTokens buildNextTokens(String expression, int lookupNameBeginPos, int lookupNameEndPos, int leftoverStartPos) {
+        NextTokens nextTokens = new NextTokens();
+        if (lookupNameEndPos >= lookupNameBeginPos) {
+            nextTokens.propertyName = expression.substring(lookupNameBeginPos, lookupNameEndPos);
+            nextTokens.leftoverExpression = expression.substring(leftoverStartPos);
+            if ("".equals(nextTokens.leftoverExpression)) {
+                nextTokens.leftoverExpression = null;
+            }
+        } else {
+            nextTokens.propertyName = expression.substring(lookupNameBeginPos);
+            nextTokens.leftoverExpression = null;
+        }
+        return nextTokens;
+    }
+
+    private int findNextStartDelimiterPos(String expression, int lookupNameBeginPos) {
+        int lookupNameEndPos;
+        int dotlookupNameEndPos = expression.indexOf(".", lookupNameBeginPos);
+        int squareBracketlookupNameEndPos = expression.indexOf("[\"", lookupNameBeginPos);
+        if (dotlookupNameEndPos >= lookupNameBeginPos && squareBracketlookupNameEndPos >= lookupNameBeginPos) {
+            lookupNameEndPos = Math.min(dotlookupNameEndPos, squareBracketlookupNameEndPos);
+        } else if (dotlookupNameEndPos >= lookupNameBeginPos) {
+            lookupNameEndPos = dotlookupNameEndPos;
+        } else if (squareBracketlookupNameEndPos >= lookupNameBeginPos) {
+            lookupNameEndPos = squareBracketlookupNameEndPos;
+        } else {
+            lookupNameEndPos = -1;
+        }
+        return lookupNameEndPos;
+    }
+
+
+    public Object getProperty(Object object, String expression) {
+        if (expression == null) {
+            return object;
+        }
+        if (expression.trim().equals("")) {
+            return object;
+        }
+        NextTokens nextTokens = getNextTokens(expression);
+        List<Class<?>> lookupClasses = new ArrayList<>();
+        lookupClasses.add(object.getClass());
+        lookupClasses.add(object.getClass().getSuperclass());
+        lookupClasses.addAll(Arrays.asList(object.getClass().getInterfaces()));
+        for (Class<?> lookupClass : lookupClasses) {
+            HardcodedPropertyAccessor propertyAccessor = propertyAccessors.get(lookupClass.getName());
+            if (propertyAccessor != null) {
+                Object result = propertyAccessor.getProperty(object, nextTokens.propertyName, nextTokens.leftoverExpression);
+                if (!HardcodedPropertyAccessor.PROPERTY_NOT_FOUND_MARKER.equals(result)) {
+                    return result;
+                }
+            }
+        }
+        logger.warn("Couldn't find any property access for class {} and expression {}", object.getClass().getName(), expression);
+        return HardcodedPropertyAccessor.PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
index 1f9928c..d2e4185 100644
--- a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluator.java
@@ -23,8 +23,7 @@ import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.unomi.api.*;
 import org.apache.unomi.api.conditions.Condition;
-import org.apache.unomi.api.rules.Rule;
-import org.apache.unomi.scripting.ExpressionFilter;
+import org.apache.unomi.plugins.baseplugin.conditions.accessors.HardcodedPropertyAccessor;
 import org.apache.unomi.scripting.ExpressionFilterFactory;
 import org.apache.unomi.scripting.SecureFilteringClassLoader;
 import org.apache.unomi.persistence.elasticsearch.conditions.ConditionContextHelper;
@@ -52,14 +51,14 @@ public class PropertyConditionEvaluator implements ConditionEvaluator {
     private static final Logger logger = LoggerFactory.getLogger(PropertyConditionEvaluator.class.getName());
 
     private static final SimpleDateFormat yearMonthDayDateFormat = new SimpleDateFormat("yyyyMMdd");
-    public static final String NOT_OPTIMIZED_MARKER = "$$$###NOT_OPTIMIZED###$$$";
 
-    private Map<String, Map<String, ExpressionAccessor>> expressionCache = new HashMap<>(64);
+    private final Map<String, Map<String, ExpressionAccessor>> expressionCache = new HashMap<>(64);
     private boolean usePropertyConditionOptimizations = true;
-    private static ClassLoader secureFilteringClassLoader = new SecureFilteringClassLoader(PropertyConditionEvaluator.class.getClassLoader());
+    private static final ClassLoader secureFilteringClassLoader = new SecureFilteringClassLoader(PropertyConditionEvaluator.class.getClassLoader());
+    private static final HardcodedPropertyAccessorRegistry hardcodedPropertyAccessorRegistry = new HardcodedPropertyAccessorRegistry();
     private ExpressionFilterFactory expressionFilterFactory;
 
-    private boolean useOGNLScripting = Boolean.parseBoolean(System.getProperty("org.apache.unomi.security.properties.useOGNLScripting", "false"));
+    private final boolean useOGNLScripting = Boolean.parseBoolean(System.getProperty("org.apache.unomi.security.properties.useOGNLScripting", "false"));
 
     public void setUsePropertyConditionOptimizations(boolean usePropertyConditionOptimizations) {
         this.usePropertyConditionOptimizations = usePropertyConditionOptimizations;
@@ -263,7 +262,7 @@ public class PropertyConditionEvaluator implements ConditionEvaluator {
     protected Object getPropertyValue(Item item, String expression) throws Exception {
         if (usePropertyConditionOptimizations) {
             Object result = getHardcodedPropertyValue(item, expression);
-            if (!NOT_OPTIMIZED_MARKER.equals(result)) {
+            if (!HardcodedPropertyAccessor.PROPERTY_NOT_FOUND_MARKER.equals(result)) {
                 return result;
             }
         }
@@ -278,7 +277,7 @@ public class PropertyConditionEvaluator implements ConditionEvaluator {
     protected Object getHardcodedPropertyValue(Item item, String expression) {
         // the following are optimizations to avoid using the expressions that are slower. The main objective here is
         // to avoid the most used expression that may also trigger calls to the Java Reflection API.
-        return getItemProperty(item, expression);
+        return hardcodedPropertyAccessorRegistry.getProperty(item, expression);
     }
 
     protected Object getOGNLPropertyValue(Item item, String expression) throws Exception {
@@ -299,21 +298,6 @@ public class PropertyConditionEvaluator implements ConditionEvaluator {
         return null;
     }
 
-    private Object getNestedPropertyValue(String expressionPart, Map<String, Object> properties) {
-        int nextDotPos = expressionPart.indexOf(".");
-        if (nextDotPos > -1) {
-            String mapKey = expressionPart.substring(0, nextDotPos);
-            Object mapValue = properties.get(mapKey);
-            if (mapValue == null) {
-                return null;
-            }
-            String nextExpression = expressionPart.substring(nextDotPos + 1);
-            return getNestedPropertyValue(nextExpression, (Map<String, Object>) mapValue);
-        } else {
-            return properties.get(expressionPart);
-        }
-    }
-
     private class ClassLoaderClassResolver extends DefaultClassResolver {
         private ClassLoader classLoader;
 
@@ -422,230 +406,4 @@ public class PropertyConditionEvaluator implements ConditionEvaluator {
         }
     }
 
-    private Object getEventProperty(Event event, String expression) {
-        if (expression.startsWith("properties.")) {
-            return getNestedPropertyValue(expression.substring("properties.".length()), event.getProperties());
-        }
-        if ("scope".equals(expression)) {
-            return event.getScope();
-        }
-        if ("eventType".equals(expression)) {
-            return event.getEventType();
-        }
-        if (expression.startsWith("profile")) {
-            if ("profile".equals(expression)) {
-                return event.getProfile();
-            } else {
-                return getProfileProperty(event.getProfile(), expression.substring("profile".length()+1));
-            }
-        }
-        if ("profileId".equals(expression)) {
-            return event.getProfileId();
-        }
-        if (expression.startsWith("session")) {
-            if ("session".equals(expression)) {
-                return event.getSession();
-            } else {
-                return getSessionProperty(event.getSession(), expression.substring("session".length()+1));
-            }
-        }
-        if ("sessionId".equals(expression)) {
-            return event.getSessionId();
-        }
-        if (expression.startsWith("source")) {
-            if ("source".equals(expression)) {
-                return event.getSource();
-            } else {
-                return getItemProperty(event.getSource(), expression.substring("source".length()+1));
-            }
-        }
-        if (expression.startsWith("target")) {
-            if ("target".equals(expression)) {
-                return event.getTarget();
-            } else {
-                return getItemProperty(event.getTarget(), expression.substring("target".length()+1));
-            }
-        }
-        if ("timeStamp".equals(expression)) {
-            return event.getTimeStamp();
-        }
-        if ("itemId".equals(expression)) {
-            return event.getItemId();
-        }
-        if ("itemType".equals(expression)) {
-            return event.getItemType();
-        }
-        logger.warn("Requested unimplemented property {} on Event object", expression);
-        return NOT_OPTIMIZED_MARKER;
-    }
-
-    private Object getSessionProperty(Session session, String expression) {
-        if ("scope".equals(expression)) {
-            return session.getScope();
-        }
-        if ("timeStamp".equals(expression)) {
-            return session.getTimeStamp();
-        }
-        if ("duration".equals(expression)) {
-            return session.getDuration();
-        }
-        if ("size".equals(expression)) {
-            return session.getSize();
-        }
-        if ("lastEventDate".equals(expression)) {
-            return session.getLastEventDate();
-        }
-        if (expression.startsWith("properties.")) {
-            return getNestedPropertyValue(expression.substring("properties.".length()), session.getProperties());
-        }
-        if (expression.startsWith("systemProperties.")) {
-            return getNestedPropertyValue(expression.substring("systemProperties.".length()), session.getSystemProperties());
-        }
-        if ("itemId".equals(expression)) {
-            return session.getItemId();
-        }
-        if ("itemType".equals(expression)) {
-            return session.getItemType();
-        }
-        if (expression.startsWith("profile")) {
-            if ("profile".equals(expression)) {
-                return session.getProfile();
-            } else {
-                return getProfileProperty((Profile) session.getProfile(), expression.substring("profile".length()+1));
-            }
-        }
-        if ("profileId".equals(expression)) {
-            return session.getProfileId();
-        }
-        logger.warn("Requested unimplemented property {} on Session object", expression);
-        return NOT_OPTIMIZED_MARKER;
-    }
-
-    private Object getProfileProperty(Profile profile, String expression) {
-        if ("segments".equals(expression)) {
-            return profile.getSegments();
-        }
-        if (expression.startsWith("consents")) {
-            if ("consents".equals(expression)) {
-                return profile.getConsents();
-            } else {
-                String consentLookupName = null;
-                String leftoverExpression = expression;
-                if (expression.startsWith("consents[\"")) {
-                    int lookupNameBeginPos = "consents[\"".length();
-                    int lookupNameEndPos = expression.indexOf("\"].", lookupNameBeginPos);
-                    if (lookupNameEndPos > lookupNameBeginPos) {
-                        consentLookupName = expression.substring(lookupNameBeginPos, lookupNameEndPos);
-                        leftoverExpression = expression.substring(lookupNameEndPos+3);
-                    } else {
-                        consentLookupName = expression.substring(lookupNameBeginPos);
-                        leftoverExpression = null;
-                    }
-                } else if (expression.startsWith("consents.")) {
-                    int lookupNameBeginPos = "consents.".length();
-                    int lookupNameEndPos = expression.indexOf(".", lookupNameBeginPos);
-                    if (lookupNameEndPos > lookupNameBeginPos) {
-                        consentLookupName = expression.substring(lookupNameBeginPos, lookupNameEndPos);
-                        leftoverExpression = expression.substring(lookupNameEndPos+1);
-                    } else {
-                        consentLookupName = expression.substring(lookupNameBeginPos);
-                        leftoverExpression = expression.substring(lookupNameEndPos);
-                    }
-                }
-                Consent consent = profile.getConsents().get(consentLookupName);
-                if (consent == null) {
-                    return null;
-                }
-                if (leftoverExpression == null) {
-                    return consent;
-                }
-                return getConsentProperty(consent, leftoverExpression);
-            }
-        }
-        if (expression.startsWith("scores.")) {
-            return profile.getScores().get(expression.substring("scores.".length()));
-        }
-        if (expression.startsWith("properties.")) {
-            return getNestedPropertyValue(expression.substring("properties.".length()), profile.getProperties());
-        }
-        if (expression.startsWith("systemProperties.")) {
-            return getNestedPropertyValue(expression.substring("systemProperties.".length()), profile.getSystemProperties());
-        }
-        if ("itemId".equals(expression)) {
-            return profile.getItemId();
-        }
-        if ("itemType".equals(expression)) {
-            return profile.getItemType();
-        }
-        if ("mergedWith".equals(expression)) {
-            return profile.getMergedWith();
-        }
-        logger.warn("Requested unimplemented property {} on Profile object", expression);
-        return NOT_OPTIMIZED_MARKER;
-    }
-
-    private Object getCustomItemProperty(CustomItem customItem, String expression) {
-        if (expression.startsWith("properties.")) {
-            return getNestedPropertyValue(expression.substring("properties.".length()), customItem.getProperties());
-        }
-        if ("itemId".equals(expression)) {
-            return customItem.getItemId();
-        }
-        if ("itemType".equals(expression)) {
-            return customItem.getItemType();
-        }
-        if ("scope".equals(expression)) {
-            return customItem.getScope();
-        }
-        logger.warn("Requested unimplemented property {} on CustomItem object", expression);
-        return NOT_OPTIMIZED_MARKER;
-    }
-
-    private Object getRuleProperty(Rule rule, String expression) {
-        if ("itemId".equals(expression)) {
-            return rule.getItemId();
-        }
-        if ("itemType".equals(expression)) {
-            return rule.getItemType();
-        }
-        if ("scope".equals(expression)) {
-            return rule.getScope();
-        }
-        logger.warn("Requested unimplemented property {} on Rule object", expression);
-        return NOT_OPTIMIZED_MARKER;
-    }
-
-    private Object getItemProperty(Item item, String expression) {
-        if (item instanceof Profile) {
-            return getProfileProperty((Profile) item, expression);
-        } else if (item instanceof Session) {
-            return getSessionProperty((Session) item, expression);
-        } else if (item instanceof Rule) {
-            return getRuleProperty((Rule) item, expression);
-        } else if (item instanceof Event) {
-            return getEventProperty((Event) item, expression);
-        } else if (item instanceof CustomItem) {
-            return getCustomItemProperty((CustomItem) item, expression);
-        } else {
-            logger.warn("Requested unrecognized property {} on {} class", expression, item.getClass().getName());
-            return NOT_OPTIMIZED_MARKER;
-        }
-    }
-
-    private Object getConsentProperty(Consent consent, String expression) {
-        if ("typeIdentifier".equals(expression)) {
-            return consent.getTypeIdentifier();
-        } else if ("scope".equals(expression)) {
-            return consent.getScope();
-        } else if ("status".equals(expression)) {
-            return consent.getStatus();
-        } else if ("statusDate".equals(expression)) {
-            return consent.getStatusDate();
-        } else if ("revokeDate".equals(expression)) {
-            return consent.getRevokeDate();
-        } else {
-            logger.warn("Requested unrecognized property {} on Consent object {}", expression, consent);
-            return NOT_OPTIMIZED_MARKER;
-        }
-    }
 }
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/CampaignAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/CampaignAccessor.java
new file mode 100644
index 0000000..5736780
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/CampaignAccessor.java
@@ -0,0 +1,44 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.campaigns.Campaign;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class CampaignAccessor extends HardcodedPropertyAccessor<Campaign> {
+    public CampaignAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Campaign object, String propertyName, String leftoverExpression) {
+        if ("startDate".equals(propertyName)) {
+            return object.getStartDate();
+        } else if ("endDate".equals(propertyName)) {
+            return object.getEndDate();
+        } else if ("cost".equals(propertyName)) {
+            return object.getCost();
+        } else if ("currency".equals(propertyName)) {
+            return object.getCurrency();
+        } else if ("primaryGoal".equals(propertyName)) {
+            return object.getPrimaryGoal();
+        } else if ("timezone".equals(propertyName)) {
+            return object.getTimezone();
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ConsentAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ConsentAccessor.java
new file mode 100644
index 0000000..1b052b9
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ConsentAccessor.java
@@ -0,0 +1,44 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.Consent;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class ConsentAccessor extends HardcodedPropertyAccessor<Consent> {
+
+    public ConsentAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Consent object, String propertyName, String leftoverExpression) {
+        if ("typeIdentifier".equals(propertyName)) {
+            return object.getTypeIdentifier();
+        } else if ("scope".equals(propertyName)) {
+            return object.getScope();
+        } else if ("status".equals(propertyName)) {
+            return object.getStatus();
+        } else if ("statusDate".equals(propertyName)) {
+            return object.getStatusDate();
+        } else if ("revokeDate".equals(propertyName)) {
+            return object.getRevokeDate();
+        } else {
+            return PROPERTY_NOT_FOUND_MARKER;
+        }
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/CustomItemAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/CustomItemAccessor.java
new file mode 100644
index 0000000..66ceab2
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/CustomItemAccessor.java
@@ -0,0 +1,35 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.CustomItem;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class CustomItemAccessor extends HardcodedPropertyAccessor<CustomItem> {
+
+    public CustomItemAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(CustomItem object, String propertyName, String leftoverExpression) {
+        if ("properties".equals(propertyName)) {
+            return registry.getProperty(object.getProperties(), leftoverExpression);
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/EventAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/EventAccessor.java
new file mode 100644
index 0000000..ba10bd9
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/EventAccessor.java
@@ -0,0 +1,56 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.Event;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class EventAccessor extends HardcodedPropertyAccessor<Event> {
+
+    public EventAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Event object, String propertyName, String leftoverExpression) {
+        if ("properties".equals(propertyName)) {
+            return registry.getProperty(object.getProperties(), leftoverExpression);
+        }
+        if ("eventType".equals(propertyName)) {
+            return object.getEventType();
+        }
+        if ("profile".equals(propertyName)) {
+            return registry.getProperty(object.getProfile(), leftoverExpression);
+        }
+        if ("profileId".equals(propertyName)) {
+            return object.getProfileId();
+        }
+        if ("session".equals(propertyName)) {
+            return registry.getProperty(object.getSession(), leftoverExpression);
+        }
+        if ("sessionId".equals(propertyName)) {
+            return object.getSessionId();
+        }
+        if ("source".equals(propertyName)) {
+            return registry.getProperty(object.getSource(), leftoverExpression);
+        }
+        if ("target".equals(propertyName)) {
+            return registry.getProperty(object.getTarget(), leftoverExpression);
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/GoalAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/GoalAccessor.java
new file mode 100644
index 0000000..03e0b6c
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/GoalAccessor.java
@@ -0,0 +1,35 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.goals.Goal;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class GoalAccessor extends HardcodedPropertyAccessor<Goal> {
+
+    public GoalAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Goal object, String propertyName, String leftoverExpression) {
+        if ("campaignId".equals(propertyName)) {
+            return object.getCampaignId();
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/HardcodedPropertyAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/HardcodedPropertyAccessor.java
new file mode 100644
index 0000000..7a414fd
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/HardcodedPropertyAccessor.java
@@ -0,0 +1,38 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+/**
+ * Hardcoded property accessors serve two purpose:
+ * - control access to object fields, only expose the ones that are "safe" to use
+ * - prevent using Java Reflection API that is both slower and potentially unsafe as there could be potential to abuse it.
+ */
+public abstract class HardcodedPropertyAccessor<T> {
+
+    public static final String PROPERTY_NOT_FOUND_MARKER = "$$$###PROPERTY_NOT_FOUND###$$$";
+
+    protected HardcodedPropertyAccessorRegistry registry;
+
+    public HardcodedPropertyAccessor(HardcodedPropertyAccessorRegistry registry) {
+        this.registry = registry;
+    }
+
+    public abstract Object getProperty(T object, String propertyName, String leftoverExpression);
+
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ItemAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ItemAccessor.java
new file mode 100644
index 0000000..7dc9913
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ItemAccessor.java
@@ -0,0 +1,44 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.Item;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class ItemAccessor extends HardcodedPropertyAccessor<Item> {
+
+    public ItemAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Item object, String propertyName, String leftoverExpression) {
+        if ("itemId".equals(propertyName)) {
+            return object.getItemId();
+        }
+        if ("itemType".equals(propertyName)) {
+            return object.getItemType();
+        }
+        if ("scope".equals(propertyName)) {
+            return object.getScope();
+        }
+        if ("version".equals(propertyName)) {
+            return object.getVersion();
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MapAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MapAccessor.java
new file mode 100644
index 0000000..fb04257
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MapAccessor.java
@@ -0,0 +1,40 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+import java.util.Map;
+
+public class MapAccessor extends HardcodedPropertyAccessor<Map> {
+    public MapAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Map object, String propertyName, String leftoverExpression) {
+        Object mapValue = object.get(propertyName);
+        if (mapValue == null) {
+            return null;
+        }
+        if (leftoverExpression != null) {
+            return registry.getProperty(mapValue, leftoverExpression);
+        } else {
+            return mapValue;
+        }
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MetadataAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MetadataAccessor.java
new file mode 100644
index 0000000..c4effd1
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MetadataAccessor.java
@@ -0,0 +1,53 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.Metadata;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class MetadataAccessor extends HardcodedPropertyAccessor<Metadata> {
+
+    public MetadataAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Metadata object, String propertyName, String leftoverExpression) {
+        if ("id".equals(propertyName)) {
+            return object.getId();
+        } else if ("name".equals(propertyName)) {
+            return object.getName();
+        } else if ("description".equals(propertyName)) {
+            return object.getDescription();
+        } else if ("scope".equals(propertyName)) {
+            return object.getScope();
+        } else if ("tags".equals(propertyName)) {
+            return object.getTags();
+        } else if ("systemTags".equals(propertyName)) {
+            return object.getSystemTags();
+        } else if ("enabled".equals(propertyName)) {
+            return object.isEnabled();
+        } else if ("missingPlugins".equals(propertyName)) {
+            return object.isMissingPlugins();
+        } else if ("hidden".equals(propertyName)) {
+            return object.isHidden();
+        } else if ("readOnly".equals(propertyName)) {
+            return object.isReadOnly();
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MetadataItemAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MetadataItemAccessor.java
new file mode 100644
index 0000000..1c787a3
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/MetadataItemAccessor.java
@@ -0,0 +1,34 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.MetadataItem;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class MetadataItemAccessor extends HardcodedPropertyAccessor<MetadataItem> {
+    public MetadataItemAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(MetadataItem object, String propertyName, String leftoverExpression) {
+        if ("metadata".equals(propertyName)) {
+            registry.getProperty(object.getMetadata(), leftoverExpression);
+        }
+        return null;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ProfileAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ProfileAccessor.java
new file mode 100644
index 0000000..d008cfd
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/ProfileAccessor.java
@@ -0,0 +1,50 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.Profile;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class ProfileAccessor extends HardcodedPropertyAccessor<Profile> {
+
+    public ProfileAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Profile object, String propertyName, String leftoverExpression) {
+        if ("segments".equals(propertyName)) {
+            return object.getSegments();
+        }
+        if ("consents".equals(propertyName)) {
+            return registry.getProperty(object.getConsents(), leftoverExpression);
+        }
+        if ("scores".equals(propertyName)) {
+            return registry.getProperty(object.getScores(), leftoverExpression);
+        }
+        if ("properties".equals(propertyName)) {
+            return registry.getProperty(object.getProperties(), leftoverExpression);
+        }
+        if ("systemProperties".equals(propertyName)) {
+            return registry.getProperty(object.getSystemProperties(), leftoverExpression);
+        }
+        if ("mergedWith".equals(propertyName)) {
+            return object.getMergedWith();
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/RuleAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/RuleAccessor.java
new file mode 100644
index 0000000..e398798
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/RuleAccessor.java
@@ -0,0 +1,38 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.rules.Rule;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class RuleAccessor extends HardcodedPropertyAccessor<Rule> {
+
+    public RuleAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Rule object, String propertyName, String leftoverExpression) {
+        if ("linkedItems".equals(propertyName)) {
+            return object.getLinkedItems();
+        } else if ("priority".equals(propertyName)) {
+            return object.getPriority();
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/SessionAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/SessionAccessor.java
new file mode 100644
index 0000000..a3da510
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/SessionAccessor.java
@@ -0,0 +1,53 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.Session;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class SessionAccessor extends HardcodedPropertyAccessor<Session> {
+
+    public SessionAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(Session object, String propertyName, String leftoverExpression) {
+        if ("duration".equals(propertyName)) {
+            return object.getDuration();
+        }
+        if ("size".equals(propertyName)) {
+            return object.getSize();
+        }
+        if ("lastEventDate".equals(propertyName)) {
+            return object.getLastEventDate();
+        }
+        if ("properties".equals(propertyName)) {
+            return registry.getProperty(object.getProperties(), leftoverExpression);
+        }
+        if ("systemProperties".equals(propertyName)) {
+            return registry.getProperty(object.getSystemProperties(), leftoverExpression);
+        }
+        if ("profile".equals(propertyName)) {
+            return registry.getProperty(object.getProfile(), leftoverExpression);
+        }
+        if ("profileId".equals(propertyName)) {
+            return object.getProfileId();
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/TimestampedItemAccessor.java b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/TimestampedItemAccessor.java
new file mode 100644
index 0000000..7916a28
--- /dev/null
+++ b/plugins/baseplugin/src/main/java/org/apache/unomi/plugins/baseplugin/conditions/accessors/TimestampedItemAccessor.java
@@ -0,0 +1,35 @@
+/*
+ * 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.plugins.baseplugin.conditions.accessors;
+
+import org.apache.unomi.api.TimestampedItem;
+import org.apache.unomi.plugins.baseplugin.conditions.HardcodedPropertyAccessorRegistry;
+
+public class TimestampedItemAccessor extends HardcodedPropertyAccessor<TimestampedItem> {
+
+    public TimestampedItemAccessor(HardcodedPropertyAccessorRegistry registry) {
+        super(registry);
+    }
+
+    @Override
+    public Object getProperty(TimestampedItem object, String propertyName, String leftoverExpression) {
+        if ("timeStamp".equals(propertyName)) {
+            return object.getTimeStamp();
+        }
+        return PROPERTY_NOT_FOUND_MARKER;
+    }
+}
diff --git a/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/HardcodedPropertyAccessorRegistryTest.java b/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/HardcodedPropertyAccessorRegistryTest.java
new file mode 100644
index 0000000..03bdb30
--- /dev/null
+++ b/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/HardcodedPropertyAccessorRegistryTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.plugins.baseplugin.conditions;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class HardcodedPropertyAccessorRegistryTest {
+
+    HardcodedPropertyAccessorRegistry registry = new HardcodedPropertyAccessorRegistry();
+
+    @Test
+    public void testGetNextTokens() {
+        assertTokens("test", "test", null);
+        assertTokens("test.test", "test", ".test");
+        assertTokens("test..", "test", "..");
+        assertTokens("test...", "test", "...");
+        assertTokens(".test", "test", null);
+        assertTokens(".test[abc]", "test[abc]", null);
+        assertTokens("[abc]", "[abc]", null);
+        assertTokens("[\"abc\"]", "abc", null);
+        assertTokens(".test[\"abc\"]", "test", "[\"abc\"]");
+        assertTokens("..test", "", ".test");
+        assertTokens(".[test", "[test", null);
+        assertTokens("[\"test\"][\"a\"]", "test", "[\"a\"]");
+        assertTokens("test[\"a\"].c", "test", "[\"a\"].c");
+        assertTokens("[\"b\"]", "b", null);
+        assertTokens("[\"b\"].c", "b", ".c");
+        assertTokens("[\"b.c\"].c", "b.c", ".c");
+        assertTokens("[\"b\"test\"].c", "b\"test", ".c");
+        assertTokens("[\"b\"]test\"].c", "b", "test\"].c");
+        assertTokens("[\"b\\.\\\"]c\"].c", "b\\.\\", "c\"].c");
+        assertTokens("[]", "[]", null);
+    }
+
+    private void assertTokens(String expression, String expectedPropertyName, String expectedLeftoverExpression) {
+        HardcodedPropertyAccessorRegistry.NextTokens nextTokens = registry.getNextTokens(expression);
+        assertEquals("Property name value was wrong", expectedPropertyName, nextTokens.propertyName);
+        assertEquals("Leftover expression value was wrong", expectedLeftoverExpression, nextTokens.leftoverExpression);
+    }
+}
diff --git a/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluatorTest.java b/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluatorTest.java
index 720dcff..d63c6be 100644
--- a/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluatorTest.java
+++ b/plugins/baseplugin/src/test/java/org/apache/unomi/plugins/baseplugin/conditions/PropertyConditionEvaluatorTest.java
@@ -18,6 +18,7 @@ package org.apache.unomi.plugins.baseplugin.conditions;
 
 import ognl.MethodFailedException;
 import org.apache.unomi.api.*;
+import org.apache.unomi.plugins.baseplugin.conditions.accessors.HardcodedPropertyAccessor;
 import org.apache.unomi.scripting.ExpressionFilter;
 import org.apache.unomi.scripting.ExpressionFilterFactory;
 import org.junit.Before;
@@ -33,7 +34,6 @@ import java.util.regex.Pattern;
 
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNull;
-import static org.apache.unomi.plugins.baseplugin.conditions.PropertyConditionEvaluator.NOT_OPTIMIZED_MARKER;
 import static org.junit.Assert.assertFalse;
 
 public class PropertyConditionEvaluatorTest {
@@ -94,7 +94,7 @@ public class PropertyConditionEvaluatorTest {
         assertEquals("Unexisting property should be null", null, propertyConditionEvaluator.getHardcodedPropertyValue(mockProfile, "properties.email"));
 
         // here let's make sure our reporting of non optimized expressions works.
-        assertEquals("Should have received the non-optimized marker string", NOT_OPTIMIZED_MARKER, propertyConditionEvaluator.getHardcodedPropertyValue(mockSession, "profile.non-existing-field"));
+        assertEquals("Should have received the non-optimized marker string", HardcodedPropertyAccessor.PROPERTY_NOT_FOUND_MARKER, propertyConditionEvaluator.getHardcodedPropertyValue(mockSession, "profile.non-existing-field"));
 
     }