http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/etcd/src/test/java/org/apache/tamaya/etcd/EtcdAccessorTest.java
----------------------------------------------------------------------
diff --git 
a/modules/etcd/src/test/java/org/apache/tamaya/etcd/EtcdAccessorTest.java 
b/modules/etcd/src/test/java/org/apache/tamaya/etcd/EtcdAccessorTest.java
new file mode 100644
index 0000000..630a028
--- /dev/null
+++ b/modules/etcd/src/test/java/org/apache/tamaya/etcd/EtcdAccessorTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.tamaya.etcd;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.net.MalformedURLException;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for the etcd backend integration. You must have setCurrent a system 
property so, theses tests are executed, e.g.
+ * {@code -Detcd.url=http://127.0.0.1:4001}.
+ */
+public class EtcdAccessorTest {
+
+    private static EtcdAccessor accessor;
+    static boolean execute = false;
+
+    @BeforeClass
+    public static void setup() throws MalformedURLException {
+        accessor = new EtcdAccessor("http://192.168.99.105:4001";);
+        if(!accessor.getVersion().contains("etcd")){
+            System.out.println("Disabling etcd tests, etcd not accessible at: 
" + System.getProperty("etcd.server.urls"));
+            System.out.println("Configure etcd with 
-Detcd.server.urls=http://<IP>:<PORT>");
+        }
+        else{
+            execute = true;
+        }
+    }
+
+    @Test
+    public void testGetVersion() throws Exception {
+        if(!execute)return;
+        assertEquals(accessor.getVersion(), "etcd 0.4.9");
+    }
+
+    @Test
+    public void testGet() throws Exception {
+        if(!execute)return;
+        Map<String,String> result = accessor.get("test1");
+        assertNotNull(result);
+    }
+
+    @Test
+    public void testSetNormal() throws Exception {
+        if(!execute)return;
+        String value = UUID.randomUUID().toString();
+        Map<String,String> result = accessor.set("testSetNormal", value);
+        assertNull(result.get("_testSetNormal.ttl"));
+        assertEquals(value, 
accessor.get("testSetNormal").get("testSetNormal"));
+    }
+
+    @Test
+    public void testSetNormal2() throws Exception {
+        if(!execute)return;
+        String value = UUID.randomUUID().toString();
+        Map<String,String> result = accessor.set("testSetNormal2", value, 
null);
+        assertNull(result.get("_testSetNormal2.ttl"));
+        assertEquals(value, 
accessor.get("testSetNormal2").get("testSetNormal2"));
+    }
+
+    @Test
+    public void testSetWithTTL() throws Exception {
+        if(!execute)return;
+        String value = UUID.randomUUID().toString();
+        Map<String,String> result = accessor.set("testSetWithTTL", value, 1);
+        assertNotNull(result.get("_testSetWithTTL.ttl"));
+        assertEquals(value, 
accessor.get("testSetWithTTL").get("testSetWithTTL"));
+        Thread.sleep(2000L);
+        result = accessor.get("testSetWithTTL");
+        assertNull(result.get("testSetWithTTL"));
+    }
+
+    @Test
+    public void testDelete() throws Exception {
+        if(!execute)return;
+        String value = UUID.randomUUID().toString();
+        Map<String,String> result = accessor.set("testDelete", value, null);
+        assertEquals(value, accessor.get("testDelete").get("testDelete"));
+        assertNotNull(result.get("_testDelete.createdIndex"));
+        result = accessor.delete("testDelete");
+        assertEquals(value, result.get("_testDelete.prevNode.createValue"));
+        assertNull(accessor.get("testDelete").get("testDelete"));
+    }
+
+    @Test
+    public void testGetProperties() throws Exception {
+        if(!execute)return;
+        String value = UUID.randomUUID().toString();
+        accessor.set("testGetProperties1", value);
+        Map<String,String> result = accessor.getProperties("");
+        assertNotNull(result);
+        assertEquals(value, result.get("testGetProperties1"));
+        assertNotNull(result.get("_testGetProperties1.createdIndex"));
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/etcd/src/test/java/org/apache/tamaya/etcd/EtcdPropertySourceTest.java
----------------------------------------------------------------------
diff --git 
a/modules/etcd/src/test/java/org/apache/tamaya/etcd/EtcdPropertySourceTest.java 
b/modules/etcd/src/test/java/org/apache/tamaya/etcd/EtcdPropertySourceTest.java
new file mode 100644
index 0000000..8b6569f
--- /dev/null
+++ 
b/modules/etcd/src/test/java/org/apache/tamaya/etcd/EtcdPropertySourceTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.tamaya.etcd;
+
+import org.apache.tamaya.spi.PropertyValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Created by atsticks on 07.01.16.
+ */
+public class EtcdPropertySourceTest {
+
+    private final EtcdPropertySource propertySource = new EtcdPropertySource();
+
+    @BeforeClass
+    public static void setup(){
+        System.setProperty("etcd.server.urls", 
"http://8.8.8.8:4001,http://192.168.99.105:4001";);
+    }
+
+    @Test
+    public void testGetOrdinal() throws Exception {
+        assertEquals(1000, propertySource.getOrdinal());
+    }
+
+    @Test
+    public void testGetDefaultOrdinal() throws Exception {
+        assertEquals(1000, propertySource.getDefaultOrdinal());
+    }
+
+    @Test
+    public void testGetName() throws Exception {
+        assertEquals("etcd", propertySource.getName());
+    }
+
+    @Test
+    public void testGet() throws Exception {
+        Map<String,PropertyValue> props = propertySource.getProperties();
+        for(Map.Entry<String,PropertyValue> en:props.entrySet()){
+            assertNotNull("Key not found: " + en.getKey(), 
propertySource.get(en.getKey()));
+        }
+    }
+
+    @Test
+    public void testGetProperties() throws Exception {
+        Map<String,PropertyValue> props = propertySource.getProperties();
+        assertNotNull(props);
+    }
+
+    @Test
+    public void testIsScannable() throws Exception {
+        assertTrue(propertySource.isScannable());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/hazelcast/bnd.bnd
----------------------------------------------------------------------
diff --git a/modules/hazelcast/bnd.bnd b/modules/hazelcast/bnd.bnd
new file mode 100644
index 0000000..22db283
--- /dev/null
+++ b/modules/hazelcast/bnd.bnd
@@ -0,0 +1,29 @@
+-buildpath: \
+       osgi.annotation; version=6.0.0,\
+       osgi.core; version=6.0,\
+       osgi.cmpn; version=6.0
+
+-testpath: \
+       ${junit}
+
+javac.source: 1.8
+javac.target: 1.8
+
+Automatic-Module-Name: org.apache.tamaya.hazelcast
+Bundle-Version: ${version}.${tstamp}
+Bundle-Name: Apache Tamaya - Hazelcast Config
+Bundle-SymbolicName: org.apache.tamaya.hazelcast
+Bundle-Description: Apacha Tamaya Config - Hazelcast PropertySource
+Bundle-Category: Implementation
+Bundle-Copyright: (C) Apache Foundation
+Bundle-License: Apache Licence version 2
+Bundle-Vendor: Apache Software Foundation
+Bundle-ContactAddress: [email protected]
+Bundle-DocURL: http://tamaya.apache.org
+Export-Package: \
+       org.apache.tamaya.hazelcast
+Import-Package: \
+    org.apache.tamaya,\
+    org.apache.tamaya.spi
+Export-Service: \
+    org.apache.tamaya.spi.PropertySource

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/hazelcast/pom.xml
----------------------------------------------------------------------
diff --git a/modules/hazelcast/pom.xml b/modules/hazelcast/pom.xml
new file mode 100644
index 0000000..af7bced
--- /dev/null
+++ b/modules/hazelcast/pom.xml
@@ -0,0 +1,77 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~  or more contributor license agreements.  See the NOTICE file
+  ~  distributed with this work for additional information
+  ~  regarding copyright ownership.  The ASF licenses this file
+  ~  to you under the Apache License, Version 2.0 (the
+  ~  "License"); you may not use this file except in compliance
+  ~  with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing,
+  ~  software distributed under the License is distributed on an
+  ~  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~  KIND, either express or implied.  See the License for the
+  ~  specific language governing permissions and limitations
+  ~  under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.tamaya.ext</groupId>
+        <artifactId>tamaya-sandbox</artifactId>
+        <version>0.4-incubating-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+
+    <artifactId>tamaya-hazelcast</artifactId>
+    <name>Apache Tamaya Modules - Hazelcast PropertySource</name>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>java-hamcrest</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tamaya</groupId>
+            <artifactId>tamaya-core</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tamaya</groupId>
+            <artifactId>tamaya-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tamaya.ext</groupId>
+            <artifactId>tamaya-functions</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tamaya</groupId>
+            <artifactId>tamaya-spisupport</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.hazelcast</groupId>
+            <artifactId>hazelcast</artifactId>
+            <version>3.5.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tamaya.ext</groupId>
+            <artifactId>tamaya-mutable-config</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+    </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/hazelcast/src/main/java/org/apache/tamaya/hazelcast/AbstractHazelcastPropertySource.java
----------------------------------------------------------------------
diff --git 
a/modules/hazelcast/src/main/java/org/apache/tamaya/hazelcast/AbstractHazelcastPropertySource.java
 
b/modules/hazelcast/src/main/java/org/apache/tamaya/hazelcast/AbstractHazelcastPropertySource.java
new file mode 100644
index 0000000..117bb2c
--- /dev/null
+++ 
b/modules/hazelcast/src/main/java/org/apache/tamaya/hazelcast/AbstractHazelcastPropertySource.java
@@ -0,0 +1,238 @@
+/*
+ * 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.tamaya.hazelcast;
+
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.core.IList;
+import com.hazelcast.core.IMap;
+import org.apache.tamaya.mutableconfig.ConfigChangeRequest;
+import org.apache.tamaya.mutableconfig.spi.MutablePropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spisupport.propertysource.BasePropertySource;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Distributed Propertysource using a in-memory hazelcast cluster.
+ * Created by atsticks on 03.11.16.
+ *
+ * Basically all kind of property entris can be stored. Additionally this 
property source allows
+ * to pass additional getMeta-entries to control the TTL of the data in 
milliseconds. For illustration
+ * the following map will store {@code my.entry} with a TLL of 20000 
milliseconds (20 seconds) and
+ * store {@code my.otherEntry} with infinite lifetime (as long as the cluster 
is alive):
+ *
+ * {@code
+ *     my.entry=myvalue
+ *     _my.entry.ttl=20000
+ *     my.otherEntry=1234
+ * }
+ *
+ * By default a new hazelcast instance is created, but it is also possible to 
reuse an existing
+ * instance of pass a Hazelcast configuration instance.
+ */
+public abstract class AbstractHazelcastPropertySource extends 
BasePropertySource
+implements MutablePropertySource{
+    /** The logger. */
+    private static final Logger LOG = 
Logger.getLogger(AbstractHazelcastPropertySource.class.getName());
+    /** The Hazelcast config map used. */
+    private Map<String, PropertyValue> configMap = new HashMap<>();
+    /** The hazelcast map reference ID used, by default {@code 
tamaya.configuration}. */
+    private String mapReference = "tamaya.configuration";
+    /** Flag if this property source is read-only. */
+    private boolean readOnly = false;
+
+    private AtomicLong timeoutDuration = new 
AtomicLong(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES));
+
+    private AtomicLong timeout = new AtomicLong();
+
+    /**
+     * Creates a new instance, hereby using {@code "Hazelcast"} as property 
source name and
+     * a default hazelcast backend created by calling {@link 
Hazelcast#newHazelcastInstance()}.
+     */
+    public AbstractHazelcastPropertySource(){
+        super("Hazelcast");
+    }
+
+    /**
+     * Creates a new instance, hereby using the given property source name and
+     * a default hazelcast backend created by calling {@link 
Hazelcast#newHazelcastInstance()}.
+     * @param name the property source name, not null.
+     */
+    public AbstractHazelcastPropertySource(String name){
+        super(name);
+    }
+
+    /**
+     * Get the current timeout, when a reload will be triggered on access.
+     * @return the current timeout, or 0 if no data has been loaded at all.
+     */
+    public long getValidUntil(){
+        return timeout.get();
+    }
+
+    /**
+     * Get the current cache timeout.
+     * @return the timeout duration after which data will be reloaded.
+     */
+    public long getCachePeriod(){
+        return timeoutDuration.get();
+    }
+
+    /**
+     * Set the duration after which the data cache will be reloaded.
+     * @param millis the millis
+     */
+    public void setCacheTimeout(long millis){
+        this.timeoutDuration.set(millis);
+        this.refresh();
+    }
+
+
+    /**
+     * Setting the read-only flag for this instance.
+     * @param readOnly if true, the property source will not write back any 
changes to the
+     *                 hazelcast backend.
+     */
+    public void setReadOnly(boolean readOnly){
+        this.readOnly = readOnly;
+    }
+
+    /**
+     * Flag to check if the property source is read-only.
+     * @return true, if the instance is read-only.
+     */
+    public boolean isReadOnly(){
+        return readOnly;
+    }
+
+    /**
+     * Set the Hazelcast reference name for the Tamaya configuration Map.
+     * @param mapReference the map reference to be used, not null.
+     */
+    public void setMapReference(String mapReference){
+        if (!Objects.equals(mapReference, this.mapReference)) {
+            this.mapReference = Objects.requireNonNull(mapReference);
+            refresh();
+        }
+    }
+
+    /**
+     * Get the Hazelcast reference name for the Tamaya configuration Map.
+     * @return the Hazelcast reference name for the Tamaya configuration Map, 
never null.
+     */
+    public String getMapReference(){
+        return mapReference;
+    }
+
+    /**
+     * Get access to the hazelcast instance used.
+     * @return the hazelcast instance, not null.
+     */
+    protected abstract HazelcastInstance getHazelcastInstance();
+
+    @Override
+    public PropertyValue get(String key) {
+        checkRefresh();
+        return this.configMap.get(key);
+    }
+
+    @Override
+    public Map<String, PropertyValue> getProperties() {
+        checkRefresh();
+        return this.configMap;
+    }
+
+    /**
+     * Checks for a cache timeout and optionally reloads the data.
+     */
+    public void checkRefresh(){
+        if(this.timeout.get() < System.currentTimeMillis()){
+            refresh();
+        }
+    }
+
+    /**
+     * Reloads the configuration map from Hazelcast completely.
+     */
+    public void refresh() {
+        IMap<String,String> config = 
getHazelcastInstance().getMap(mapReference);
+        Map<String, PropertyValue> configMap = new HashMap<>();
+        config.entrySet().forEach(en -> {
+            configMap.put(en.getKey(),
+            PropertyValue.createValue(en.getKey(), en.getValue())
+                    .setMeta("source", getName())
+                    .setMeta("backend", "Hazelcast")
+                    .setMeta("instance", getHazelcastInstance().getName())
+                    .setMeta("mapReference", mapReference)
+                    .immutable());
+        });
+        this.timeout.set(System.currentTimeMillis() + timeoutDuration.get());
+        this.configMap = Collections.unmodifiableMap(configMap);
+    }
+
+    @Override
+    public void applyChange(ConfigChangeRequest configChange) {
+        if(readOnly){
+            return;
+        }
+        IMap<String,String> config = 
getHazelcastInstance().getMap(mapReference);
+        for(Map.Entry<String, String> en: 
configChange.getAddedProperties().entrySet()){
+            String metaVal = configChange.getAddedProperties().get("_" + 
en.getKey()+".ttl");
+            if(metaVal!=null){
+                try {
+                    long ms = Long.parseLong(metaVal);
+                    config.put(en.getKey(), en.getValue(), ms, 
TimeUnit.MILLISECONDS);
+                }catch(Exception e){
+                    LOG.log(Level.WARNING, "Failed to parse TTL in millis: " + 
metaVal +
+                            " for '"+ en.getKey()+"'", e);
+                    config.put(en.getKey(), en.getValue());
+                }
+            }else {
+                config.put(en.getKey(), en.getValue());
+            }
+        }
+        for(String key: configChange.getRemovedProperties()){
+            config.remove(key);
+        }
+        IList<String> taList = 
getHazelcastInstance().getList("[META]tamaya.transactions");
+        taList.add(configChange.getTransactionID());
+        config.put("[META]tamaya.transaction.lastId", 
configChange.getTransactionID(), 1, TimeUnit.DAYS);
+        config.put("[META]tamaya.transaction.startedAt", 
String.valueOf(configChange.getStartedAt()), 1, TimeUnit.DAYS);
+        config.flush();
+        refresh();
+    }
+
+    @Override
+    protected String toStringValues() {
+        return super.toStringValues() +
+                "\n  hazelcastInstance=" + getHazelcastInstance() +
+                "\n  name='" + getName() + '\'' +
+                "\n  mapReference='" + mapReference + '\'' +
+                "\n  readOnly=" + readOnly + '\'';
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/hazelcast/src/main/java/org/apache/tamaya/hazelcast/HazelcastPropertySource.java
----------------------------------------------------------------------
diff --git 
a/modules/hazelcast/src/main/java/org/apache/tamaya/hazelcast/HazelcastPropertySource.java
 
b/modules/hazelcast/src/main/java/org/apache/tamaya/hazelcast/HazelcastPropertySource.java
new file mode 100644
index 0000000..58b3617
--- /dev/null
+++ 
b/modules/hazelcast/src/main/java/org/apache/tamaya/hazelcast/HazelcastPropertySource.java
@@ -0,0 +1,119 @@
+/*
+ * 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.tamaya.hazelcast;
+
+import com.hazelcast.config.Config;
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.core.IList;
+import com.hazelcast.core.IMap;
+import org.apache.tamaya.mutableconfig.ConfigChangeRequest;
+import org.apache.tamaya.mutableconfig.spi.MutablePropertySource;
+import org.apache.tamaya.spi.PropertyValue;
+import org.apache.tamaya.spisupport.propertysource.BasePropertySource;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Distributed Propertysource using a in-memory hazelcast cluster.
+ * Created by atsticks on 03.11.16.
+ *
+ * Basically all kind of property entris can be stored. Additionally this 
property source allows
+ * to pass additional getMeta-entries to control the TTL of the data in 
milliseconds. For illustration
+ * the following map will store {@code my.entry} with a TLL of 20000 
milliseconds (20 seconds) and
+ * store {@code my.otherEntry} with infinite lifetime (as long as the cluster 
is alive):
+ *
+ * {@code
+ *     my.entry=myvalue
+ *     _my.entry.ttl=20000
+ *     my.otherEntry=1234
+ * }
+ *
+ * By default a new hazelcast instance is created, but it is also possible to 
reuse an existing
+ * instance of pass a Hazelcast configuration instance.
+ */
+public class HazelcastPropertySource extends AbstractHazelcastPropertySource {
+
+    /** The hazelcast API instance. */
+    private HazelcastInstance hazelcastInstance;
+
+    /**
+     * Creates a new instance, hereby using {@code "Hazelcast"} as property 
source name and
+     * a default hazelcast backend created by calling {@link 
Hazelcast#newHazelcastInstance()}.
+     */
+    public HazelcastPropertySource(){
+        this.hazelcastInstance = Hazelcast.newHazelcastInstance();
+    }
+
+    /**
+     * Creates a new instance, hereby using {@code "Hazelcast"} as property 
source name and the
+     * given hazelcast instance.
+     * @param hazelcastInstance the hazelcast instance, not null.
+     */
+    public HazelcastPropertySource(HazelcastInstance hazelcastInstance){
+        this("Hazelcast", hazelcastInstance);
+    }
+
+    /**
+     * Creates a new instance, hereby using the given property source name and
+     * a default hazelcast backend created by calling {@link 
Hazelcast#newHazelcastInstance()}.
+     * @param name the property source name, not null.
+     */
+    public HazelcastPropertySource(String name){
+        super(name);
+        this.hazelcastInstance = Hazelcast.newHazelcastInstance();
+    }
+
+    /**
+     * Creates a new instance, hereby using the given property source name and
+     * a creating a new hazelcast backend using the given Hazelcast {@link 
Config}.
+     * @param config the hazelcast config, not null.
+     * @param name the property source name, not null.
+     */
+    public HazelcastPropertySource(String name, Config config){
+        super(name);
+        this.hazelcastInstance = Hazelcast.newHazelcastInstance(config);
+    }
+
+    /**
+     * Creates a new instance, hereby using the given property source name and 
the
+     * hazelcast instance.
+     * @param name the property source name, not null.
+     * @param hazelcastInstance the hazelcast instance, not null.
+     */
+    public HazelcastPropertySource(String name, HazelcastInstance 
hazelcastInstance){
+        super(name);
+        this.hazelcastInstance = Objects.requireNonNull(hazelcastInstance);
+    }
+
+    /**
+     * Get access to the hazelcast instance used.
+     * @return the hazelcast instance, not null.
+     */
+    @Override
+    public HazelcastInstance getHazelcastInstance() {
+        return hazelcastInstance;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/AbstractHzPropertySourceTest.java
----------------------------------------------------------------------
diff --git 
a/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/AbstractHzPropertySourceTest.java
 
b/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/AbstractHzPropertySourceTest.java
new file mode 100644
index 0000000..57d4e59
--- /dev/null
+++ 
b/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/AbstractHzPropertySourceTest.java
@@ -0,0 +1,207 @@
+/*
+ * 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.tamaya.hazelcast;
+
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.core.IMap;
+import org.apache.tamaya.spi.PropertyValue;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by atsticks on 03.11.16.
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class AbstractHzPropertySourceTest {
+
+    private static HazelcastInstance hz = HazelcastUtil.getHazelcastInstance();
+    private AbstractHazelcastPropertySource hps = new 
AbstractHazelcastPropertySource() {
+        @Override
+        protected HazelcastInstance getHazelcastInstance() {
+            return HazelcastUtil.getHazelcastInstance();
+        }
+    };
+
+    @BeforeClass
+    public static void start() {
+        IMap<Object, Object> map = hz.getMap("config");
+        map.put("k1", "v1");
+        map.put("k2", "v2");
+        map.put("tamaya.ordinal", "2000");
+        map.flush();
+        IMap<Object, Object> map2 = hz.getMap("config2");
+        map2.put("key1", "val1");
+        map2.put("key2", "val2");
+        map2.flush();
+    }
+
+    @org.junit.Test
+    public void t01_testGetProperties(){
+        hps.setMapReference("config");
+        Map<String, PropertyValue> values = hps.getProperties();
+        assertNotNull(values);
+        assertEquals(3, values.size());
+        assertNotNull(values.get("k1"));
+        assertNotNull(values.get("k2"));
+        assertEquals("v1", values.get("k1").getValue());
+        assertEquals("v2", values.get("k2").getValue());
+        assertEquals(hps.getOrdinal(), 2000);
+
+        hps.setMapReference("config2");
+        Map<String, PropertyValue> values2 = hps.getProperties();
+        assertNotNull(values2);
+        assertEquals(2, values2.size());
+        assertNotNull(values2.get("key1"));
+        assertNotNull(values2.get("key2"));
+        assertEquals("val1", values2.get("key1").getValue());
+        assertEquals("val2", values2.get("key2").getValue());
+        assertEquals(hps.getOrdinal(), 0);
+
+        hps.setMapReference("foo");
+        hps.setDefaultOrdinal(1500);
+        Map<String, PropertyValue> values3 = hps.getProperties();
+        assertNotNull(values3);
+        assertEquals(0, values3.size());
+        assertEquals(hps.getOrdinal(), 1500);
+    }
+
+    @org.junit.Test
+    public void t02_testGetOrdinal(){
+        hps.setMapReference("config");
+        hps.setDefaultOrdinal(1500);
+        assertEquals(1500, hps.getDefaultOrdinal());
+        assertEquals(hps.getOrdinal(), 2000);
+
+        hps.setMapReference("config2");
+        hps.setDefaultOrdinal(0);
+        assertEquals(0, hps.getDefaultOrdinal());
+        assertEquals(hps.getOrdinal(), 0);
+
+        hps.setMapReference("foo");
+        hps.setDefaultOrdinal(1500);
+        assertEquals(1500, hps.getDefaultOrdinal());
+        assertEquals(hps.getOrdinal(), 1500);
+    }
+
+    @org.junit.Test
+    public void t03_tesGet(){
+        hps.setMapReference("config");
+        PropertyValue val1 = hps.get("k1");
+        assertNotNull(val1);
+        assertEquals("v1", val1.getValue());
+        PropertyValue val2 = hps.get("k2");
+        assertNotNull(val2);
+        assertEquals("v2", val2.getValue());
+
+        hps.setMapReference("config2");
+        val1 = hps.get("key1");
+        assertNotNull(val1);
+        assertEquals("val1", val1.getValue());
+        val2 = hps.get("key2");
+        assertNotNull(val2);
+        assertEquals("val2", val2.getValue());
+
+        hps.setMapReference("foo");
+        val1 = hps.get("key1");
+        assertNull(val1);
+        val1 = hps.get("k1");
+        assertNull(val1);
+    }
+
+    @org.junit.Test
+    public void t03_tesGetMapReference(){
+        hps.setMapReference("config");
+        assertEquals("config", hps.getMapReference());
+
+        hps.setMapReference("config2");
+        assertEquals("config2", hps.getMapReference());
+    }
+
+    @org.junit.Test
+    public void t03_tesGetSetName(){
+        hps.setMapReference("config");
+        assertEquals("config", hps.getMapReference());
+        assertEquals("Hazelcast", hps.getName());
+
+        hps.setMapReference("config2");
+        hps.setName("foo");
+        assertEquals("config2", hps.getMapReference());
+        assertEquals("foo", hps.getName());
+    }
+
+    @org.junit.Test
+    public void t04_testCache() throws InterruptedException {
+        hps.setCacheTimeout(50L);
+        assertTrue(hps.getValidUntil()>= System.currentTimeMillis());
+        assertEquals(50L, hps.getCachePeriod());
+        hps.setMapReference("config");
+        hps.setDefaultOrdinal(200);
+        Map<String, PropertyValue> values = hps.getProperties();
+        assertNotNull(values);
+        assertEquals(3, values.size());
+        assertNotNull(values.get("k1"));
+        assertNotNull(values.get("k2"));
+        assertEquals("v1", values.get("k1").getValue());
+        assertEquals("v2", values.get("k2").getValue());
+        assertEquals(hps.getOrdinal(), 2000);
+
+        IMap<Object, Object> map = hz.getMap("config");
+        map.put("k3", "v3");
+        map.remove("tamaya.ordinal");
+        map.flush();
+
+        // Read from cache
+        assertEquals(50L, hps.getCachePeriod());
+        assertTrue(hps.getValidUntil()>= System.currentTimeMillis());
+        values = hps.getProperties();
+        assertNotNull(values);
+        assertEquals(3, values.size());
+        assertNotNull(values.get("k1"));
+        assertNotNull(values.get("k2"));
+        assertEquals("v1", values.get("k1").getValue());
+        assertEquals("v2", values.get("k2").getValue());
+        assertEquals(hps.getOrdinal(), 2000);
+
+        // Let cache timeout
+        Thread.sleep(300L);
+
+        // Read updated values
+        values = hps.getProperties();
+        assertNotNull(values);
+        assertEquals(3, values.size());
+        assertNotNull(values.get("k1"));
+        assertNotNull(values.get("k2"));
+        assertNotNull(values.get("k3"));
+        assertEquals("v1", values.get("k1").getValue());
+        assertEquals("v2", values.get("k2").getValue());
+        assertEquals("v3", values.get("k3").getValue());
+        assertEquals(hps.getOrdinal(), 200);
+    }
+
+    @AfterClass
+    public static void end(){
+        HazelcastUtil.shutdown();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/HazelcastUtil.java
----------------------------------------------------------------------
diff --git 
a/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/HazelcastUtil.java
 
b/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/HazelcastUtil.java
new file mode 100644
index 0000000..87c82ca
--- /dev/null
+++ 
b/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/HazelcastUtil.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.tamaya.hazelcast;
+
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Simple test util o manage Hazelcast.
+ */
+public final class HazelcastUtil {
+
+    private static HazelcastInstance hz;
+    private static AtomicInteger accessCounter = new AtomicInteger();
+
+    private HazelcastUtil(){}
+
+    /**
+     * Get a hazelcast instance.
+     * @return a hazelcast instance, not null.
+     */
+    public static synchronized HazelcastInstance getHazelcastInstance(){
+        accessCounter.incrementAndGet();
+        if(hz==null){
+            hz = Hazelcast.newHazelcastInstance();
+        }
+        return hz;
+    }
+
+    /**
+     * Shut down hazelcast, if we are the last client alive.
+     */
+    public static synchronized void shutdown(){
+        if(accessCounter.decrementAndGet()<0){
+            if(hz!=null){
+                hz.shutdown();
+                hz = null;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/HazelcaszPropertySourceTest.java
----------------------------------------------------------------------
diff --git 
a/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/HazelcaszPropertySourceTest.java
 
b/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/HazelcaszPropertySourceTest.java
new file mode 100644
index 0000000..9986827
--- /dev/null
+++ 
b/modules/hazelcast/src/test/java/org/apache/tamaya/hazelcast/HazelcaszPropertySourceTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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.tamaya.hazelcast;
+
+import com.hazelcast.core.Hazelcast;
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.core.IMap;
+import org.apache.tamaya.spi.PropertyValue;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.runners.MethodSorters;
+
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by atsticks on 03.11.16.
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class HazelcaszPropertySourceTest {
+
+    private static HazelcastInstance hz = HazelcastUtil.getHazelcastInstance();
+    private HazelcastPropertySource hps = new HazelcastPropertySource();
+
+    @BeforeClass
+    public static void start() {
+        IMap<Object, Object> map = hz.getMap("config3");
+        map.put("k1", "v1");
+        map.put("k2", "v2");
+        map.put("tamaya.ordinal", "2000");
+        map.flush();
+        IMap<Object, Object> map2 = hz.getMap("config4");
+        map2.put("key1", "val1");
+        map2.put("key2", "val2");
+        map2.flush();
+    }
+
+    @org.junit.Test
+    public void t01_testGetProperties(){
+        hps.setMapReference("config3");
+        Map<String, PropertyValue> values = hps.getProperties();
+        assertNotNull(values);
+        assertEquals(3, values.size());
+        assertNotNull(values.get("k1"));
+        assertNotNull(values.get("k2"));
+        assertEquals("v1", values.get("k1").getValue());
+        assertEquals("v2", values.get("k2").getValue());
+        assertEquals(hps.getOrdinal(), 2000);
+
+        hps.setMapReference("config4");
+        Map<String, PropertyValue> values2 = hps.getProperties();
+        assertNotNull(values2);
+        assertEquals(2, values2.size());
+        assertNotNull(values2.get("key1"));
+        assertNotNull(values2.get("key2"));
+        assertEquals("val1", values2.get("key1").getValue());
+        assertEquals("val2", values2.get("key2").getValue());
+        assertEquals(hps.getOrdinal(), 0);
+
+        hps.setMapReference("bar");
+        hps.setDefaultOrdinal(1500);
+        Map<String, PropertyValue> values3 = hps.getProperties();
+        assertNotNull(values3);
+        assertEquals(0, values3.size());
+        assertEquals(hps.getOrdinal(), 1500);
+    }
+
+    @org.junit.Test
+    public void t02_testGetOrdinal(){
+        hps.setMapReference("config3");
+        hps.setDefaultOrdinal(1500);
+        assertEquals(1500, hps.getDefaultOrdinal());
+        assertEquals(hps.getOrdinal(), 2000);
+
+        hps.setMapReference("config4");
+        hps.setDefaultOrdinal(0);
+        assertEquals(0, hps.getDefaultOrdinal());
+        assertEquals(hps.getOrdinal(), 0);
+
+        hps.setMapReference("bar");
+        hps.setDefaultOrdinal(1500);
+        assertEquals(1500, hps.getDefaultOrdinal());
+        assertEquals(hps.getOrdinal(), 1500);
+    }
+
+    @org.junit.Test
+    public void t03_tesGet(){
+        hps.setMapReference("config3");
+        PropertyValue val1 = hps.get("k1");
+        assertNotNull(val1);
+        assertEquals("v1", val1.getValue());
+        PropertyValue val2 = hps.get("k2");
+        assertNotNull(val2);
+        assertEquals("v2", val2.getValue());
+
+        hps.setMapReference("config4");
+        val1 = hps.get("key1");
+        assertNotNull(val1);
+        assertEquals("val1", val1.getValue());
+        val2 = hps.get("key2");
+        assertNotNull(val2);
+        assertEquals("val2", val2.getValue());
+
+        hps.setMapReference("bar");
+        val1 = hps.get("key1");
+        assertNull(val1);
+        val1 = hps.get("k1");
+        assertNull(val1);
+    }
+
+    @org.junit.Test
+    public void t03_tesGetMapReference(){
+        hps.setMapReference("config3");
+        assertEquals("config3", hps.getMapReference());
+
+        hps.setMapReference("config4");
+        assertEquals("config4", hps.getMapReference());
+    }
+
+    @org.junit.Test
+    public void t03_tesGetSetName(){
+        hps.setMapReference("config3");
+        assertEquals("config3", hps.getMapReference());
+        assertEquals("Hazelcast", hps.getName());
+
+        hps.setMapReference("config4");
+        hps.setName("bar");
+        assertEquals("config4", hps.getMapReference());
+        assertEquals("bar", hps.getName());
+    }
+
+    @org.junit.Test
+    public void t04_testCache() throws InterruptedException {
+        hps.setCacheTimeout(50L);
+        assertTrue(hps.getValidUntil()>= System.currentTimeMillis());
+        assertEquals(50L, hps.getCachePeriod());
+        hps.setMapReference("config3");
+        hps.setDefaultOrdinal(200);
+        Map<String, PropertyValue> values = hps.getProperties();
+        assertNotNull(values);
+        assertEquals(3, values.size());
+        assertNotNull(values.get("k1"));
+        assertNotNull(values.get("k2"));
+        assertEquals("v1", values.get("k1").getValue());
+        assertEquals("v2", values.get("k2").getValue());
+        assertEquals(hps.getOrdinal(), 2000);
+
+        IMap<Object, Object> map = hz.getMap("config3");
+        map.put("k3", "v3");
+        map.remove("tamaya.ordinal");
+        map.flush();
+
+        // Read from cache
+        assertEquals(50L, hps.getCachePeriod());
+        assertTrue(hps.getValidUntil()>= System.currentTimeMillis());
+        values = hps.getProperties();
+        assertNotNull(values);
+        assertEquals(3, values.size());
+        assertNotNull(values.get("k1"));
+        assertNotNull(values.get("k2"));
+        assertEquals("v1", values.get("k1").getValue());
+        assertEquals("v2", values.get("k2").getValue());
+        assertEquals(hps.getOrdinal(), 2000);
+
+        // Let cache timeout
+        Thread.sleep(300L);
+
+        // Read updated values
+        values = hps.getProperties();
+        assertNotNull(values);
+        assertEquals(3, values.size());
+        assertNotNull(values.get("k1"));
+        assertNotNull(values.get("k2"));
+        assertNotNull(values.get("k3"));
+        assertEquals("v1", values.get("k1").getValue());
+        assertEquals("v2", values.get("k2").getValue());
+        assertEquals("v3", values.get("k3").getValue());
+        assertEquals(hps.getOrdinal(), 200);
+    }
+
+    @AfterClass
+    public static void end(){
+        HazelcastUtil.shutdown();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-tamaya-extensions/blob/c8ba9c4c/modules/pom.xml
----------------------------------------------------------------------
diff --git a/modules/pom.xml b/modules/pom.xml
index bd7abe0..62c878f 100644
--- a/modules/pom.xml
+++ b/modules/pom.xml
@@ -45,6 +45,10 @@ under the License.
         <module>osgi</module>
         <module>microprofile</module>
         <module>injection</module>
+        <module>collections</module>
+        <module>hazelcast</module>
+        <module>etcd</module>
+        <module>consul</module>
     </modules>
 
 </project>


Reply via email to