http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
 
b/persistence-elasticsearch/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index f0fd64e..afa6cd8 100644
--- 
a/persistence-elasticsearch/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ 
b/persistence-elasticsearch/core/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -42,7 +42,7 @@
         </cm:default-properties>
     </cm:property-placeholder>
 
-    <cm:property-placeholder persistent-id="org.oasis_open.contextserver.web"
+    <cm:property-placeholder persistent-id="org.apache.unomi.web"
                              update-strategy="reload" 
placeholder-prefix="${web.">
         <cm:default-properties>
             <cm:property name="contextserver.address" value="localhost"/>
@@ -54,23 +54,23 @@
 
     <service id="elasticSearchPersistenceService" 
ref="elasticSearchPersistenceServiceImpl">
         <interfaces>
-            
<value>org.oasis_open.contextserver.persistence.spi.PersistenceService</value>
-            
<value>org.oasis_open.contextserver.api.services.ClusterService</value>
+            <value>org.apache.unomi.persistence.spi.PersistenceService</value>
+            <value>org.apache.unomi.api.services.ClusterService</value>
         </interfaces>
     </service>
 
     <bean id="conditionESQueryBuilderDispatcher"
-          
class="org.oasis_open.contextserver.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher">
+          
class="org.apache.unomi.persistence.elasticsearch.conditions.ConditionESQueryBuilderDispatcher">
         <property name="bundleContext" ref="blueprintBundleContext"/>
     </bean>
 
     <bean id="conditionEvaluatorDispatcherImpl"
-          
class="org.oasis_open.contextserver.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher">
+          
class="org.apache.unomi.persistence.elasticsearch.conditions.ConditionEvaluatorDispatcher">
         <property name="bundleContext" ref="blueprintBundleContext"/>
     </bean>
 
     <bean id="elasticSearchPersistenceServiceImpl"
-          
class="org.oasis_open.contextserver.persistence.elasticsearch.ElasticSearchPersistenceServiceImpl"
+          
class="org.apache.unomi.persistence.elasticsearch.ElasticSearchPersistenceServiceImpl"
           init-method="start"
           destroy-method="stop">
         <property name="bundleContext" ref="blueprintBundleContext"/>

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/IPRangeMatcher.java
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/IPRangeMatcher.java
 
b/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/IPRangeMatcher.java
new file mode 100644
index 0000000..85b1983
--- /dev/null
+++ 
b/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/IPRangeMatcher.java
@@ -0,0 +1,158 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2013 Edin Dazdarevic ([email protected])
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ *
+ */
+
+package org.apache.unomi.elasticsearch.plugin.security;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class that enables to get an IP range from CIDR specification. It supports
+ * both IPv4 and IPv6.
+ * <p/>
+ * This class was adapted from the CIDRUtils code at 
https://github.com/edazdarevic/CIDRUtils
+ * and support for IP ranges was added.
+ */
+public class IPRangeMatcher {
+
+    private InetAddress inetAddress;
+    private InetAddress startAddress;
+    private InetAddress endAddress;
+    private int prefixLength;
+
+    public IPRangeMatcher(String cidrOrIPRange) throws UnknownHostException {
+
+        if (cidrOrIPRange.contains("/")) {
+            /* split CIDR to address and prefix part */
+            int index = cidrOrIPRange.indexOf("/");
+            String addressPart = cidrOrIPRange.substring(0, index);
+            String networkPart = cidrOrIPRange.substring(index + 1);
+
+            inetAddress = InetAddress.getByName(addressPart);
+            prefixLength = Integer.parseInt(networkPart);
+
+            calculate();
+        } else if (cidrOrIPRange.contains("-")) {
+            String[] rangeParts = cidrOrIPRange.split("-");
+            this.startAddress = InetAddress.getByName(rangeParts[0].trim());
+            this.endAddress = InetAddress.getByName(rangeParts[1].trim());
+        } else {
+            // we don't handle a range, we just match a single IP address
+            this.startAddress = InetAddress.getByName(cidrOrIPRange);
+            this.endAddress = this.startAddress;
+        }
+    }
+
+    public IPRangeMatcher(InetAddress startAddress, InetAddress endAddress) {
+        this.startAddress = startAddress;
+        this.endAddress = endAddress;
+    }
+
+    public IPRangeMatcher(String startAddress, String endAddress) throws 
UnknownHostException {
+        this.startAddress = InetAddress.getByName(startAddress);
+        this.endAddress = InetAddress.getByName(endAddress);
+    }
+
+
+    private void calculate() throws UnknownHostException {
+
+        ByteBuffer maskBuffer;
+        int targetSize;
+        if (inetAddress.getAddress().length == 4) {
+            maskBuffer =
+                    ByteBuffer
+                            .allocate(4)
+                            .putInt(-1);
+            targetSize = 4;
+        } else {
+            maskBuffer = ByteBuffer.allocate(16)
+                    .putLong(-1L)
+                    .putLong(-1L);
+            targetSize = 16;
+        }
+
+        BigInteger mask = (new BigInteger(1, 
maskBuffer.array())).not().shiftRight(prefixLength);
+
+        ByteBuffer buffer = ByteBuffer.wrap(inetAddress.getAddress());
+        BigInteger ipVal = new BigInteger(1, buffer.array());
+
+        BigInteger startIp = ipVal.and(mask);
+        BigInteger endIp = startIp.add(mask.not());
+
+        byte[] startIpArr = toBytes(startIp.toByteArray(), targetSize);
+        byte[] endIpArr = toBytes(endIp.toByteArray(), targetSize);
+
+        this.startAddress = InetAddress.getByAddress(startIpArr);
+        this.endAddress = InetAddress.getByAddress(endIpArr);
+
+    }
+
+    private byte[] toBytes(byte[] array, int targetSize) {
+        int counter = 0;
+        List<Byte> newArr = new ArrayList<Byte>();
+        while (counter < targetSize && (array.length - 1 - counter >= 0)) {
+            newArr.add(0, array[array.length - 1 - counter]);
+            counter++;
+        }
+
+        int size = newArr.size();
+        for (int i = 0; i < (targetSize - size); i++) {
+
+            newArr.add(0, (byte) 0);
+        }
+
+        byte[] ret = new byte[newArr.size()];
+        for (int i = 0; i < newArr.size(); i++) {
+            ret[i] = newArr.get(i);
+        }
+        return ret;
+    }
+
+    public String getNetworkAddress() {
+
+        return this.startAddress.getHostAddress();
+    }
+
+    public String getBroadcastAddress() {
+        return this.endAddress.getHostAddress();
+    }
+
+    public boolean isInRange(String ipAddress) throws UnknownHostException {
+        InetAddress address = InetAddress.getByName(ipAddress);
+        BigInteger start = new BigInteger(1, this.startAddress.getAddress());
+        BigInteger end = new BigInteger(1, this.endAddress.getAddress());
+        BigInteger target = new BigInteger(1, address.getAddress());
+
+        int st = start.compareTo(target);
+        int te = target.compareTo(end);
+
+        return (st == -1 || st == 0) && (te == -1 || te == 0);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPlugin.java
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPlugin.java
 
b/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPlugin.java
new file mode 100644
index 0000000..61814a1
--- /dev/null
+++ 
b/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPlugin.java
@@ -0,0 +1,61 @@
+/*
+ * 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.elasticsearch.plugin.security;
+
+import org.elasticsearch.common.component.LifecycleComponent;
+import org.elasticsearch.common.inject.Module;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.plugins.AbstractPlugin;
+
+import java.util.Collection;
+
+import static org.elasticsearch.common.collect.Lists.newArrayList;
+
+public class SecurityPlugin extends AbstractPlugin {
+
+    public SecurityPlugin(Settings settings) {
+        super();
+    }
+
+    public String name() {
+        return "contextserver-security";
+    }
+
+    public String description() {
+        return "A plugin that provides some basic security to the Context 
Server elasticsearch HTTP and Transport connectors";
+    }
+
+    @Override
+    public Collection<Class<? extends Module>> modules() {
+        Collection<Class<? extends Module>> modules = newArrayList();
+        // if (settings.getAsBoolean("security.enabled", true)) {
+        modules.add(SecurityPluginModule.class);
+        // }
+        return modules;
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    public Collection<Class<? extends LifecycleComponent>> services() {
+        Collection<Class<? extends LifecycleComponent>> services = 
newArrayList();
+        // if (settings.getAsBoolean("security.enabled", true)) {
+        services.add(SecurityPluginService.class);
+        // }
+        return services;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPluginModule.java
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPluginModule.java
 
b/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPluginModule.java
new file mode 100644
index 0000000..67e1770
--- /dev/null
+++ 
b/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPluginModule.java
@@ -0,0 +1,33 @@
+/*
+ * 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.elasticsearch.plugin.security;
+
+import org.elasticsearch.common.inject.AbstractModule;
+import org.elasticsearch.common.settings.Settings;
+
+public class SecurityPluginModule extends AbstractModule {
+
+    public SecurityPluginModule(Settings settings) {
+        super();
+    }
+
+    @Override
+    protected void configure() {
+        bind(SecurityPluginService.class).asEagerSingleton();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPluginService.java
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPluginService.java
 
b/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPluginService.java
new file mode 100644
index 0000000..f3941ea
--- /dev/null
+++ 
b/persistence-elasticsearch/plugins/security/src/main/java/org/apache/unomi/elasticsearch/plugin/security/SecurityPluginService.java
@@ -0,0 +1,157 @@
+/*
+ * 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.elasticsearch.plugin.security;
+
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.cluster.node.DiscoveryNode;
+import org.elasticsearch.common.component.AbstractLifecycleComponent;
+import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.network.NetworkService;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.rest.*;
+import org.elasticsearch.transport.TransportConnectionListener;
+import org.elasticsearch.transport.TransportService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * ElasticSearch plugin that simply rejects connection from non-authorized IP 
ranges
+ */
+public class SecurityPluginService extends 
AbstractLifecycleComponent<SecurityPluginService> {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(SecurityPluginService.class.getName());
+
+    RestController restController;
+    TransportService transportService;
+    RestFilter restFilter;
+    TransportConnectionListener transportConnectionListener;
+    String publishHost;
+    List<IPRangeMatcher> ipRangeMatchers = new ArrayList<IPRangeMatcher>();
+
+    @Inject
+    public SecurityPluginService(Settings settings,
+                                 RestController restController,
+                                 TransportService transportService,
+                                 NetworkService networkService) {
+        super(settings);
+        this.restController = restController;
+        this.transportService = transportService;
+        this.publishHost = componentSettings.get("publish_host", 
settings.get("transport.publish_host", settings.get("transport.host")));
+        InetAddress publishHostAddress = null;
+        try {
+            publishHostAddress = 
networkService.resolvePublishHostAddress(publishHost);
+        } catch (IOException e) {
+            logger.error("Error trying to resolve publish host address " + 
publishHost);
+        }
+
+        initIPRangeMatcher(settings, publishHostAddress);
+    }
+
+    protected void initIPRangeMatcher(Settings settings, InetAddress 
publishHostAddress) {
+        String hostAddressRange = null;
+        if (publishHostAddress != null) {
+            String hostAddress = publishHostAddress.getHostAddress();
+            if (publishHostAddress instanceof Inet4Address) {
+                int lastDotPos = hostAddress.lastIndexOf(".");
+                if (lastDotPos > -1) {
+                    hostAddressRange = hostAddress.substring(0, lastDotPos) + 
".0-" + hostAddress.substring(0, lastDotPos) + ".255";
+                }
+            } else if (publishHostAddress instanceof Inet6Address) {
+                int lastColonPos = hostAddress.lastIndexOf(":");
+                if (lastColonPos > -1) {
+                    hostAddressRange = hostAddress.substring(0, lastColonPos) 
+ ":0-" + hostAddress.substring(0, lastColonPos) + ":ffff";
+                }
+            }
+        }
+        String defaultIpRanges = "localhost,127.0.0.1,127.0.1.1,::1";
+        if (hostAddressRange != null) {
+            defaultIpRanges += "," + hostAddressRange;
+        }
+        String[] ipRanges = settings.get("security.ipranges", 
defaultIpRanges).split(",");
+        for (String ipRange : ipRanges) {
+            try {
+                IPRangeMatcher iprangeMatcher = new 
IPRangeMatcher(ipRange.trim());
+                ipRangeMatchers.add(iprangeMatcher);
+            } catch (UnknownHostException e) {
+                logger.error("Error in specified IP range " + ipRange, e);
+            }
+        }
+    }
+
+    @Override
+    protected void doStart() throws ElasticsearchException {
+        restFilter = new RestFilter() {
+            @Override
+            public void process(RestRequest request, RestChannel channel, 
RestFilterChain filterChain) throws Exception {
+                logger.info("Processing REST request=" + request + " channel=" 
+ channel);
+                if (request.getRemoteAddress() instanceof InetSocketAddress) {
+                    InetSocketAddress inetSocketAddress = (InetSocketAddress) 
request.getRemoteAddress();
+                    if (!isIPAllowed(inetSocketAddress.getHostName())) {
+                        logger.warn("Rejecting request from unauthorized IP " 
+ request.getRemoteAddress());
+                        return;
+                    }
+                } else {
+                    logger.warn("Unexpected SocketAddress that is not an 
InetSocketAddress (but an instance of  " + 
request.getRemoteAddress().getClass().getName() + "), IP range filtering is 
DISABLED !");
+                }
+                filterChain.continueProcessing(request, channel);
+            }
+        };
+        restController.registerFilter(restFilter);
+        transportConnectionListener = new TransportConnectionListener() {
+            public void onNodeConnected(DiscoveryNode node) {
+                logger.info("Node connected " + node);
+                if (!isIPAllowed(node.getHostAddress())) {
+                    logger.warn("Rejecting connection from unauthorized IP " + 
node.getHostAddress());
+                    transportService.disconnectFromNode(node);
+                }
+            }
+
+            public void onNodeDisconnected(DiscoveryNode node) {
+            }
+        };
+        transportService.addConnectionListener(transportConnectionListener);
+    }
+
+    @Override
+    protected void doStop() throws ElasticsearchException {
+        transportService.removeConnectionListener(transportConnectionListener);
+    }
+
+    @Override
+    protected void doClose() throws ElasticsearchException {
+
+    }
+
+    public boolean isIPAllowed(String ipAddress) {
+        for (IPRangeMatcher ipRangeMatcher : ipRangeMatchers) {
+            try {
+                if (ipRangeMatcher.isInRange(ipAddress)) {
+                    return true;
+                }
+            } catch (UnknownHostException e) {
+                logger.error("Error checking IP range for " + ipAddress + " 
connection will NOT be allowed", e);
+            }
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/IPRangeMatcher.java
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/IPRangeMatcher.java
 
b/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/IPRangeMatcher.java
deleted file mode 100644
index 114c86a..0000000
--- 
a/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/IPRangeMatcher.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright (c) 2013 Edin Dazdarevic ([email protected])
-
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to 
deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
-
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
-
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *
- */
-
-package org.elasticsearch.contextserver;
-
-import java.math.BigInteger;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A class that enables to get an IP range from CIDR specification. It supports
- * both IPv4 and IPv6.
- * <p/>
- * This class was adapted from the CIDRUtils code at 
https://github.com/edazdarevic/CIDRUtils
- * and support for IP ranges was added.
- */
-public class IPRangeMatcher {
-
-    private InetAddress inetAddress;
-    private InetAddress startAddress;
-    private InetAddress endAddress;
-    private int prefixLength;
-
-    public IPRangeMatcher(String cidrOrIPRange) throws UnknownHostException {
-
-        if (cidrOrIPRange.contains("/")) {
-            /* split CIDR to address and prefix part */
-            int index = cidrOrIPRange.indexOf("/");
-            String addressPart = cidrOrIPRange.substring(0, index);
-            String networkPart = cidrOrIPRange.substring(index + 1);
-
-            inetAddress = InetAddress.getByName(addressPart);
-            prefixLength = Integer.parseInt(networkPart);
-
-            calculate();
-        } else if (cidrOrIPRange.contains("-")) {
-            String[] rangeParts = cidrOrIPRange.split("-");
-            this.startAddress = InetAddress.getByName(rangeParts[0].trim());
-            this.endAddress = InetAddress.getByName(rangeParts[1].trim());
-        } else {
-            // we don't handle a range, we just match a single IP address
-            this.startAddress = InetAddress.getByName(cidrOrIPRange);
-            this.endAddress = this.startAddress;
-        }
-    }
-
-    public IPRangeMatcher(InetAddress startAddress, InetAddress endAddress) {
-        this.startAddress = startAddress;
-        this.endAddress = endAddress;
-    }
-
-    public IPRangeMatcher(String startAddress, String endAddress) throws 
UnknownHostException {
-        this.startAddress = InetAddress.getByName(startAddress);
-        this.endAddress = InetAddress.getByName(endAddress);
-    }
-
-
-    private void calculate() throws UnknownHostException {
-
-        ByteBuffer maskBuffer;
-        int targetSize;
-        if (inetAddress.getAddress().length == 4) {
-            maskBuffer =
-                    ByteBuffer
-                            .allocate(4)
-                            .putInt(-1);
-            targetSize = 4;
-        } else {
-            maskBuffer = ByteBuffer.allocate(16)
-                    .putLong(-1L)
-                    .putLong(-1L);
-            targetSize = 16;
-        }
-
-        BigInteger mask = (new BigInteger(1, 
maskBuffer.array())).not().shiftRight(prefixLength);
-
-        ByteBuffer buffer = ByteBuffer.wrap(inetAddress.getAddress());
-        BigInteger ipVal = new BigInteger(1, buffer.array());
-
-        BigInteger startIp = ipVal.and(mask);
-        BigInteger endIp = startIp.add(mask.not());
-
-        byte[] startIpArr = toBytes(startIp.toByteArray(), targetSize);
-        byte[] endIpArr = toBytes(endIp.toByteArray(), targetSize);
-
-        this.startAddress = InetAddress.getByAddress(startIpArr);
-        this.endAddress = InetAddress.getByAddress(endIpArr);
-
-    }
-
-    private byte[] toBytes(byte[] array, int targetSize) {
-        int counter = 0;
-        List<Byte> newArr = new ArrayList<Byte>();
-        while (counter < targetSize && (array.length - 1 - counter >= 0)) {
-            newArr.add(0, array[array.length - 1 - counter]);
-            counter++;
-        }
-
-        int size = newArr.size();
-        for (int i = 0; i < (targetSize - size); i++) {
-
-            newArr.add(0, (byte) 0);
-        }
-
-        byte[] ret = new byte[newArr.size()];
-        for (int i = 0; i < newArr.size(); i++) {
-            ret[i] = newArr.get(i);
-        }
-        return ret;
-    }
-
-    public String getNetworkAddress() {
-
-        return this.startAddress.getHostAddress();
-    }
-
-    public String getBroadcastAddress() {
-        return this.endAddress.getHostAddress();
-    }
-
-    public boolean isInRange(String ipAddress) throws UnknownHostException {
-        InetAddress address = InetAddress.getByName(ipAddress);
-        BigInteger start = new BigInteger(1, this.startAddress.getAddress());
-        BigInteger end = new BigInteger(1, this.endAddress.getAddress());
-        BigInteger target = new BigInteger(1, address.getAddress());
-
-        int st = start.compareTo(target);
-        int te = target.compareTo(end);
-
-        return (st == -1 || st == 0) && (te == -1 || te == 0);
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPlugin.java
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPlugin.java
 
b/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPlugin.java
deleted file mode 100644
index 6c62ea7..0000000
--- 
a/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPlugin.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.elasticsearch.contextserver;
-
-import org.elasticsearch.common.component.LifecycleComponent;
-import org.elasticsearch.common.inject.Module;
-import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.plugins.AbstractPlugin;
-
-import java.util.Collection;
-
-import static org.elasticsearch.common.collect.Lists.newArrayList;
-
-public class SecurityPlugin extends AbstractPlugin {
-
-    public SecurityPlugin(Settings settings) {
-        super();
-    }
-
-    public String name() {
-        return "contextserver-security";
-    }
-
-    public String description() {
-        return "A plugin that provides some basic security to the Context 
Server elasticsearch HTTP and Transport connectors";
-    }
-
-    @Override
-    public Collection<Class<? extends Module>> modules() {
-        Collection<Class<? extends Module>> modules = newArrayList();
-        // if (settings.getAsBoolean("security.enabled", true)) {
-        modules.add(SecurityPluginModule.class);
-        // }
-        return modules;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    public Collection<Class<? extends LifecycleComponent>> services() {
-        Collection<Class<? extends LifecycleComponent>> services = 
newArrayList();
-        // if (settings.getAsBoolean("security.enabled", true)) {
-        services.add(SecurityPluginService.class);
-        // }
-        return services;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPluginModule.java
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPluginModule.java
 
b/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPluginModule.java
deleted file mode 100644
index 04d81ca..0000000
--- 
a/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPluginModule.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.elasticsearch.contextserver;
-
-import org.elasticsearch.common.inject.AbstractModule;
-import org.elasticsearch.common.settings.Settings;
-
-public class SecurityPluginModule extends AbstractModule {
-
-    public SecurityPluginModule(Settings settings) {
-        super();
-    }
-
-    @Override
-    protected void configure() {
-        bind(SecurityPluginService.class).asEagerSingleton();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPluginService.java
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPluginService.java
 
b/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPluginService.java
deleted file mode 100644
index d3f306f..0000000
--- 
a/persistence-elasticsearch/plugins/security/src/main/java/org/elasticsearch/contextserver/SecurityPluginService.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.elasticsearch.contextserver;
-
-import org.elasticsearch.ElasticsearchException;
-import org.elasticsearch.cluster.node.DiscoveryNode;
-import org.elasticsearch.common.component.AbstractLifecycleComponent;
-import org.elasticsearch.common.inject.Inject;
-import org.elasticsearch.common.network.NetworkService;
-import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.rest.*;
-import org.elasticsearch.transport.TransportConnectionListener;
-import org.elasticsearch.transport.TransportService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.IOException;
-import java.net.*;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * ElasticSearch plugin that simply rejects connection from non-authorized IP 
ranges
- */
-public class SecurityPluginService extends 
AbstractLifecycleComponent<SecurityPluginService> {
-
-    private static final Logger logger = 
LoggerFactory.getLogger(SecurityPluginService.class.getName());
-
-    RestController restController;
-    TransportService transportService;
-    RestFilter restFilter;
-    TransportConnectionListener transportConnectionListener;
-    String publishHost;
-    List<IPRangeMatcher> ipRangeMatchers = new ArrayList<IPRangeMatcher>();
-
-    @Inject
-    public SecurityPluginService(Settings settings,
-                                 RestController restController,
-                                 TransportService transportService,
-                                 NetworkService networkService) {
-        super(settings);
-        this.restController = restController;
-        this.transportService = transportService;
-        this.publishHost = componentSettings.get("publish_host", 
settings.get("transport.publish_host", settings.get("transport.host")));
-        InetAddress publishHostAddress = null;
-        try {
-            publishHostAddress = 
networkService.resolvePublishHostAddress(publishHost);
-        } catch (IOException e) {
-            logger.error("Error trying to resolve publish host address " + 
publishHost);
-        }
-
-        initIPRangeMatcher(settings, publishHostAddress);
-    }
-
-    protected void initIPRangeMatcher(Settings settings, InetAddress 
publishHostAddress) {
-        String hostAddressRange = null;
-        if (publishHostAddress != null) {
-            String hostAddress = publishHostAddress.getHostAddress();
-            if (publishHostAddress instanceof Inet4Address) {
-                int lastDotPos = hostAddress.lastIndexOf(".");
-                if (lastDotPos > -1) {
-                    hostAddressRange = hostAddress.substring(0, lastDotPos) + 
".0-" + hostAddress.substring(0, lastDotPos) + ".255";
-                }
-            } else if (publishHostAddress instanceof Inet6Address) {
-                int lastColonPos = hostAddress.lastIndexOf(":");
-                if (lastColonPos > -1) {
-                    hostAddressRange = hostAddress.substring(0, lastColonPos) 
+ ":0-" + hostAddress.substring(0, lastColonPos) + ":ffff";
-                }
-            }
-        }
-        String defaultIpRanges = "localhost,127.0.0.1,127.0.1.1,::1";
-        if (hostAddressRange != null) {
-            defaultIpRanges += "," + hostAddressRange;
-        }
-        String[] ipRanges = settings.get("security.ipranges", 
defaultIpRanges).split(",");
-        for (String ipRange : ipRanges) {
-            try {
-                IPRangeMatcher iprangeMatcher = new 
IPRangeMatcher(ipRange.trim());
-                ipRangeMatchers.add(iprangeMatcher);
-            } catch (UnknownHostException e) {
-                logger.error("Error in specified IP range " + ipRange, e);
-            }
-        }
-    }
-
-    @Override
-    protected void doStart() throws ElasticsearchException {
-        restFilter = new RestFilter() {
-            @Override
-            public void process(RestRequest request, RestChannel channel, 
RestFilterChain filterChain) throws Exception {
-                logger.info("Processing REST request=" + request + " channel=" 
+ channel);
-                if (request.getRemoteAddress() instanceof InetSocketAddress) {
-                    InetSocketAddress inetSocketAddress = (InetSocketAddress) 
request.getRemoteAddress();
-                    if (!isIPAllowed(inetSocketAddress.getHostName())) {
-                        logger.warn("Rejecting request from unauthorized IP " 
+ request.getRemoteAddress());
-                        return;
-                    }
-                } else {
-                    logger.warn("Unexpected SocketAddress that is not an 
InetSocketAddress (but an instance of  " + 
request.getRemoteAddress().getClass().getName() + "), IP range filtering is 
DISABLED !");
-                }
-                filterChain.continueProcessing(request, channel);
-            }
-        };
-        restController.registerFilter(restFilter);
-        transportConnectionListener = new TransportConnectionListener() {
-            public void onNodeConnected(DiscoveryNode node) {
-                logger.info("Node connected " + node);
-                if (!isIPAllowed(node.getHostAddress())) {
-                    logger.warn("Rejecting connection from unauthorized IP " + 
node.getHostAddress());
-                    transportService.disconnectFromNode(node);
-                }
-            }
-
-            public void onNodeDisconnected(DiscoveryNode node) {
-            }
-        };
-        transportService.addConnectionListener(transportConnectionListener);
-    }
-
-    @Override
-    protected void doStop() throws ElasticsearchException {
-        transportService.removeConnectionListener(transportConnectionListener);
-    }
-
-    @Override
-    protected void doClose() throws ElasticsearchException {
-
-    }
-
-    public boolean isIPAllowed(String ipAddress) {
-        for (IPRangeMatcher ipRangeMatcher : ipRangeMatchers) {
-            try {
-                if (ipRangeMatcher.isInRange(ipAddress)) {
-                    return true;
-                }
-            } catch (UnknownHostException e) {
-                logger.error("Error checking IP range for " + ipAddress + " 
connection will NOT be allowed", e);
-            }
-        }
-        return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-elasticsearch/plugins/security/src/main/resources/es-plugin.properties
----------------------------------------------------------------------
diff --git 
a/persistence-elasticsearch/plugins/security/src/main/resources/es-plugin.properties
 
b/persistence-elasticsearch/plugins/security/src/main/resources/es-plugin.properties
index d24783e..0ac5643 100644
--- 
a/persistence-elasticsearch/plugins/security/src/main/resources/es-plugin.properties
+++ 
b/persistence-elasticsearch/plugins/security/src/main/resources/es-plugin.properties
@@ -14,5 +14,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-plugin=org.elasticsearch.contextserver.SecurityPlugin
+plugin=org.apache.unomi.elasticsearch.plugin.security.SecurityPlugin
 version=${project.version}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/CustomObjectMapper.java
----------------------------------------------------------------------
diff --git 
a/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/CustomObjectMapper.java
 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/CustomObjectMapper.java
new file mode 100644
index 0000000..f17f8b2
--- /dev/null
+++ 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/CustomObjectMapper.java
@@ -0,0 +1,92 @@
+/*
+ * 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.persistence.spi;
+
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
+import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
+import org.apache.unomi.api.*;
+import org.apache.unomi.api.campaigns.Campaign;
+import org.apache.unomi.api.campaigns.events.CampaignEvent;
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.api.goals.Goal;
+import org.apache.unomi.api.rules.Rule;
+import org.apache.unomi.api.segments.Scoring;
+import org.apache.unomi.api.segments.Segment;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * Custom object mapper to be able to configure Jackson to our needs.
+ */
+public class CustomObjectMapper extends ObjectMapper {
+
+    private static final long serialVersionUID = 4578277612897061535L;
+
+    public CustomObjectMapper() {
+        super();
+        super.registerModule(new JaxbAnnotationModule());
+        configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+        ISO8601DateFormat dateFormat = new ISO8601DateFormat();
+        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
+        setDateFormat(dateFormat);
+        SimpleModule deserializerModule =
+              new SimpleModule("PropertyTypedObjectDeserializerModule",
+                      new Version(1, 0, 0, null, "org.apache.unomi.rest", 
"deserializer"));
+
+        PropertyTypedObjectDeserializer propertyTypedObjectDeserializer = new 
PropertyTypedObjectDeserializer();
+        propertyTypedObjectDeserializer.registerMapping("type=.*Condition", 
Condition.class);
+        deserializerModule.addDeserializer(Object.class, 
propertyTypedObjectDeserializer);
+
+        ItemDeserializer itemDeserializer = new ItemDeserializer();
+        deserializerModule.addDeserializer(Item.class, itemDeserializer);
+
+
+        Map<String,Class<? extends Item>> classes = new HashMap<>();
+        classes.put(Campaign.ITEM_TYPE,Campaign.class);
+        classes.put(CampaignEvent.ITEM_TYPE,CampaignEvent.class);
+        classes.put(Event.ITEM_TYPE,Event.class);
+        classes.put(Goal.ITEM_TYPE,Goal.class);
+        classes.put(Persona.ITEM_TYPE,Persona.class);
+        classes.put(Rule.ITEM_TYPE,Rule.class);
+        classes.put(Scoring.ITEM_TYPE,Scoring.class);
+        classes.put(Segment.ITEM_TYPE,Segment.class);
+        classes.put(Session.ITEM_TYPE, Session.class);
+        for (Map.Entry<String, Class<? extends Item>> entry : 
classes.entrySet()) {
+            
propertyTypedObjectDeserializer.registerMapping("itemType="+entry.getKey(), 
entry.getValue());
+            itemDeserializer.registerMapping(entry.getKey(), entry.getValue());
+        }
+        propertyTypedObjectDeserializer.registerMapping("itemType=.*", 
CustomItem.class);
+
+
+       super.registerModule(deserializerModule);
+    }
+
+    public static ObjectMapper getObjectMapper() {
+        return Holder.INSTANCE;
+    }
+
+    private static class Holder {
+        static final CustomObjectMapper INSTANCE = new CustomObjectMapper();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/ItemDeserializer.java
----------------------------------------------------------------------
diff --git 
a/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/ItemDeserializer.java
 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/ItemDeserializer.java
new file mode 100644
index 0000000..9080907
--- /dev/null
+++ 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/ItemDeserializer.java
@@ -0,0 +1,60 @@
+/*
+ * 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.persistence.spi;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.unomi.api.CustomItem;
+import org.apache.unomi.api.Item;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ItemDeserializer extends StdDeserializer<Item> {
+
+    private static final long serialVersionUID = -7040054009670771266L;
+    private Map<String,Class<? extends Item>> classes = new HashMap<>();
+
+    public ItemDeserializer() {
+        super(Item.class);
+    }
+
+    public void registerMapping(String type, Class<? extends Item> clazz) {
+        classes.put(type, clazz);
+    }
+
+    @Override
+    public Item deserialize(JsonParser jp, DeserializationContext ctxt) throws 
IOException {
+        ObjectCodec codec = jp.getCodec();
+        ObjectNode treeNode = codec.readTree(jp);
+        String type = treeNode.get("itemType").textValue();
+        Class<? extends Item> objectClass = classes.get(type);
+        if (objectClass == null) {
+            objectClass = CustomItem.class;
+        } else {
+            treeNode.remove("itemType");
+        }
+        Item item = codec.treeToValue(treeNode, objectClass);
+        item.setItemId(treeNode.get("itemId").asText());
+        return item;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PersistenceService.java
----------------------------------------------------------------------
diff --git 
a/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PersistenceService.java
 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PersistenceService.java
new file mode 100644
index 0000000..4a44c63
--- /dev/null
+++ 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PersistenceService.java
@@ -0,0 +1,399 @@
+/*
+ * 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.persistence.spi;
+
+import org.apache.unomi.api.Item;
+import org.apache.unomi.api.PartialList;
+import org.apache.unomi.api.conditions.Condition;
+import org.apache.unomi.persistence.spi.aggregate.BaseAggregate;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A service to provide persistence and retrieval of context server entities.
+ */
+public interface PersistenceService {
+
+    /**
+     * Retrieves all known items of the specified class.
+     * <em>WARNING</em>: this method can be quite computationally intensive 
and calling the paged version {@link #getAllItems(Class, int, int, String)} is 
preferred.
+     *
+     * @param <T>   the type of the {@link Item}s we want to retrieve
+     * @param clazz the {@link Item} subclass of entities we want to retrieve
+     * @return a list of all known items with the given type
+     */
+    <T extends Item> List<T> getAllItems(Class<T> clazz);
+
+    /**
+     * Retrieves all known items of the specified class, ordered according to 
the specified {@code sortBy} String and and paged: only {@code size} of them 
are retrieved,
+     * starting with the {@code offset}-th one.
+     *
+     * TODO: use a Query object instead of distinct parameters?
+     *
+     * @param <T>    the type of the {@link Item}s we want to retrieve
+     * @param clazz  the {@link Item} subclass of entities we want to retrieve
+     * @param offset zero or a positive integer specifying the position of the 
first item in the total ordered collection of matching items
+     * @param size   a positive integer specifying how many matching items 
should be retrieved or {@code -1} if all of them should be retrieved
+     * @param sortBy an optional ({@code null} if no sorting is required) 
String of comma ({@code ,}) separated property names on which ordering should 
be performed, ordering
+     *               elements according to the property order in the
+     *               String, considering each in turn and moving on to the 
next one in case of equality of all preceding ones. Each property name is 
optionally followed by
+     *               a column ({@code :}) and an order specifier: {@code asc} 
or {@code desc}.
+     * @return a {@link PartialList} of pages items with the given type
+     */
+    <T extends Item> PartialList<T> getAllItems(Class<T> clazz, int offset, 
int size, String sortBy);
+
+    /**
+     * Persists the specified Item in the context server.
+     *
+     * @param item the item to persist
+     * @return {@code true} if the item was properly persisted, {@code false} 
otherwise
+     */
+    boolean save(Item item);
+
+    /**
+     * Updates the item of the specified class and identified by the specified 
identifier with new property values provided as name - value pairs in the 
specified Map.
+     *
+     * @param itemId   the identifier of the item we want to update
+     * @param dateHint a Date helping in identifying where the item is located
+     * @param clazz    the Item subclass of the item to update
+     * @param source   a Map with entries specifying as key the property name 
to update and as value its new value
+     * @return {@code true} if the update was successful, {@code false} 
otherwise
+     */
+    boolean update(String itemId, Date dateHint, Class<?> clazz, Map<?, ?> 
source);
+
+    /**
+     * Updates the item of the specified class and identified by the specified 
identifier with a new property value for the specified property name. Same as
+     * {@code update(itemId, dateHint, clazz, 
Collections.singletonMap(propertyName, propertyValue))}
+     *
+     * @param itemId        the identifier of the item we want to update
+     * @param dateHint      a Date helping in identifying where the item is 
located
+     * @param clazz         the Item subclass of the item to update
+     * @param propertyName  the name of the property to update
+     * @param propertyValue the new value of the property
+     * @return {@code true} if the update was successful, {@code false} 
otherwise
+     */
+    boolean update(String itemId, Date dateHint, Class<?> clazz, String 
propertyName, Object propertyValue);
+
+    /**
+     * Updates the item of the specified class and identified by the specified 
identifier with a new property value for the specified property name. Same as
+     * {@code update(itemId, dateHint, clazz, 
Collections.singletonMap(propertyName, propertyValue))}
+     *
+     * @param itemId        the identifier of the item we want to update
+     * @param dateHint      a Date helping in identifying where the item is 
located
+     * @param clazz         the Item subclass of the item to update
+     * @param script        inline script
+     * @param scriptParams  script params
+     * @return {@code true} if the update was successful, {@code false} 
otherwise
+     */
+    boolean update(String itemId, Date dateHint, Class<?> clazz, String 
script, Map<String, Object> scriptParams);
+
+    /**
+     * Retrieves the item identified with the specified identifier and with 
the specified Item subclass if it exists.
+     *
+     * @param <T>    the type of the Item subclass we want to retrieve
+     * @param itemId the identifier of the item we want to retrieve
+     * @param clazz  the {@link Item} subclass of the item we want to retrieve
+     * @return the item identified with the specified identifier and with the 
specified Item subclass if it exists, {@code null} otherwise
+     */
+    <T extends Item> T load(String itemId, Class<T> clazz);
+
+    /**
+     * Retrieves the item identified with the specified identifier and with 
the specified Item subclass if it exists.
+     *
+     * @param <T>      the type of the Item subclass we want to retrieve
+     * @param itemId   the identifier of the item we want to retrieve
+     * @param dateHint a Date helping in identifying where the item is located
+     * @param clazz    the {@link Item} subclass of the item we want to 
retrieve
+     * @return the item identified with the specified identifier and with the 
specified Item subclass if it exists, {@code null} otherwise
+     */
+    <T extends Item> T load(String itemId, Date dateHint, Class<T> clazz);
+
+    /**
+     * Deletes the item identified with the specified identifier and with the 
specified Item subclass if it exists.
+     *
+     * @param <T>    the type of the Item subclass we want to delete
+     * @param itemId the identifier of the item we want to delete
+     * @param clazz  the {@link Item} subclass of the item we want to delete
+     * @return {@code true} if the deletion was successful, {@code false} 
otherwise
+     */
+    <T extends Item> boolean remove(String itemId, Class<T> clazz);
+
+    /**
+     * Deletes items with the specified Item subclass matching the specified 
{@link Condition}.
+     *
+     * @param <T>   the type of the Item subclass we want to delete
+     * @param query a {@link Condition} identifying which elements we want to 
delete
+     * @param clazz the {@link Item} subclass of the items we want to delete
+     * @return {@code true} if the deletion was successful, {@code false} 
otherwise
+     */
+    <T extends Item> boolean removeByQuery(Condition query, Class<T> clazz);
+
+    /**
+     * Persists the specified query under the specified name.
+     *
+     * @param queryName the name under which the specified query should be 
recorded
+     * @param query     the query to be recorded
+     * @return {@code true} if the query was properly saved, {@code false} 
otherwise
+     */
+    boolean saveQuery(String queryName, Condition query);
+
+    /**
+     * Deletes the query identified by the specified name.
+     *
+     * @param queryName the name under which the specified query was recorded
+     * @return {@code true} if the deletion was successful, {@code false} 
otherwise
+     */
+    boolean removeQuery(String queryName);
+
+    /**
+     * TODO
+     *
+     * @param itemType
+     * @return
+     */
+    Map<String, Map<String, Object>> getMapping(String itemType);
+
+    /**
+     * TODO
+     *
+     * @param item
+     * @return
+     */
+    List<String> getMatchingSavedQueries(Item item);
+
+    /**
+     * Checks whether the specified item satisfies the provided condition.
+     *
+     * TODO: rename to isMatching?
+     *
+     * @param query the condition we're testing the specified item against
+     * @param item  the item we're checking against the specified condition
+     * @return {@code true} if the item satisfies the condition, {@code false} 
otherwise
+     */
+    boolean testMatch(Condition query, Item item);
+
+    /**
+     * Same as {@code query(fieldName, fieldValue, sortBy, clazz, 0, 
-1).getList()}
+     *
+     * @see #query(Condition, String, Class, int, int)
+     */
+    <T extends Item> List<T> query(String fieldName, String fieldValue, String 
sortBy, Class<T> clazz);
+
+    /**
+     * Retrieves a list of items with the specified field having the specified 
values.
+     *
+     * @param <T>         the type of the Item subclass we want to retrieve
+     * @param fieldName   the name of the field which we want items to have 
the specified values
+     * @param fieldValues the values the items to retrieve should have for the 
specified field
+     * @param sortBy      an optional ({@code null} if no sorting is required) 
String of comma ({@code ,}) separated property names on which ordering should 
be performed, ordering
+     *                    elements according to the property order in the
+     *                    String, considering each in turn and moving on to 
the next one in case of equality of all preceding ones. Each property name is 
optionally followed by
+     *                    a column ({@code :}) and an order specifier: {@code 
asc} or {@code desc}.
+     * @param clazz       the {@link Item} subclass of the items we want to 
retrieve
+     * @return a list of items matching the specified criteria
+     */
+    <T extends Item> List<T> query(String fieldName, String[] fieldValues, 
String sortBy, Class<T> clazz);
+
+    /**
+     * Retrieves a list of items with the specified field having the specified 
value.
+     *
+     * @param <T>        the type of the Item subclass we want to retrieve
+     * @param fieldName  the name of the field which we want items to have the 
specified value
+     * @param fieldValue the value the items to retrieve should have for the 
specified field
+     * @param sortBy     an optional ({@code null} if no sorting is required) 
String of comma ({@code ,}) separated property names on which ordering should 
be performed, ordering
+     *                   elements according to the property order in the
+     *                   String, considering each in turn and moving on to the 
next one in case of equality of all preceding ones. Each property name is 
optionally followed by
+     *                   a column ({@code :}) and an order specifier: {@code 
asc} or {@code desc}.
+     * @param clazz      the {@link Item} subclass of the items we want to 
retrieve
+     * @return a {@link PartialList} of items matching the specified criteria
+     */
+    <T extends Item> PartialList<T> query(String fieldName, String fieldValue, 
String sortBy, Class<T> clazz, int offset, int size);
+
+    /**
+     * Retrieves a list of items with the specified field having the specified 
value and having at least a field with the specified full text value in it, 
ordered according to the
+     * specified {@code sortBy} String and and paged: only {@code size} of 
them are retrieved, starting with the {@code offset}-th one.
+     *
+     * @param <T>        the type of the Item subclass we want to retrieve
+     * @param fieldName  the name of the field which we want items to have the 
specified value
+     * @param fieldValue the value the items to retrieve should have for the 
specified field
+     * @param fulltext   the text that the item must have in one of its fields 
to be considered a match
+     * @param sortBy     an optional ({@code null} if no sorting is required) 
String of comma ({@code ,}) separated property names on which ordering should 
be performed, ordering
+     *                   elements according to the property order in the
+     *                   String, considering each in turn and moving on to the 
next one in case of equality of all preceding ones. Each property name is 
optionally followed by
+     *                   a column ({@code :}) and an order specifier: {@code 
asc} or {@code desc}.
+     * @param clazz      the {@link Item} subclass of the items we want to 
retrieve
+     * @param offset     zero or a positive integer specifying the position of 
the first item in the total ordered collection of matching items
+     * @param size       a positive integer specifying how many matching items 
should be retrieved or {@code -1} if all of them should be retrieved
+     * @return a {@link PartialList} of items matching the specified criteria
+     */
+    <T extends Item> PartialList<T> queryFullText(String fieldName, String 
fieldValue, String fulltext, String sortBy, Class<T> clazz, int offset, int 
size);
+
+    /**
+     * Retrieves a list of items having at least a field with the specified 
full text value in it, ordered according to the specified {@code sortBy} String 
and and paged: only
+     * {@code size} of them are retrieved, starting with the {@code offset}-th 
one.
+     *
+     * @param <T>      the type of the Item subclass we want to retrieve
+     * @param fulltext the text that the item must have in one of its fields 
to be considered a match
+     * @param sortBy   an optional ({@code null} if no sorting is required) 
String of comma ({@code ,}) separated property names on which ordering should 
be performed, ordering
+     *                 elements according to the property order in the
+     *                 String, considering each in turn and moving on to the 
next one in case of equality of all preceding ones. Each property name is 
optionally followed by
+     *                 a column ({@code :}) and an order specifier: {@code 
asc} or {@code desc}.
+     * @param clazz    the {@link Item} subclass of the items we want to 
retrieve
+     * @param offset   zero or a positive integer specifying the position of 
the first item in the total ordered collection of matching items
+     * @param size     a positive integer specifying how many matching items 
should be retrieved or {@code -1} if all of them should be retrieved
+     * @return a {@link PartialList} of items matching the specified criteria
+     */
+    <T extends Item> PartialList<T> queryFullText(String fulltext, String 
sortBy, Class<T> clazz, int offset, int size);
+
+    /**
+     * Same as {@code query(query, sortBy, clazz, 0, -1).getList()}
+     *
+     * @see #query(Condition, String, Class, int, int)
+     */
+    <T extends Item> List<T> query(Condition query, String sortBy, Class<T> 
clazz);
+
+    /**
+     * Retrieves a list of items satisfying the specified {@link Condition}, 
ordered according to the specified {@code sortBy} String and and paged: only 
{@code size} of them
+     * are retrieved, starting with the {@code offset}-th one.
+     *
+     * @param <T>    the type of the Item subclass we want to retrieve
+     * @param query  the {@link Condition} the items must satisfy to be 
retrieved
+     * @param sortBy an optional ({@code null} if no sorting is required) 
String of comma ({@code ,}) separated property names on which ordering should 
be performed, ordering
+     *               elements according to the property order in the
+     *               String, considering each in turn and moving on to the 
next one in case of equality of all preceding ones. Each property name is 
optionally followed by
+     *               a column ({@code :}) and an order specifier: {@code asc} 
or {@code desc}.
+     * @param clazz  the {@link Item} subclass of the items we want to retrieve
+     * @param offset zero or a positive integer specifying the position of the 
first item in the total ordered collection of matching items
+     * @param size   a positive integer specifying how many matching items 
should be retrieved or {@code -1} if all of them should be retrieved
+     * @return a {@link PartialList} of items matching the specified criteria
+     */
+    <T extends Item> PartialList<T> query(Condition query, String sortBy, 
Class<T> clazz, int offset, int size);
+
+    /**
+     * Retrieves the same items as {@code query(query, sortBy, clazz, 0, -1)} 
with the added constraints that the matching elements must also have at least a 
field matching the
+     * specified full text query.
+     *
+     * @param <T>      the type of the Item subclass we want to retrieve
+     * @param fulltext the text that the item must have in one of its fields 
to be considered a match
+     * @param query    the {@link Condition} the items must satisfy to be 
retrieved
+     * @param sortBy   an optional ({@code null} if no sorting is required) 
String of comma ({@code ,}) separated property names on which ordering should 
be performed, ordering
+     *                 elements according to the property order in the
+     *                 String, considering each in turn and moving on to the 
next one in case of equality of all preceding ones. Each property name is 
optionally followed by
+     *                 a column ({@code :}) and an order specifier: {@code 
asc} or {@code desc}.
+     * @param clazz    the {@link Item} subclass of the items we want to 
retrieve
+     * @param offset   zero or a positive integer specifying the position of 
the first item in the total ordered collection of matching items
+     * @param size     a positive integer specifying how many matching items 
should be retrieved or {@code -1} if all of them should be retrieved
+     * @return a {@link PartialList} of items matching the specified criteria
+     */
+    <T extends Item> PartialList<T> queryFullText(String fulltext, Condition 
query, String sortBy, Class<T> clazz, int offset, int size);
+
+    /**
+     * Retrieves the number of items of the specified type as defined by the 
Item subclass public field {@code ITEM_TYPE} and matching the specified {@link 
Condition}.
+     *
+     * @param query    the condition the items must satisfy
+     * @param itemType the String representation of the item type we want to 
retrieve the count of, as defined by its class' {@code ITEM_TYPE} field
+     * @return the number of items of the specified type
+     * @see Item Item for a discussion of {@code ITEM_TYPE}
+     */
+    long queryCount(Condition query, String itemType);
+
+    /**
+     * Retrieves the number of items with the specified type as defined by the 
Item subclass public field {@code ITEM_TYPE}.
+     *
+     * @param itemType the String representation of the item type we want to 
retrieve the count of, as defined by its class' {@code ITEM_TYPE} field
+     * @return the number of items of the specified type
+     * @see Item Item for a discussion of {@code ITEM_TYPE}
+     */
+    long getAllItemsCount(String itemType);
+
+    /**
+     * Retrieves the number of items with the specified type as defined by the 
Item subclass public field {@code ITEM_TYPE} matching the optional specified 
condition and
+     * aggregated according to the specified {@link BaseAggregate}.
+     *
+     * @param filter    the condition the items must match or {@code null} if 
no filtering is needed
+     * @param aggregate an aggregate specifying how matching items must be 
bundled
+     * @param itemType  the String representation of the item type we want to 
retrieve the count of, as defined by its class' {@code ITEM_TYPE} field
+     * @return a Map associating aggregation dimension name as key and 
cardinality for that dimension as value
+     */
+    Map<String, Long> aggregateQuery(Condition filter, BaseAggregate 
aggregate, String itemType);
+
+    /**
+     * Updates the persistence's engine indices if needed.
+     */
+    void refresh();
+
+    /**
+     * Purges all data in the context server up to the specified date, not 
included.
+     *
+     * @param date the date (not included) before which we want to erase all 
data
+     */
+    void purge(Date date);
+
+    /**
+     * Retrieves all items of the specified Item subclass which specified 
ranged property is within the specified bounds, ordered according to the 
specified {@code sortBy} String
+     * and and paged: only {@code size} of them are retrieved, starting with 
the {@code offset}-th one.
+     *
+     * @param <T>    the type of the Item subclass we want to retrieve
+     * @param s      the name of the range property we want items to retrieve 
to be included between the specified start and end points
+     * @param from   the beginning of the range we want to consider
+     * @param to     the end of the range we want to consider
+     * @param sortBy an optional ({@code null} if no sorting is required) 
String of comma ({@code ,}) separated property names on which ordering should 
be performed, ordering
+     *               elements according to the property order in the String, 
considering each in turn and moving on to the next one in case of equality of 
all preceding ones.
+     *               Each property name is optionally followed by a column 
({@code :}) and an order specifier: {@code asc} or {@code desc}.
+     * @param clazz  the {@link Item} subclass of the items we want to retrieve
+     * @param offset zero or a positive integer specifying the position of the 
first item in the total ordered collection of matching items
+     * @param size   a positive integer specifying how many matching items 
should be retrieved or {@code -1} if all of them should be retrieved
+     * @return a {@link PartialList} of items matching the specified criteria
+     */
+    <T extends Item> PartialList<T> rangeQuery(String s, String from, String 
to, String sortBy, Class<T> clazz, int offset, int size);
+
+    /**
+     * Retrieves the specified metrics for the specified field of items of the 
specified type as defined by the Item subclass public field {@code ITEM_TYPE} 
and matching the
+     * specified {@link Condition}.
+     *
+     * @param condition the condition the items must satisfy
+     * @param metrics   a String array which metrics should be computed 
(possible values: {@code sum} for the sum of the values,  {@code avg} for the 
average of the values, {@code
+     *                  min} for the minimum value and {@code max} for the 
maximum value)
+     * @param field     the name of the field for which the metrics should be 
computed
+     * @param type      the String representation of the item type we want to 
retrieve the count of, as defined by its class' {@code ITEM_TYPE} field
+     * @return a Map associating computed metric name as key to its associated 
value
+     */
+    Map<String, Double> getSingleValuesMetrics(Condition condition, String[] 
metrics, String field, String type);
+
+    /**
+     * Creates an index with the specified name in the persistence engine.
+     *
+     * TODO: remove from API?
+     *
+     * @param indexName the index name
+     * @return {@code true} if the operation was successful, {@code false} 
otherwise
+     */
+    boolean createIndex(final String indexName);
+
+    /**
+     * Removes the index with the specified name.
+     *
+     * TODO: remove from API?
+     *
+     * @param indexName the index name
+     * @return {@code true} if the operation was successful, {@code false} 
otherwise
+     */
+    boolean removeIndex(final String indexName);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PropertyHelper.java
----------------------------------------------------------------------
diff --git 
a/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PropertyHelper.java
 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PropertyHelper.java
new file mode 100644
index 0000000..5b24a62
--- /dev/null
+++ 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PropertyHelper.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.unomi.persistence.spi;
+
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.beanutils.expression.DefaultResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+/**
+ * Helper method for properties
+ */
+public class PropertyHelper {
+
+    private static final Logger logger = 
LoggerFactory.getLogger(PropertyHelper.class.getName());
+    private static DefaultResolver resolver = new DefaultResolver();
+
+    public static boolean setProperty(Object target, String propertyName, 
Object propertyValue, String setPropertyStrategy) {
+        try {
+            while (resolver.hasNested(propertyName)) {
+                Object v = PropertyUtils.getProperty(target, 
resolver.next(propertyName));
+                if (v == null) {
+                    v = new LinkedHashMap<>();
+                    PropertyUtils.setProperty(target, 
resolver.next(propertyName), v);
+                }
+                propertyName = resolver.remove(propertyName);
+                target = v;
+            }
+
+            if (setPropertyStrategy != null && 
setPropertyStrategy.equals("addValue")) {
+                Object previousValue = PropertyUtils.getProperty(target, 
propertyName);
+                List<Object> values = new ArrayList<>();
+                if (previousValue != null && previousValue instanceof List) {
+                    values.addAll((List) previousValue);
+                } else if (previousValue != null) {
+                    values.add(previousValue);
+                }
+                if (!values.contains(propertyValue)) {
+                    values.add(propertyValue);
+                    BeanUtils.setProperty(target, propertyName, values);
+                    return true;
+                }
+            } else if (propertyValue != null && 
!propertyValue.equals(BeanUtils.getProperty(target, propertyName))) {
+                if (setPropertyStrategy == null ||
+                        setPropertyStrategy.equals("alwaysSet") ||
+                        (setPropertyStrategy.equals("setIfMissing") && 
BeanUtils.getProperty(target, propertyName) == null)) {
+                    BeanUtils.setProperty(target, propertyName, propertyValue);
+                    return true;
+                }
+            }
+        } catch (IllegalAccessException | InvocationTargetException | 
NoSuchMethodException e) {
+            logger.error("Cannot set property", e);
+        }
+        return false;
+    }
+
+    public static Integer getInteger(Object value) {
+        if (value instanceof Number) {
+            return ((Number)value).intValue();
+        } else {
+            try {
+                return Integer.parseInt(value.toString());
+            } catch (NumberFormatException e) {
+                // Not a number
+            }
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PropertyTypedObjectDeserializer.java
----------------------------------------------------------------------
diff --git 
a/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PropertyTypedObjectDeserializer.java
 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PropertyTypedObjectDeserializer.java
new file mode 100644
index 0000000..f9d2613
--- /dev/null
+++ 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/PropertyTypedObjectDeserializer.java
@@ -0,0 +1,114 @@
+/*
+ * 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.persistence.spi;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonTokenId;
+import com.fasterxml.jackson.core.ObjectCodec;
+import com.fasterxml.jackson.core.TreeNode;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * This Jackson deserializer makes it possible to register field matching
+ * regular expressions that can be matched to class names, as in the following
+ * example:
+ *
+ *            SimpleModule deserializerModule =
+ *                  new SimpleModule("PropertyTypedObjectDeserializerModule",
+ *                      new Version(1, 0, 0, null, "org.apache.unomi.rest", 
"deserializer"));
+ *            PropertyTypedObjectDeserializer propertyTypedObjectDeserializer 
= new PropertyTypedObjectDeserializer();
+ *            
propertyTypedObjectDeserializer.registerMapping("type=.*Condition", 
Condition.class);
+ *            deserializerModule.addDeserializer(Object.class, 
propertyTypedObjectDeserializer);
+ *            objectMapper.registerModule(deserializerModule);
+ *
+ * In this example any JSON object that has a "type" property that matches the
+ * ".*Condition" regular expression will be parsed and mapped to a Condition 
class
+ *
+ * Note that there exists a way to map properties as type identifiers in 
Jackson,
+ * but this feature is very limited and requires hardcoding possible values.
+ * This deserializer is much more flexible and powerful.
+ */
+public class PropertyTypedObjectDeserializer extends UntypedObjectDeserializer 
{
+
+    private static final long serialVersionUID = -2561171359946902967L;
+
+    private Map<String, Class<? extends Object>> registry =
+            new LinkedHashMap<String, Class<? extends Object>>();
+
+    private Map<String,Set<String>> fieldValuesToMatch = new 
LinkedHashMap<String,Set<String>>();
+
+    public void registerMapping(String matchExpression,
+                                Class<? extends Object> mappedClass) {
+        registry.put(matchExpression, mappedClass);
+        String[] fieldParts = matchExpression.split("=");
+        Set<String> valuesToMatch = fieldValuesToMatch.get(fieldParts[0]);
+        if (valuesToMatch == null) {
+            valuesToMatch = new LinkedHashSet<String>();
+        }
+        valuesToMatch.add(fieldParts[1]);
+        fieldValuesToMatch.put(fieldParts[0], valuesToMatch);
+    }
+
+    @Override
+    public Object deserialize(
+            JsonParser jp, DeserializationContext ctxt)
+            throws IOException {
+        if (jp.getCurrentTokenId() != JsonTokenId.ID_START_OBJECT) {
+            return super.deserialize(jp, ctxt);
+        }
+        ObjectCodec codec = jp.getCodec();
+        TreeNode treeNode = codec.readTree(jp);
+        Class<? extends Object> objectClass = null;
+        if (treeNode instanceof ObjectNode) {
+            ObjectNode root = (ObjectNode) treeNode;
+            Iterator<Map.Entry<String, JsonNode>> elementsIterator =
+                    root.fields();
+            while (elementsIterator.hasNext()) {
+                Map.Entry<String, JsonNode> element = elementsIterator.next();
+                String name = element.getKey();
+                if (fieldValuesToMatch.containsKey(name)) {
+                    Set<String> valuesToMatch = fieldValuesToMatch.get(name);
+                    for (String valueToMatch : valuesToMatch) {
+                        if (element.getValue().asText().matches(valueToMatch)) 
{
+                            objectClass = registry.get(name + "=" + 
valueToMatch);
+                            break;
+                        }
+                    }
+                    if (objectClass != null) {
+                        break;
+                    }
+                }
+            }
+            if (objectClass == null) {
+                objectClass = HashMap.class;
+            }
+        } else {
+
+        }
+        if (objectClass == null) {
+            return super.deserialize(codec.treeAsTokens(treeNode), ctxt);
+        }
+        return codec.treeToValue(treeNode, objectClass);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-unomi/blob/dc1d1520/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/aggregate/BaseAggregate.java
----------------------------------------------------------------------
diff --git 
a/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/aggregate/BaseAggregate.java
 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/aggregate/BaseAggregate.java
new file mode 100644
index 0000000..4bd26a2
--- /dev/null
+++ 
b/persistence-spi/src/main/java/org/apache/unomi/persistence/spi/aggregate/BaseAggregate.java
@@ -0,0 +1,30 @@
+/*
+ * 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.persistence.spi.aggregate;
+
+public abstract class BaseAggregate {
+    private String field;
+
+    public BaseAggregate(String field) {
+        this.field = field;
+    }
+
+    public String getField() {
+        return field;
+    }
+}

Reply via email to