You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/12/17 12:59:51 UTC

[3/7] incubator-brooklyn git commit: Moving HazelcastCluster out of the sandbox

Moving HazelcastCluster out of the sandbox

Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/3635a465
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/3635a465
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/3635a465

Branch: refs/heads/master
Commit: 3635a46507085cac0e80ac448658f0f8e32133e1
Parents: ed928a5
Author: Yavor Yanchev <ya...@yanchev.com>
Authored: Fri Nov 27 01:41:15 2015 +0200
Committer: Yavor Yanchev <ya...@yanchev.com>
Committed: Mon Dec 14 03:20:22 2015 +0200

----------------------------------------------------------------------
 sandbox/nosql/pom.xml                           |  19 ---
 .../nosql/hazelcast/HazelcastCluster.java       |  60 -------
 .../nosql/hazelcast/HazelcastClusterImpl.java   | 125 ---------------
 .../entity/nosql/hazelcast/HazelcastNode.java   |  97 -----------
 .../nosql/hazelcast/HazelcastNodeDriver.java    |  25 ---
 .../nosql/hazelcast/HazelcastNodeImpl.java      | 147 -----------------
 .../nosql/hazelcast/HazelcastNodeSshDriver.java | 160 -------------------
 .../nosql/hazelcast/hazelcast-brooklyn.xml      |  65 --------
 .../hazelcast/HazelcastClusterEc2LiveTest.java  |  74 ---------
 .../HazelcastClusterSoftlayerLiveTest.java      |  74 ---------
 software/nosql/pom.xml                          |   1 +
 .../nosql/hazelcast/HazelcastCluster.java       |  60 +++++++
 .../nosql/hazelcast/HazelcastClusterImpl.java   | 125 +++++++++++++++
 .../entity/nosql/hazelcast/HazelcastNode.java   |  97 +++++++++++
 .../nosql/hazelcast/HazelcastNodeDriver.java    |  25 +++
 .../nosql/hazelcast/HazelcastNodeImpl.java      | 147 +++++++++++++++++
 .../nosql/hazelcast/HazelcastNodeSshDriver.java | 160 +++++++++++++++++++
 .../nosql/hazelcast/hazelcast-brooklyn.xml      |  65 ++++++++
 .../hazelcast/HazelcastClusterEc2LiveTest.java  |  74 +++++++++
 .../HazelcastClusterSoftlayerLiveTest.java      |  74 +++++++++
 20 files changed, 828 insertions(+), 846 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/pom.xml
----------------------------------------------------------------------
diff --git a/sandbox/nosql/pom.xml b/sandbox/nosql/pom.xml
index d62be44..5b15536 100644
--- a/sandbox/nosql/pom.xml
+++ b/sandbox/nosql/pom.xml
@@ -76,23 +76,4 @@
             <scope>test</scope>
         </dependency>
     </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.rat</groupId>
-                <artifactId>apache-rat-plugin</artifactId>
-                <configuration>
-                    <excludes combine.children="append">
-                        <!--
-                            Configuration artifacts (for installations) are based on templated defaults for 
-                            the given components. These are files "without any degree of creativity" from the
-                            perspective of the Brooklyn/Apache contribution.
-                        -->
-                        <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml</exclude>
-                    </excludes>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
deleted file mode 100644
index c43e882..0000000
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
+++ /dev/null
@@ -1,60 +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.apache.brooklyn.entity.nosql.hazelcast;
-
-import java.util.List;
-
-import com.google.common.reflect.TypeToken;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.core.sensor.Sensors;
-import org.apache.brooklyn.entity.group.DynamicCluster;
-
-/**
- * A cluster of {@link HazelcastNode}s based on {@link DynamicCluster}.
- */
-@Catalog(name="Hazelcast Cluster", description="Hazelcast is a clustering and highly scalable data distribution platform for Java.")
-
-@ImplementedBy(HazelcastClusterImpl.class)
-public interface HazelcastCluster extends DynamicCluster {
-
-    @SetFromFlag("clusterName")
-    BasicAttributeSensorAndConfigKey<String> CLUSTER_NAME = new BasicAttributeSensorAndConfigKey<String>(String.class, 
-            "hazelcast.cluster.name", "Name of the Hazelcast cluster", "HazelcastCluster");
-    
-    @SetFromFlag("clusterPassword")
-    ConfigKey<String> CLUSTER_PASSWORD =
-            ConfigKeys.newStringConfigKey("hazelcast.cluster.password", "Hazelcast cluster password.");
-    
-    @SuppressWarnings("serial")
-    AttributeSensor<List<String>> PUBLIC_CLUSTER_NODES = Sensors.newSensor(new TypeToken<List<String>>() {},
-        "hazelcast.cluster.public.nodes", "List of public addresses of all nodes in the cluster");
-    
-    String getClusterName();
-    
-    String getClusterPassword();
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
deleted file mode 100644
index 83cf15a..0000000
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
+++ /dev/null
@@ -1,125 +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.apache.brooklyn.entity.nosql.hazelcast;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.Lists;
-import org.apache.brooklyn.api.entity.Entity;
-
-import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
-import org.apache.brooklyn.entity.group.DynamicClusterImpl;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.policy.PolicySpec;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.entity.EntityInternal;
-import org.apache.brooklyn.util.text.Strings;
-
-public class HazelcastClusterImpl extends DynamicClusterImpl implements HazelcastCluster {
-    private static final Logger LOG = LoggerFactory.getLogger(HazelcastClusterImpl.class);
-    
-    private static final AtomicInteger nextMemberId = new AtomicInteger(0);
-    
-    @Override
-    protected EntitySpec<?> getMemberSpec() {
-        EntitySpec<?> spec = EntitySpec.create(getConfig(MEMBER_SPEC, EntitySpec.create(HazelcastNode.class)));
-        
-        spec.configure(HazelcastNode.GROUP_NAME, getConfig(HazelcastClusterImpl.CLUSTER_NAME));
-        
-        if (LOG.isInfoEnabled()) {
-            LOG.info("Cluster name : {} : used as a group name", getConfig(HazelcastNode.GROUP_NAME));
-        }
-        
-        spec.configure(HazelcastNode.GROUP_PASSWORD, getClusterPassword());
-        
-        return spec;
-    }
-  
-    @Override
-    public void init() {
-        super.init();
-
-        String clusterPassword = getClusterPassword();
-        
-        if (Strings.isBlank(clusterPassword)) {
-            if (LOG.isInfoEnabled()) {
-                LOG.info(this + " cluster password not provided for " + CLUSTER_PASSWORD.getName() + " : generating random password");
-            }
-            config().set(CLUSTER_PASSWORD, Strings.makeRandomId(12));
-        }
-        
-        policies().add(PolicySpec.create(MemberTrackingPolicy.class)
-                .displayName("Hazelcast members tracker")
-                .configure("group", this));
-    }
-    
-    public static class MemberTrackingPolicy extends AbstractMembershipTrackingPolicy {
-        @Override
-        protected void onEntityChange(Entity member) {
-        }
-
-        @Override
-        protected void onEntityAdded(Entity member) {
-            if (member.getAttribute(HazelcastNode.NODE_NAME) == null) {
-                ((EntityInternal) member).sensors().set(HazelcastNode.NODE_NAME, "hazelcast-" + nextMemberId.incrementAndGet());
-                if (LOG.isInfoEnabled()) {
-                    LOG.info("Node {} added to the cluster", member);
-                }
-            }
-        }
-
-        @Override
-        protected void onEntityRemoved(Entity member) {
-        }
-    };
-    
-    @Override
-    public String getClusterName() {
-        return getConfig(CLUSTER_NAME);
-    }
-
-    @Override
-    public String getClusterPassword() {
-        return getConfig(CLUSTER_PASSWORD);
-    }
-
-    @Override
-    protected void initEnrichers() {
-        super.initEnrichers();
-        
-    }
-    
-    @Override
-    public void start(Collection<? extends Location> locations) {
-        super.start(locations);
-        
-        
-        List<String> clusterNodes = Lists.newArrayList();
-        for (Entity member : getMembers()) {
-            clusterNodes.add(member.getAttribute(Attributes.ADDRESS));
-        }
-        sensors().set(PUBLIC_CLUSTER_NODES, clusterNodes);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
deleted file mode 100644
index e53d0da..0000000
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
+++ /dev/null
@@ -1,97 +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.apache.brooklyn.entity.nosql.hazelcast;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.ImplementedBy;
-import org.apache.brooklyn.util.core.flags.SetFromFlag;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.location.PortRanges;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
-import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
-import org.apache.brooklyn.entity.software.base.SoftwareProcess;
-import org.apache.brooklyn.entity.java.UsesJava;
-import org.apache.brooklyn.entity.java.UsesJmx;
-import org.apache.brooklyn.util.javalang.JavaClassNames;
-
-/**
- * An {@link brooklyn.entity.Entity} that represents an Hazelcast node
- */
-@Catalog(name="Hazelcast Node", description="Hazelcast is a clustering and highly scalable data distribution platform for Java.")
-
-@ImplementedBy(HazelcastNodeImpl.class)
-public interface HazelcastNode extends SoftwareProcess, UsesJava, UsesJmx {
-    @SetFromFlag("version")
-    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "3.4.2");
-    
-    @SetFromFlag("downloadUrl")
-    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
-            SoftwareProcess.DOWNLOAD_URL, "https://repo1.maven.org/maven2/com/hazelcast/hazelcast/${version}/hazelcast-${version}.jar");
-    
-    @SetFromFlag("configTemplateUrl")
-    ConfigKey<String> CONFIG_TEMPLATE_URL = ConfigKeys.newStringConfigKey(
-            "hazelcast.node.config.templateUrl", "Template file (in freemarker format) for the Hazelcat config file", 
-            JavaClassNames.resolveClasspathUrl(HazelcastNode.class, "hazelcast-brooklyn.xml"));
-    
-    @SetFromFlag("configFileName")
-    ConfigKey<String> CONFIG_FILE_NAME = ConfigKeys.newStringConfigKey(
-            "hazelcast.node.config.fileName", "Name of the Hazelcast config file", "hazelcast.xml");    
-    
-    @SetFromFlag("nodeName")
-    StringAttributeSensorAndConfigKey NODE_NAME = new StringAttributeSensorAndConfigKey("hazelcast.node.name", 
-            "Node name (or randomly selected if not set", null);
-
-    @SetFromFlag("nodeHeapMemorySize")
-    ConfigKey<String> NODE_HEAP_MEMORY_SIZE = ConfigKeys.newStringConfigKey(
-            "hazelcast.node.heap.memory.size", "Node's heap memory size (-Xmx and -Xms) in megabytes. Default: 256m", "256m");
-    
-    @SetFromFlag("nodePort")
-    PortAttributeSensorAndConfigKey NODE_PORT = new PortAttributeSensorAndConfigKey("hazelcast.node.port", "Hazelcast communication port", PortRanges.fromString("5701+"));
-
-    /**
-     * Specifies the group name in the configuration file. Each Hazelcast cluster has a separate group.
-     */ 
-    @SetFromFlag("groupName")
-    ConfigKey<String> GROUP_NAME = ConfigKeys.newStringConfigKey("hazelcast.group.name", 
-            "Group name", "brooklyn");
-  
-    @SetFromFlag("groupPassword")
-    ConfigKey<String> GROUP_PASSWORD = ConfigKeys.newStringConfigKey("hazelcast.group.password", 
-            "Group password", "brooklyn");
-    
-    String getNodeName();
-    
-    Integer getNodePort();
-    
-    String getGroupName();
-    
-    String getGroupPassword();
-    
-    String getHostname();
-    
-    String getHostAddress();
-
-    String getPrivateIpAddress();
-
-    String getListenAddress();
-    
-    String getHeapMemorySize();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java
deleted file mode 100644
index 8cf1e0c..0000000
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java
+++ /dev/null
@@ -1,25 +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.apache.brooklyn.entity.nosql.hazelcast;
-
-import org.apache.brooklyn.entity.software.base.SoftwareProcessDriver;
-
-public interface HazelcastNodeDriver extends SoftwareProcessDriver {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
deleted file mode 100644
index 6e17737..0000000
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
+++ /dev/null
@@ -1,147 +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.apache.brooklyn.entity.nosql.hazelcast;
-
-import java.net.URI;
-import java.util.concurrent.TimeUnit;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.core.entity.Attributes;
-import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
-import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
-import org.apache.brooklyn.feed.http.HttpFeed;
-import org.apache.brooklyn.feed.http.HttpPollConfig;
-import org.apache.brooklyn.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.util.text.Strings;
-
-import com.google.common.base.Functions;
-import com.google.common.net.HostAndPort;
-
-public class HazelcastNodeImpl extends SoftwareProcessImpl implements HazelcastNode {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(HazelcastNodeImpl.class);
-    
-    HttpFeed httpFeed;
-
-    @Override
-    public Class<HazelcastNodeDriver> getDriverInterface() {
-        return HazelcastNodeDriver.class;
-    }
-    
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Connecting sensors for node: {} ", getAttribute(Attributes.HOSTNAME));
-        }
-        
-        HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(this, getNodePort());
-
-        String nodeUri = String.format("http://%s:%d/hazelcast/rest/cluster", hp.getHostText(), hp.getPort());
-        sensors().set(Attributes.MAIN_URI, URI.create(nodeUri));
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Node {} is using {} as a main URI", this, nodeUri);
-        }
-        
-        httpFeed = HttpFeed.builder()
-                .entity(this)
-                .period(3000, TimeUnit.MILLISECONDS)
-                .baseUri(nodeUri)
-                .poll(new HttpPollConfig<Boolean>(SERVICE_UP)
-                        .onSuccess(HttpValueFunctions.responseCodeEquals(200))
-                        .onFailureOrException(Functions.constant(false)))
-                .build();
-    }
-    
-    @Override
-    protected void disconnectSensors() {
-        if (httpFeed != null) {
-            httpFeed.stop();
-        }
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Disconnecting sensors for node: {} ", getAttribute(Attributes.HOSTNAME));
-        }
-        
-        super.disconnectSensors();
-        disconnectServiceUpIsRunning();
-    }
-
-
-    @Override
-    public String getGroupName() {
-        return getConfig(HazelcastNode.GROUP_NAME);
-    }
-
-    @Override
-    public String getGroupPassword() {
-        return getConfig(HazelcastNode.GROUP_PASSWORD);
-    }
-
-    @Override
-    public String getNodeName() {
-        return getAttribute(HazelcastNode.NODE_NAME);
-    }
-
-    @Override
-    public Integer getNodePort() {
-        return getAttribute(HazelcastNode.NODE_PORT);
-    }
-
-    @Override
-    public String getHostname() { 
-        return getAttribute(HOSTNAME); 
-    }
-    
-    @Override
-    public String getHostAddress() { 
-        return getAttribute(ADDRESS); 
-    }
-    
-    @Override
-    public String getPrivateIpAddress() {
-        return getAttribute(SUBNET_ADDRESS);
-    }
-    
-    @Override
-    public String getListenAddress() {
-        String listenAddress = getPrivateIpAddress();
-        
-        if (Strings.isBlank(listenAddress)) {
-            listenAddress = getAttribute(ADDRESS);
-        }
-        
-        if (LOG.isInfoEnabled()) {
-            LOG.info("Node {} is listening on {}", this, listenAddress);
-        }
-
-         
-        return listenAddress;
-    }
-
-
-    @Override
-    public String getHeapMemorySize() {
-        return getConfig(HazelcastNode.NODE_HEAP_MEMORY_SIZE);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java b/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java
deleted file mode 100644
index 2d67453..0000000
--- a/sandbox/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java
+++ /dev/null
@@ -1,160 +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.apache.brooklyn.entity.nosql.hazelcast;
-
-import static java.lang.String.format;
-
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.core.entity.Entities;
-
-import org.apache.brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.os.Os;
-import org.apache.brooklyn.util.ssh.BashCommands;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-public class HazelcastNodeSshDriver extends JavaSoftwareProcessSshDriver implements HazelcastNodeDriver {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(HazelcastNodeSshDriver.class);
-
-    public HazelcastNodeSshDriver(EntityLocal entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-        
-        List<String> commands = ImmutableList.<String>builder()
-            .add(BashCommands.installJavaLatestOrWarn())
-            .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
-            .build();
-        
-        newScript(INSTALLING).body.append(commands).execute();
-    }
-
-    @Override
-    public void customize() {
-        if (LOG.isInfoEnabled()) {
-            LOG.info("Customizing {}", entity.getAttribute(HazelcastNode.NODE_NAME));
-        }
-        
-        ImmutableList.Builder<String> commands = new ImmutableList.Builder<String>()
-                .add("mkdir -p lib conf log")
-                .add(String.format("cp %s/%s %s/lib/", getInstallDir(), resolver.getFilename(), getRunDir()));
-
-        newScript(CUSTOMIZING)
-                .body.append(commands.build())
-                .failOnNonZeroResultCode()
-                .execute();
-        
-        copyTemplate(entity.getConfig(HazelcastNode.CONFIG_TEMPLATE_URL), Os.mergePathsUnix(getRunDir(), "conf", getConfigFileName()));
-        
-    }
-
-    @Override
-    public void launch() {
-        
-        entity.sensors().set(HazelcastNode.PID_FILE, Os.mergePathsUnix(getRunDir(), PID_FILENAME));
-        
-        String maxHeapMemorySize = getHeapMemorySize();
-        
-        if (LOG.isInfoEnabled()) {
-            LOG.info("Launching {} with heap memory of {}", entity, maxHeapMemorySize);
-        }
-        
-        // Setting initial heap size (Xms) size to match max heap size (Xms) at first
-        String initialHeapMemorySize = maxHeapMemorySize;
-        
-        StringBuilder commandBuilder = new StringBuilder()
-            .append(format("nohup java -cp ./lib/%s", resolver.getFilename()))
-            .append(format(" -Xmx%s -Xms%s", maxHeapMemorySize, initialHeapMemorySize))
-            .append(format(" -Dhazelcast.config=./conf/%s", getConfigFileName()))
-            .append(format(" com.hazelcast.core.server.StartServer >> %s 2>&1 </dev/null &", getLogFileLocation()));
-        
-        newScript(MutableMap.of(USE_PID_FILE, true), LAUNCHING)
-            .updateTaskAndFailOnNonZeroResultCode()
-            .body.append(commandBuilder.toString())
-            .execute();
-    }
-       
-    public String getConfigFileName() {
-        return entity.getConfig(HazelcastNode.CONFIG_FILE_NAME);
-    }
-    
-    public String getHeapMemorySize() {
-        return entity.getConfig(HazelcastNode.NODE_HEAP_MEMORY_SIZE);
-    }
-    
-    @Override
-    public boolean isRunning() {       
-        return newScript(MutableMap.of(USE_PID_FILE, true), CHECK_RUNNING).execute() == 0;
-    }
-    
-    @Override
-    public void stop() {
-        newScript(MutableMap.of(USE_PID_FILE, true), STOPPING).execute();
-    }
-    
-    @Override
-    public void kill() {
-        newScript(MutableMap.of(USE_PID_FILE, true), KILLING).execute();
-    }
-
-    public List<String> getHazelcastNodesList() throws ExecutionException, InterruptedException {
-        HazelcastCluster cluster = (HazelcastCluster) entity.getParent();
-        List<String> result = Lists.newArrayList();
-
-        for (Entity member : cluster.getMembers()) {
-            String address = Entities.attributeSupplierWhenReady(member, HazelcastNode.SUBNET_ADDRESS).get();
-            Integer port = Entities.attributeSupplierWhenReady(member, HazelcastNode.NODE_PORT).get();
-            
-            String addressAndPort = String.format("%s:%d", address, port);
-            
-            if (LOG.isInfoEnabled()) {
-                LOG.info("Adding {} to the members' list of {}", addressAndPort, entity.getAttribute(HazelcastNode.NODE_NAME));
-            }
-            result.add(addressAndPort);
-        }
-        
-        return result;
-    }
-
-    @Override
-    protected String getLogFileLocation() {
-        return Os.mergePathsUnix(getRunDir(),"/log/out.log");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml b/sandbox/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml
deleted file mode 100644
index 459be4e..0000000
--- a/sandbox/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-[#ftl]
-<?xml version="1.0" encoding="UTF-8"?>
-
-<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.4.xsd"
-           xmlns="http://www.hazelcast.com/schema/config"
-           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-    <group>
-        <name>${entity.groupName}</name>
-        <password>${entity.groupPassword}</password>
-    </group>
-    <management-center enabled="false">http://localhost:8080/mancenter</management-center>
-    <network>
-        <port auto-increment="true" port-count="100">${entity.nodePort?c}</port>
-        <outbound-ports>
-            <!--
-            Allowed port range when connecting to other nodes.
-            0 or * means use system provided port.
-            -->
-            <ports>0</ports>
-        </outbound-ports>
-        
-        <interfaces enabled="true">
-            <interface>${entity.listenAddress}</interface> 
-        </interfaces> 
-        
-        <join>
-            <multicast enabled="false" />
-
-            <tcp-ip enabled="true">
-            [#list driver.hazelcastNodesList as member]
-                <member>${member}</member>
-            [/#list]
-            </tcp-ip>
-            
-            <aws enabled="false" />
-
-        </join>
-
-        <ssl enabled="false"/>
-        <socket-interceptor enabled="false"/>
-        <symmetric-encryption enabled="false"/>
-
-    </network>
-    <partition-group enabled="false"/>
-
-    <map name="default">
-        <in-memory-format>BINARY</in-memory-format>
-        <backup-count>1</backup-count>
-        <async-backup-count>0</async-backup-count>
-        <time-to-live-seconds>0</time-to-live-seconds>
-        <max-idle-seconds>0</max-idle-seconds>
-        <eviction-policy>NONE</eviction-policy>
-        <max-size policy="PER_NODE">0</max-size>
-        <eviction-percentage>25</eviction-percentage>
-        <min-eviction-check-millis>100</min-eviction-check-millis>
-        <merge-policy>com.hazelcast.map.merge.PutIfAbsentMapMergePolicy</merge-policy>
-    </map>
-
-    <serialization>
-        <portable-version>0</portable-version>
-    </serialization>
-
-    <services enable-defaults="true"/>
-
-</hazelcast>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java
deleted file mode 100644
index f1d44fc..0000000
--- a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java
+++ /dev/null
@@ -1,74 +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.apache.brooklyn.entity.nosql.hazelcast;
-
-import org.apache.brooklyn.entity.nosql.hazelcast.HazelcastCluster;
-import org.apache.brooklyn.entity.nosql.hazelcast.HazelcastNode;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.Test;
-
-import org.apache.brooklyn.entity.AbstractEc2LiveTest;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.core.entity.Attributes;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-public class HazelcastClusterEc2LiveTest extends AbstractEc2LiveTest {
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(HazelcastClusterEc2LiveTest.class);
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        HazelcastCluster cluster = app.createAndManageChild(EntitySpec.create(HazelcastCluster.class)
-                .configure(HazelcastCluster.INITIAL_SIZE, 3)
-                .configure(HazelcastCluster.MEMBER_SPEC, EntitySpec.create(HazelcastNode.class)));
-        app.start(ImmutableList.of(loc));
-
-        EntityTestUtils.assertAttributeEqualsEventually(cluster, HazelcastNode.SERVICE_UP, true);
-
-        HazelcastNode first = (HazelcastNode) Iterables.get(cluster.getMembers(), 0);
-        HazelcastNode second = (HazelcastNode) Iterables.get(cluster.getMembers(), 1);
-
-        assertNodesUpAndInCluster(first, second);
-        
-        EntityTestUtils.assertAttributeEqualsEventually(cluster, Attributes.SERVICE_UP, true);
-    }
-    
-    private void assertNodesUpAndInCluster(final HazelcastNode... nodes) {
-        for (final HazelcastNode node : nodes) {
-            EntityTestUtils.assertAttributeEqualsEventually(node, HazelcastNode.SERVICE_UP, true);
-        }
-    }
-
-    @Test(enabled = false)
-    public void testDummy() {
-    } // Convince TestNG IDE integration that this really does have test methods
-
-    
-    @Test(groups = {"Live", "Live-sanity"})
-    @Override
-    public void test_CentOS_6_3() throws Exception {
-        super.test_CentOS_6_3();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java
deleted file mode 100644
index 0e9fe0b..0000000
--- a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java
+++ /dev/null
@@ -1,74 +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.apache.brooklyn.entity.nosql.hazelcast;
-
-import org.apache.brooklyn.entity.nosql.hazelcast.HazelcastCluster;
-import org.apache.brooklyn.entity.nosql.hazelcast.HazelcastNode;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.Test;
-
-import org.apache.brooklyn.entity.AbstractSoftlayerLiveTest;
-
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.core.entity.Attributes;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-public class HazelcastClusterSoftlayerLiveTest extends AbstractSoftlayerLiveTest {
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(HazelcastClusterSoftlayerLiveTest.class);
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        HazelcastCluster cluster = app.createAndManageChild(EntitySpec.create(HazelcastCluster.class)
-                .configure(HazelcastCluster.INITIAL_SIZE, 3)
-                .configure(HazelcastCluster.MEMBER_SPEC, EntitySpec.create(HazelcastNode.class)));
-        app.start(ImmutableList.of(loc));
-
-        EntityTestUtils.assertAttributeEqualsEventually(cluster, HazelcastNode.SERVICE_UP, true);
-
-        HazelcastNode first = (HazelcastNode) Iterables.get(cluster.getMembers(), 0);
-        HazelcastNode second = (HazelcastNode) Iterables.get(cluster.getMembers(), 1);
-
-        assertNodesUpAndInCluster(first, second);
-        
-        EntityTestUtils.assertAttributeEqualsEventually(cluster, Attributes.SERVICE_UP, true);
-    }
-    
-    private void assertNodesUpAndInCluster(final HazelcastNode... nodes) {
-        for (final HazelcastNode node : nodes) {
-            EntityTestUtils.assertAttributeEqualsEventually(node, HazelcastNode.SERVICE_UP, true);
-        }
-    }
-
-    @Test(enabled = false)
-    public void testDummy() {
-    } // Convince TestNG IDE integration that this really does have test methods
-
-    
-    @Test(groups = {"Live", "Live-sanity"})
-    @Override
-    public void test_Ubuntu_12_0_4() throws Exception {
-        super.test_Ubuntu_12_0_4();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/pom.xml
----------------------------------------------------------------------
diff --git a/software/nosql/pom.xml b/software/nosql/pom.xml
index 4fd2d18..e3e9acf 100644
--- a/software/nosql/pom.xml
+++ b/software/nosql/pom.xml
@@ -251,6 +251,7 @@
                 <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/cassandra/cassandra-rackdc.properties</exclude>
                 <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/couchdb/couch.ini</exclude>
                 <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/couchdb/couch.uri</exclude>
+                <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml</exclude>
                 <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/mongodb/default.conf</exclude>
                 <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/mongodb/default-mongod.conf</exclude>
                 <exclude>src/test/resources/test-mongodb.conf</exclude>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
new file mode 100644
index 0000000..c43e882
--- /dev/null
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.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.brooklyn.entity.nosql.hazelcast;
+
+import java.util.List;
+
+import com.google.common.reflect.TypeToken;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.entity.group.DynamicCluster;
+
+/**
+ * A cluster of {@link HazelcastNode}s based on {@link DynamicCluster}.
+ */
+@Catalog(name="Hazelcast Cluster", description="Hazelcast is a clustering and highly scalable data distribution platform for Java.")
+
+@ImplementedBy(HazelcastClusterImpl.class)
+public interface HazelcastCluster extends DynamicCluster {
+
+    @SetFromFlag("clusterName")
+    BasicAttributeSensorAndConfigKey<String> CLUSTER_NAME = new BasicAttributeSensorAndConfigKey<String>(String.class, 
+            "hazelcast.cluster.name", "Name of the Hazelcast cluster", "HazelcastCluster");
+    
+    @SetFromFlag("clusterPassword")
+    ConfigKey<String> CLUSTER_PASSWORD =
+            ConfigKeys.newStringConfigKey("hazelcast.cluster.password", "Hazelcast cluster password.");
+    
+    @SuppressWarnings("serial")
+    AttributeSensor<List<String>> PUBLIC_CLUSTER_NODES = Sensors.newSensor(new TypeToken<List<String>>() {},
+        "hazelcast.cluster.public.nodes", "List of public addresses of all nodes in the cluster");
+    
+    String getClusterName();
+    
+    String getClusterPassword();
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
new file mode 100644
index 0000000..83cf15a
--- /dev/null
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
@@ -0,0 +1,125 @@
+/*
+ * 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.brooklyn.entity.nosql.hazelcast;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import org.apache.brooklyn.api.entity.Entity;
+
+import org.apache.brooklyn.entity.group.AbstractMembershipTrackingPolicy;
+import org.apache.brooklyn.entity.group.DynamicClusterImpl;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.util.text.Strings;
+
+public class HazelcastClusterImpl extends DynamicClusterImpl implements HazelcastCluster {
+    private static final Logger LOG = LoggerFactory.getLogger(HazelcastClusterImpl.class);
+    
+    private static final AtomicInteger nextMemberId = new AtomicInteger(0);
+    
+    @Override
+    protected EntitySpec<?> getMemberSpec() {
+        EntitySpec<?> spec = EntitySpec.create(getConfig(MEMBER_SPEC, EntitySpec.create(HazelcastNode.class)));
+        
+        spec.configure(HazelcastNode.GROUP_NAME, getConfig(HazelcastClusterImpl.CLUSTER_NAME));
+        
+        if (LOG.isInfoEnabled()) {
+            LOG.info("Cluster name : {} : used as a group name", getConfig(HazelcastNode.GROUP_NAME));
+        }
+        
+        spec.configure(HazelcastNode.GROUP_PASSWORD, getClusterPassword());
+        
+        return spec;
+    }
+  
+    @Override
+    public void init() {
+        super.init();
+
+        String clusterPassword = getClusterPassword();
+        
+        if (Strings.isBlank(clusterPassword)) {
+            if (LOG.isInfoEnabled()) {
+                LOG.info(this + " cluster password not provided for " + CLUSTER_PASSWORD.getName() + " : generating random password");
+            }
+            config().set(CLUSTER_PASSWORD, Strings.makeRandomId(12));
+        }
+        
+        policies().add(PolicySpec.create(MemberTrackingPolicy.class)
+                .displayName("Hazelcast members tracker")
+                .configure("group", this));
+    }
+    
+    public static class MemberTrackingPolicy extends AbstractMembershipTrackingPolicy {
+        @Override
+        protected void onEntityChange(Entity member) {
+        }
+
+        @Override
+        protected void onEntityAdded(Entity member) {
+            if (member.getAttribute(HazelcastNode.NODE_NAME) == null) {
+                ((EntityInternal) member).sensors().set(HazelcastNode.NODE_NAME, "hazelcast-" + nextMemberId.incrementAndGet());
+                if (LOG.isInfoEnabled()) {
+                    LOG.info("Node {} added to the cluster", member);
+                }
+            }
+        }
+
+        @Override
+        protected void onEntityRemoved(Entity member) {
+        }
+    };
+    
+    @Override
+    public String getClusterName() {
+        return getConfig(CLUSTER_NAME);
+    }
+
+    @Override
+    public String getClusterPassword() {
+        return getConfig(CLUSTER_PASSWORD);
+    }
+
+    @Override
+    protected void initEnrichers() {
+        super.initEnrichers();
+        
+    }
+    
+    @Override
+    public void start(Collection<? extends Location> locations) {
+        super.start(locations);
+        
+        
+        List<String> clusterNodes = Lists.newArrayList();
+        for (Entity member : getMembers()) {
+            clusterNodes.add(member.getAttribute(Attributes.ADDRESS));
+        }
+        sensors().set(PUBLIC_CLUSTER_NODES, clusterNodes);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
new file mode 100644
index 0000000..e53d0da
--- /dev/null
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
@@ -0,0 +1,97 @@
+/*
+ * 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.brooklyn.entity.nosql.hazelcast;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
+import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+import org.apache.brooklyn.entity.java.UsesJava;
+import org.apache.brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+
+/**
+ * An {@link brooklyn.entity.Entity} that represents an Hazelcast node
+ */
+@Catalog(name="Hazelcast Node", description="Hazelcast is a clustering and highly scalable data distribution platform for Java.")
+
+@ImplementedBy(HazelcastNodeImpl.class)
+public interface HazelcastNode extends SoftwareProcess, UsesJava, UsesJmx {
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "3.4.2");
+    
+    @SetFromFlag("downloadUrl")
+    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
+            SoftwareProcess.DOWNLOAD_URL, "https://repo1.maven.org/maven2/com/hazelcast/hazelcast/${version}/hazelcast-${version}.jar");
+    
+    @SetFromFlag("configTemplateUrl")
+    ConfigKey<String> CONFIG_TEMPLATE_URL = ConfigKeys.newStringConfigKey(
+            "hazelcast.node.config.templateUrl", "Template file (in freemarker format) for the Hazelcat config file", 
+            JavaClassNames.resolveClasspathUrl(HazelcastNode.class, "hazelcast-brooklyn.xml"));
+    
+    @SetFromFlag("configFileName")
+    ConfigKey<String> CONFIG_FILE_NAME = ConfigKeys.newStringConfigKey(
+            "hazelcast.node.config.fileName", "Name of the Hazelcast config file", "hazelcast.xml");    
+    
+    @SetFromFlag("nodeName")
+    StringAttributeSensorAndConfigKey NODE_NAME = new StringAttributeSensorAndConfigKey("hazelcast.node.name", 
+            "Node name (or randomly selected if not set", null);
+
+    @SetFromFlag("nodeHeapMemorySize")
+    ConfigKey<String> NODE_HEAP_MEMORY_SIZE = ConfigKeys.newStringConfigKey(
+            "hazelcast.node.heap.memory.size", "Node's heap memory size (-Xmx and -Xms) in megabytes. Default: 256m", "256m");
+    
+    @SetFromFlag("nodePort")
+    PortAttributeSensorAndConfigKey NODE_PORT = new PortAttributeSensorAndConfigKey("hazelcast.node.port", "Hazelcast communication port", PortRanges.fromString("5701+"));
+
+    /**
+     * Specifies the group name in the configuration file. Each Hazelcast cluster has a separate group.
+     */ 
+    @SetFromFlag("groupName")
+    ConfigKey<String> GROUP_NAME = ConfigKeys.newStringConfigKey("hazelcast.group.name", 
+            "Group name", "brooklyn");
+  
+    @SetFromFlag("groupPassword")
+    ConfigKey<String> GROUP_PASSWORD = ConfigKeys.newStringConfigKey("hazelcast.group.password", 
+            "Group password", "brooklyn");
+    
+    String getNodeName();
+    
+    Integer getNodePort();
+    
+    String getGroupName();
+    
+    String getGroupPassword();
+    
+    String getHostname();
+    
+    String getHostAddress();
+
+    String getPrivateIpAddress();
+
+    String getListenAddress();
+    
+    String getHeapMemorySize();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java
new file mode 100644
index 0000000..8cf1e0c
--- /dev/null
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java
@@ -0,0 +1,25 @@
+/*
+ * 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.brooklyn.entity.nosql.hazelcast;
+
+import org.apache.brooklyn.entity.software.base.SoftwareProcessDriver;
+
+public interface HazelcastNodeDriver extends SoftwareProcessDriver {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
new file mode 100644
index 0000000..6e17737
--- /dev/null
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
@@ -0,0 +1,147 @@
+/*
+ * 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.brooklyn.entity.nosql.hazelcast;
+
+import java.net.URI;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.location.access.BrooklynAccessUtils;
+import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+import org.apache.brooklyn.feed.http.HttpFeed;
+import org.apache.brooklyn.feed.http.HttpPollConfig;
+import org.apache.brooklyn.feed.http.HttpValueFunctions;
+import org.apache.brooklyn.util.text.Strings;
+
+import com.google.common.base.Functions;
+import com.google.common.net.HostAndPort;
+
+public class HazelcastNodeImpl extends SoftwareProcessImpl implements HazelcastNode {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(HazelcastNodeImpl.class);
+    
+    HttpFeed httpFeed;
+
+    @Override
+    public Class<HazelcastNodeDriver> getDriverInterface() {
+        return HazelcastNodeDriver.class;
+    }
+    
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Connecting sensors for node: {} ", getAttribute(Attributes.HOSTNAME));
+        }
+        
+        HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(this, getNodePort());
+
+        String nodeUri = String.format("http://%s:%d/hazelcast/rest/cluster", hp.getHostText(), hp.getPort());
+        sensors().set(Attributes.MAIN_URI, URI.create(nodeUri));
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Node {} is using {} as a main URI", this, nodeUri);
+        }
+        
+        httpFeed = HttpFeed.builder()
+                .entity(this)
+                .period(3000, TimeUnit.MILLISECONDS)
+                .baseUri(nodeUri)
+                .poll(new HttpPollConfig<Boolean>(SERVICE_UP)
+                        .onSuccess(HttpValueFunctions.responseCodeEquals(200))
+                        .onFailureOrException(Functions.constant(false)))
+                .build();
+    }
+    
+    @Override
+    protected void disconnectSensors() {
+        if (httpFeed != null) {
+            httpFeed.stop();
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Disconnecting sensors for node: {} ", getAttribute(Attributes.HOSTNAME));
+        }
+        
+        super.disconnectSensors();
+        disconnectServiceUpIsRunning();
+    }
+
+
+    @Override
+    public String getGroupName() {
+        return getConfig(HazelcastNode.GROUP_NAME);
+    }
+
+    @Override
+    public String getGroupPassword() {
+        return getConfig(HazelcastNode.GROUP_PASSWORD);
+    }
+
+    @Override
+    public String getNodeName() {
+        return getAttribute(HazelcastNode.NODE_NAME);
+    }
+
+    @Override
+    public Integer getNodePort() {
+        return getAttribute(HazelcastNode.NODE_PORT);
+    }
+
+    @Override
+    public String getHostname() { 
+        return getAttribute(HOSTNAME); 
+    }
+    
+    @Override
+    public String getHostAddress() { 
+        return getAttribute(ADDRESS); 
+    }
+    
+    @Override
+    public String getPrivateIpAddress() {
+        return getAttribute(SUBNET_ADDRESS);
+    }
+    
+    @Override
+    public String getListenAddress() {
+        String listenAddress = getPrivateIpAddress();
+        
+        if (Strings.isBlank(listenAddress)) {
+            listenAddress = getAttribute(ADDRESS);
+        }
+        
+        if (LOG.isInfoEnabled()) {
+            LOG.info("Node {} is listening on {}", this, listenAddress);
+        }
+
+         
+        return listenAddress;
+    }
+
+
+    @Override
+    public String getHeapMemorySize() {
+        return getConfig(HazelcastNode.NODE_HEAP_MEMORY_SIZE);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java
new file mode 100644
index 0000000..2d67453
--- /dev/null
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java
@@ -0,0 +1,160 @@
+/*
+ * 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.brooklyn.entity.nosql.hazelcast;
+
+import static java.lang.String.format;
+
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.core.entity.Entities;
+
+import org.apache.brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.os.Os;
+import org.apache.brooklyn.util.ssh.BashCommands;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+public class HazelcastNodeSshDriver extends JavaSoftwareProcessSshDriver implements HazelcastNodeDriver {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(HazelcastNodeSshDriver.class);
+
+    public HazelcastNodeSshDriver(EntityLocal entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+        
+        List<String> commands = ImmutableList.<String>builder()
+            .add(BashCommands.installJavaLatestOrWarn())
+            .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
+            .build();
+        
+        newScript(INSTALLING).body.append(commands).execute();
+    }
+
+    @Override
+    public void customize() {
+        if (LOG.isInfoEnabled()) {
+            LOG.info("Customizing {}", entity.getAttribute(HazelcastNode.NODE_NAME));
+        }
+        
+        ImmutableList.Builder<String> commands = new ImmutableList.Builder<String>()
+                .add("mkdir -p lib conf log")
+                .add(String.format("cp %s/%s %s/lib/", getInstallDir(), resolver.getFilename(), getRunDir()));
+
+        newScript(CUSTOMIZING)
+                .body.append(commands.build())
+                .failOnNonZeroResultCode()
+                .execute();
+        
+        copyTemplate(entity.getConfig(HazelcastNode.CONFIG_TEMPLATE_URL), Os.mergePathsUnix(getRunDir(), "conf", getConfigFileName()));
+        
+    }
+
+    @Override
+    public void launch() {
+        
+        entity.sensors().set(HazelcastNode.PID_FILE, Os.mergePathsUnix(getRunDir(), PID_FILENAME));
+        
+        String maxHeapMemorySize = getHeapMemorySize();
+        
+        if (LOG.isInfoEnabled()) {
+            LOG.info("Launching {} with heap memory of {}", entity, maxHeapMemorySize);
+        }
+        
+        // Setting initial heap size (Xms) size to match max heap size (Xms) at first
+        String initialHeapMemorySize = maxHeapMemorySize;
+        
+        StringBuilder commandBuilder = new StringBuilder()
+            .append(format("nohup java -cp ./lib/%s", resolver.getFilename()))
+            .append(format(" -Xmx%s -Xms%s", maxHeapMemorySize, initialHeapMemorySize))
+            .append(format(" -Dhazelcast.config=./conf/%s", getConfigFileName()))
+            .append(format(" com.hazelcast.core.server.StartServer >> %s 2>&1 </dev/null &", getLogFileLocation()));
+        
+        newScript(MutableMap.of(USE_PID_FILE, true), LAUNCHING)
+            .updateTaskAndFailOnNonZeroResultCode()
+            .body.append(commandBuilder.toString())
+            .execute();
+    }
+       
+    public String getConfigFileName() {
+        return entity.getConfig(HazelcastNode.CONFIG_FILE_NAME);
+    }
+    
+    public String getHeapMemorySize() {
+        return entity.getConfig(HazelcastNode.NODE_HEAP_MEMORY_SIZE);
+    }
+    
+    @Override
+    public boolean isRunning() {       
+        return newScript(MutableMap.of(USE_PID_FILE, true), CHECK_RUNNING).execute() == 0;
+    }
+    
+    @Override
+    public void stop() {
+        newScript(MutableMap.of(USE_PID_FILE, true), STOPPING).execute();
+    }
+    
+    @Override
+    public void kill() {
+        newScript(MutableMap.of(USE_PID_FILE, true), KILLING).execute();
+    }
+
+    public List<String> getHazelcastNodesList() throws ExecutionException, InterruptedException {
+        HazelcastCluster cluster = (HazelcastCluster) entity.getParent();
+        List<String> result = Lists.newArrayList();
+
+        for (Entity member : cluster.getMembers()) {
+            String address = Entities.attributeSupplierWhenReady(member, HazelcastNode.SUBNET_ADDRESS).get();
+            Integer port = Entities.attributeSupplierWhenReady(member, HazelcastNode.NODE_PORT).get();
+            
+            String addressAndPort = String.format("%s:%d", address, port);
+            
+            if (LOG.isInfoEnabled()) {
+                LOG.info("Adding {} to the members' list of {}", addressAndPort, entity.getAttribute(HazelcastNode.NODE_NAME));
+            }
+            result.add(addressAndPort);
+        }
+        
+        return result;
+    }
+
+    @Override
+    protected String getLogFileLocation() {
+        return Os.mergePathsUnix(getRunDir(),"/log/out.log");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml b/software/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml
new file mode 100644
index 0000000..459be4e
--- /dev/null
+++ b/software/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml
@@ -0,0 +1,65 @@
+[#ftl]
+<?xml version="1.0" encoding="UTF-8"?>
+
+<hazelcast xsi:schemaLocation="http://www.hazelcast.com/schema/config hazelcast-config-3.4.xsd"
+           xmlns="http://www.hazelcast.com/schema/config"
+           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <group>
+        <name>${entity.groupName}</name>
+        <password>${entity.groupPassword}</password>
+    </group>
+    <management-center enabled="false">http://localhost:8080/mancenter</management-center>
+    <network>
+        <port auto-increment="true" port-count="100">${entity.nodePort?c}</port>
+        <outbound-ports>
+            <!--
+            Allowed port range when connecting to other nodes.
+            0 or * means use system provided port.
+            -->
+            <ports>0</ports>
+        </outbound-ports>
+        
+        <interfaces enabled="true">
+            <interface>${entity.listenAddress}</interface> 
+        </interfaces> 
+        
+        <join>
+            <multicast enabled="false" />
+
+            <tcp-ip enabled="true">
+            [#list driver.hazelcastNodesList as member]
+                <member>${member}</member>
+            [/#list]
+            </tcp-ip>
+            
+            <aws enabled="false" />
+
+        </join>
+
+        <ssl enabled="false"/>
+        <socket-interceptor enabled="false"/>
+        <symmetric-encryption enabled="false"/>
+
+    </network>
+    <partition-group enabled="false"/>
+
+    <map name="default">
+        <in-memory-format>BINARY</in-memory-format>
+        <backup-count>1</backup-count>
+        <async-backup-count>0</async-backup-count>
+        <time-to-live-seconds>0</time-to-live-seconds>
+        <max-idle-seconds>0</max-idle-seconds>
+        <eviction-policy>NONE</eviction-policy>
+        <max-size policy="PER_NODE">0</max-size>
+        <eviction-percentage>25</eviction-percentage>
+        <min-eviction-check-millis>100</min-eviction-check-millis>
+        <merge-policy>com.hazelcast.map.merge.PutIfAbsentMapMergePolicy</merge-policy>
+    </map>
+
+    <serialization>
+        <portable-version>0</portable-version>
+    </serialization>
+
+    <services enable-defaults="true"/>
+
+</hazelcast>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java
new file mode 100644
index 0000000..f1d44fc
--- /dev/null
+++ b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.brooklyn.entity.nosql.hazelcast;
+
+import org.apache.brooklyn.entity.nosql.hazelcast.HazelcastCluster;
+import org.apache.brooklyn.entity.nosql.hazelcast.HazelcastNode;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.entity.AbstractEc2LiveTest;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.Attributes;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class HazelcastClusterEc2LiveTest extends AbstractEc2LiveTest {
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(HazelcastClusterEc2LiveTest.class);
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        HazelcastCluster cluster = app.createAndManageChild(EntitySpec.create(HazelcastCluster.class)
+                .configure(HazelcastCluster.INITIAL_SIZE, 3)
+                .configure(HazelcastCluster.MEMBER_SPEC, EntitySpec.create(HazelcastNode.class)));
+        app.start(ImmutableList.of(loc));
+
+        EntityTestUtils.assertAttributeEqualsEventually(cluster, HazelcastNode.SERVICE_UP, true);
+
+        HazelcastNode first = (HazelcastNode) Iterables.get(cluster.getMembers(), 0);
+        HazelcastNode second = (HazelcastNode) Iterables.get(cluster.getMembers(), 1);
+
+        assertNodesUpAndInCluster(first, second);
+        
+        EntityTestUtils.assertAttributeEqualsEventually(cluster, Attributes.SERVICE_UP, true);
+    }
+    
+    private void assertNodesUpAndInCluster(final HazelcastNode... nodes) {
+        for (final HazelcastNode node : nodes) {
+            EntityTestUtils.assertAttributeEqualsEventually(node, HazelcastNode.SERVICE_UP, true);
+        }
+    }
+
+    @Test(enabled = false)
+    public void testDummy() {
+    } // Convince TestNG IDE integration that this really does have test methods
+
+    
+    @Test(groups = {"Live", "Live-sanity"})
+    @Override
+    public void test_CentOS_6_3() throws Exception {
+        super.test_CentOS_6_3();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3635a465/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java
new file mode 100644
index 0000000..0e9fe0b
--- /dev/null
+++ b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.brooklyn.entity.nosql.hazelcast;
+
+import org.apache.brooklyn.entity.nosql.hazelcast.HazelcastCluster;
+import org.apache.brooklyn.entity.nosql.hazelcast.HazelcastNode;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.entity.AbstractSoftlayerLiveTest;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.Attributes;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class HazelcastClusterSoftlayerLiveTest extends AbstractSoftlayerLiveTest {
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(HazelcastClusterSoftlayerLiveTest.class);
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        HazelcastCluster cluster = app.createAndManageChild(EntitySpec.create(HazelcastCluster.class)
+                .configure(HazelcastCluster.INITIAL_SIZE, 3)
+                .configure(HazelcastCluster.MEMBER_SPEC, EntitySpec.create(HazelcastNode.class)));
+        app.start(ImmutableList.of(loc));
+
+        EntityTestUtils.assertAttributeEqualsEventually(cluster, HazelcastNode.SERVICE_UP, true);
+
+        HazelcastNode first = (HazelcastNode) Iterables.get(cluster.getMembers(), 0);
+        HazelcastNode second = (HazelcastNode) Iterables.get(cluster.getMembers(), 1);
+
+        assertNodesUpAndInCluster(first, second);
+        
+        EntityTestUtils.assertAttributeEqualsEventually(cluster, Attributes.SERVICE_UP, true);
+    }
+    
+    private void assertNodesUpAndInCluster(final HazelcastNode... nodes) {
+        for (final HazelcastNode node : nodes) {
+            EntityTestUtils.assertAttributeEqualsEventually(node, HazelcastNode.SERVICE_UP, true);
+        }
+    }
+
+    @Test(enabled = false)
+    public void testDummy() {
+    } // Convince TestNG IDE integration that this really does have test methods
+
+    
+    @Test(groups = {"Live", "Live-sanity"})
+    @Override
+    public void test_Ubuntu_12_0_4() throws Exception {
+        super.test_Ubuntu_12_0_4();
+    }
+}