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/23 12:06:45 UTC
[22/71] [abbrv] incubator-brooklyn git commit: Merge commit 'e430723'
into reorg2
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-library/software/nosql/pom.xml
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/pom.xml
index 0000000,4fd2d18..32dbeb6
mode 000000,100644..100644
--- a/brooklyn-library/software/nosql/pom.xml
+++ b/brooklyn-library/software/nosql/pom.xml
@@@ -1,0 -1,291 +1,300 @@@
+ <?xml version="1.0" encoding="UTF-8"?>
+ <!--
+ 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>
+ <artifactId>brooklyn-software-nosql</artifactId>
+ <packaging>jar</packaging>
+ <name>Brooklyn NoSQL Data Store Software Entities</name>
+ <description>
+ Brooklyn entities for NoSQL data store software entities
+ </description>
+
+ <parent>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-parent</artifactId>
+ <version>0.9.0-SNAPSHOT</version> <!-- BROOKLYN_VERSION -->
+ <relativePath>../../parent/pom.xml</relativePath>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-software-base</artifactId>
+ <version>${project.version}</version>
+ <exclusions>
+ <!-- Dependency versions mismatch between transitive dependencies, declare explicitly -->
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-software-webapp</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <!-- just to access DatastoreMixins -->
+ <artifactId>brooklyn-software-database</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-policy</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-utils-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <!-- for mongodb sensors -->
+ <dependency>
+ <groupId>org.mongodb</groupId>
+ <artifactId>mongo-java-driver</artifactId>
+ <version>${mongodb.version}</version>
+ </dependency>
+
+ <!-- for redis testing -->
+ <dependency>
+ <groupId>redis.clients</groupId>
+ <artifactId>jedis</artifactId>
+ <version>${redis.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- for cassandra testing -->
+ <dependency>
+ <groupId>com.netflix.astyanax</groupId>
+ <artifactId>astyanax</artifactId>
+ <version>${astyanax.version}</version>
+ <scope>test</scope>
+ <exclusions>
+ <!-- Dependency versions mismatch between transitive dependencies, declare explicitly -->
+ <exclusion>
+ <artifactId>slf4j-log4j12</artifactId>
+ <groupId>org.slf4j</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>log4j</artifactId>
+ <groupId>log4j</groupId>
+ </exclusion>
+ <exclusion>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>${jclouds.groupId}.provider</groupId>
+ <artifactId>rackspace-cloudservers-uk</artifactId>
+ <version>${jclouds.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- for couchdb testing -->
+ <dependency>
+ <groupId>com.google.code.jcouchdb</groupId>
+ <artifactId>jcouchdb</artifactId>
+ <version>${jcouchdb.version}</version>
+ <scope>test</scope>
+ <exclusions>
+ <!-- Dependency versions mismatch between transitive dependencies, declare explicitly -->
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ </exclusion>
+ <exclusion>
+ <artifactId>slf4j-log4j12</artifactId>
+ <groupId>org.slf4j</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>log4j</artifactId>
+ <groupId>log4j</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>httpcore</artifactId>
+ <groupId>org.apache.httpcomponents</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
++ <!-- for hazelcast testing -->
++ <dependency>
++ <groupId>com.hazelcast</groupId>
++ <artifactId>hazelcast-client</artifactId>
++ <version>${hazelcast.version}</version>
++ <scope>test</scope>
++ </dependency>
++
+ <!-- for solr testing -->
+ <dependency>
+ <groupId>org.apache.solr</groupId>
+ <artifactId>solr-solrj</artifactId>
+ <version>${solr.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${jclouds.groupId}.provider</groupId>
+ <artifactId>aws-ec2</artifactId>
+ <version>${jclouds.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-test-support</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-core</artifactId>
+ <version>${project.version}</version><!--$NO-MVN-MAN-VER$-->
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-software-base</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ <!-- bring in jclouds for testing -->
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-locations-jclouds</artifactId>
+ <version>${project.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Transitive dependencies, declared explicitly due to version mismatch -->
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>${commons-logging.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-codec</groupId>
+ <artifactId>commons-codec</artifactId>
+ <version>${commons-codec.version}</version>
+ </dependency>
+ </dependencies>
+ <build>
+ <pluginManagement>
+ <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/cassandra/cassandra-1.2.yaml</exclude>
+ <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/cassandra/cassandra-2.0.yaml</exclude>
+ <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>
+ <exclude>src/test/resources/test-mongodb-configserver.conf</exclude>
+ <exclude>src/test/resources/test-mongodb-router.conf</exclude>
+ <exclude>src/test/resources/mongodb-keyfile</exclude>
+ <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/redis/redis.conf</exclude>
+ <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/redis/slave.conf</exclude>
+ <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/riak/app.config</exclude>
+ <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/riak/vm.args</exclude>
+ <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/riak/riak.conf</exclude>
+ <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/riak/riak-mac.conf</exclude>
+ <exclude>src/main/resources/org/apache/brooklyn/entity/nosql/solr/solr.xml</exclude>
+
+ <!--
+ The source code for cassandra-multicloud-snitch.jar is in sandbox/cassandra-multicloud-snitch.
+ This snitch handles Cassandra datacenters in different cloud providers.
+ The source will be contributed to the Cassandra project; when it is available in the
+ Cassandra distro (and when we don't want to give backwards compatibility support for
+ older Cassandra versions), then we can delete it from Brooklyn.
+ -->
+ <exclude>**/src/main/resources/brooklyn/entity/nosql/cassandra/cassandra-multicloud-snitch.jar</exclude>
+
+ <!--
+ This is a trivial Solr example, used for testing that a simple definition is deployed
+ correctly. It is "without any degree of creativity". It is stored as a binary tgz, rather
+ than us generating the tgz as part of the build, to keep the build process and testing
+ simpler.
+ -->
+ <exclude>**/src/test/resources/solr/example.tgz</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ </project>
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNodeImpl.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNodeImpl.java
index 0000000,14867de..933e818
mode 000000,100644..100644
--- a/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNodeImpl.java
+++ b/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/couchdb/CouchDBNodeImpl.java
@@@ -1,0 -1,108 +1,109 @@@
+ /*
+ * 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.couchdb;
+
+ import java.util.concurrent.TimeUnit;
+
+ import javax.annotation.Nullable;
+
++import org.apache.brooklyn.core.entity.EntityFunctions;
+ import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl;
+ import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
+ import org.apache.brooklyn.entity.webapp.WebAppServiceMethods;
+ 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.core.flags.TypeCoercions;
+ import org.apache.brooklyn.util.guava.Functionals;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+ import com.google.common.base.Function;
+ import com.google.common.base.Functions;
+
+ /**
+ * Implementation of {@link CouchDBNode}.
+ */
+ public class CouchDBNodeImpl extends SoftwareProcessImpl implements CouchDBNode {
+
+ private static final Logger log = LoggerFactory.getLogger(CouchDBNodeImpl.class);
+
+ public CouchDBNodeImpl() {
+ }
+
+ public Integer getHttpPort() { return getAttribute(CouchDBNode.HTTP_PORT); }
+ public Integer getHttpsPort() { return getAttribute(CouchDBNode.HTTPS_PORT); }
+ public String getClusterName() { return getAttribute(CouchDBNode.CLUSTER_NAME); }
+
+ @Override
+ public Class<CouchDBNodeDriver> getDriverInterface() {
+ return CouchDBNodeDriver.class;
+ }
+
+ private volatile HttpFeed httpFeed;
+
+ @Override
+ protected void connectSensors() {
+ super.connectSensors();
+
+ connectServiceUpIsRunning();
+
+ boolean retrieveUsageMetrics = getConfig(RETRIEVE_USAGE_METRICS);
+
+ httpFeed = HttpFeed.builder()
+ .entity(this)
+ .period(500, TimeUnit.MILLISECONDS)
+ .baseUri(String.format("http://%s:%d/_stats", getAttribute(HOSTNAME), getHttpPort()))
+ .poll(new HttpPollConfig<Integer>(REQUEST_COUNT)
+ .onSuccess(HttpValueFunctions.jsonContents(new String[] { "httpd", "requests", "count" }, Integer.class))
- .onFailureOrException(Functions.constant(-1))
++ .onFailureOrException(EntityFunctions.attribute(this, REQUEST_COUNT))
+ .enabled(retrieveUsageMetrics))
+ .poll(new HttpPollConfig<Integer>(ERROR_COUNT)
+ .onSuccess(HttpValueFunctions.jsonContents(new String[] { "httpd_status_codes", "404", "count" }, Integer.class))
+ .onFailureOrException(Functions.constant(-1))
+ .enabled(retrieveUsageMetrics))
+ .poll(new HttpPollConfig<Integer>(TOTAL_PROCESSING_TIME)
+ .onSuccess(HttpValueFunctions.jsonContents(new String[] { "couchdb", "request_time", "count" }, Integer.class))
+ .onFailureOrException(Functions.constant(-1))
+ .enabled(retrieveUsageMetrics))
+ .poll(new HttpPollConfig<Integer>(MAX_PROCESSING_TIME)
+ .onSuccess(Functionals.chain(HttpValueFunctions.jsonContents(new String[] { "couchdb", "request_time", "max" }, Double.class), TypeCoercions.function(Integer.class)))
+ .onFailureOrException(Functions.constant(-1))
+ .enabled(retrieveUsageMetrics))
+ .build();
+
+ WebAppServiceMethods.connectWebAppServerPolicies(this);
+ }
+
+ @Override
+ public void disconnectSensors() {
+ super.disconnectSensors();
+ if (httpFeed != null) httpFeed.stop();
+ disconnectServiceUpIsRunning();
+ }
+
+ /** @see JavaWebAppSoftwareProcessImpl#postStop() */
+ @Override
+ protected void postStop() {
+ super.postStop();
+ // zero our workrate derived workrates.
+ sensors().set(REQUESTS_PER_SECOND_LAST, 0D);
+ sensors().set(REQUESTS_PER_SECOND_IN_WINDOW, 0D);
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
index 0000000,0000000..3962fd1
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastCluster.java
@@@ -1,0 -1,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.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/018a0e15/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
index 0000000,0000000..854c0a3
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterImpl.java
@@@ -1,0 -1,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(config().get(HazelcastCluster.MEMBER_SPEC));
++
++ spec.configure(HazelcastNode.NODE_CLUSTER_NAME, config().get(HazelcastCluster.CLUSTER_NAME));
++ spec.configure(HazelcastNode.GROUP_NAME, config().get(HazelcastCluster.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/018a0e15/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
index 0000000,0000000..768179c
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNode.java
@@@ -1,0 -1,0 +1,101 @@@
++/*
++ * 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.5.4");
++
++ @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+"));
++
++ @SetFromFlag("nodeClusterName")
++ BasicAttributeSensorAndConfigKey<String> NODE_CLUSTER_NAME = new BasicAttributeSensorAndConfigKey<String>(String.class,
++ "hazelcast.node.cluster.name", "Name of the Hazelcast cluster which node is part of", "");
++
++ /**
++ * 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/018a0e15/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java
index 0000000,0000000..8cf1e0c
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeDriver.java
@@@ -1,0 -1,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/018a0e15/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
index 0000000,0000000..6d13b74
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeImpl.java
@@@ -1,0 -1,0 +1,146 @@@
++/*
++ * 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/018a0e15/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java
index 0000000,0000000..2a9b9c5
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeSshDriver.java
@@@ -1,0 -1,0 +1,164 @@@
++/*
++ * 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 org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++import org.apache.brooklyn.api.entity.Entity;
++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 org.apache.brooklyn.util.text.Strings;
++
++import com.google.common.base.Joiner;
++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(HazelcastNodeImpl 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;
++
++ ImmutableList<String> commands = ImmutableList.<String>builder()
++ .add(format("nohup java -cp ./lib/%s", resolver.getFilename()))
++ .add(format("-Xmx%s -Xms%s", maxHeapMemorySize, initialHeapMemorySize))
++ .add(format("-Dhazelcast.config=./conf/%s", getConfigFileName()))
++ .add(format("com.hazelcast.core.server.StartServer >> %s 2>&1 </dev/null &", getLogFileLocation()))
++ .build();
++
++ newScript(MutableMap.of(USE_PID_FILE, true), LAUNCHING)
++ .updateTaskAndFailOnNonZeroResultCode()
++ .body.append(Joiner.on(" ").join(commands))
++ .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() {
++ List<String> result = Lists.newArrayList();
++
++ if (Strings.isBlank(entity.getAttribute(HazelcastNode.NODE_CLUSTER_NAME))) {
++ result.add(String.format("%s:%d", entity.getAttribute(HazelcastNode.SUBNET_ADDRESS),
++ entity.getAttribute(HazelcastNode.NODE_PORT)));
++ } else {
++ HazelcastCluster cluster = (HazelcastCluster) entity.getParent();
++
++ 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/018a0e15/brooklyn-library/software/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml
index 0000000,0000000..2f4a263
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/main/resources/org/apache/brooklyn/entity/nosql/hazelcast/hazelcast-brooklyn.xml
@@@ -1,0 -1,0 +1,64 @@@
++[#ftl]
++<?xml version="1.0" encoding="UTF-8"?>
++
++<hazelcast xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
++ xsi:schemaLocation="http://www.hazelcast.com/schema/config
++ http://www.hazelcast.com/schema/config/hazelcast-config-3.5.xsd"
++ xmlns="http://www.hazelcast.com/schema/config">
++
++ <properties>
++ <property name="hazelcast.discovery.enabled">true</property>
++ </properties>
++
++ <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>
++
++ <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"/>
++
++ </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/018a0e15/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java
index 0000000,0000000..111ba9e
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterEc2LiveTest.java
@@@ -1,0 -1,0 +1,47 @@@
++/*
++ * 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.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++import org.testng.annotations.Test;
++
++import org.apache.brooklyn.entity.AbstractEc2LiveTest;
++import org.apache.brooklyn.api.location.Location;
++
++public class HazelcastClusterEc2LiveTest extends AbstractEc2LiveTest {
++ @SuppressWarnings("unused")
++ private static final Logger LOG = LoggerFactory.getLogger(HazelcastClusterEc2LiveTest.class);
++
++ @Override
++ protected void doTest(Location loc) throws Exception {
++ HazelcastTestHelper.testHazelcastCluster(app, loc);
++ }
++
++ @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/018a0e15/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterNodeIntegrationTest.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterNodeIntegrationTest.java
index 0000000,0000000..dc89934
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterNodeIntegrationTest.java
@@@ -1,0 -1,0 +1,49 @@@
++/*
++ * 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.location.Location;
++import org.apache.brooklyn.core.entity.Entities;
++import org.apache.brooklyn.core.test.entity.TestApplication;
++
++import org.testng.annotations.AfterMethod;
++import org.testng.annotations.BeforeMethod;
++import org.testng.annotations.Test;
++import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
++
++public class HazelcastClusterNodeIntegrationTest {
++ private TestApplication app;
++ private Location location;
++
++ @BeforeMethod(alwaysRun = true)
++ public void setup() throws Exception {
++ app = TestApplication.Factory.newManagedInstanceForTests();;
++ location = new LocalhostMachineProvisioningLocation();
++ }
++
++ @AfterMethod(alwaysRun = true)
++ public void shutdown() {
++ Entities.destroyAll(app.getManagementContext());
++ }
++
++ @Test(groups = {"Integration"})
++ public void testHazelcastCluster() {
++ HazelcastTestHelper.testHazelcastCluster(app, location);
++ }
++}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java
index 0000000,0000000..412ce87
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastClusterSoftlayerLiveTest.java
@@@ -1,0 -1,0 +1,47 @@@
++/*
++ * 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.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++import org.testng.annotations.Test;
++
++import org.apache.brooklyn.entity.AbstractSoftlayerLiveTest;
++import org.apache.brooklyn.api.location.Location;
++
++public class HazelcastClusterSoftlayerLiveTest extends AbstractSoftlayerLiveTest {
++ @SuppressWarnings("unused")
++ private static final Logger LOG = LoggerFactory.getLogger(HazelcastClusterSoftlayerLiveTest.class);
++
++ @Override
++ protected void doTest(Location loc) throws Exception {
++ HazelcastTestHelper.testHazelcastCluster(app, loc);
++ }
++
++ @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/018a0e15/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeIntegrationTest.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeIntegrationTest.java
index 0000000,0000000..26a18c5
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastNodeIntegrationTest.java
@@@ -1,0 -1,0 +1,107 @@@
++/*
++ * 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 org.testng.Assert.assertEquals;
++
++import java.net.URISyntaxException;
++
++import org.apache.brooklyn.api.entity.EntitySpec;
++import org.apache.brooklyn.api.location.Location;
++import org.apache.brooklyn.core.entity.Attributes;
++import org.apache.brooklyn.core.entity.Entities;
++import org.apache.brooklyn.core.entity.EntityAsserts;
++import org.apache.brooklyn.core.entity.trait.Startable;
++import org.apache.brooklyn.core.test.entity.TestApplication;
++import org.apache.brooklyn.util.http.HttpTool;
++import org.apache.brooklyn.util.http.HttpToolResponse;
++import org.apache.http.client.methods.HttpGet;
++import com.hazelcast.core.HazelcastInstance;
++import com.hazelcast.core.IMap;
++
++import org.testng.annotations.AfterMethod;
++import org.testng.annotations.BeforeMethod;
++import org.testng.annotations.Test;
++import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
++
++import com.google.common.collect.ImmutableList;
++
++public class HazelcastNodeIntegrationTest {
++ protected TestApplication app;
++ protected Location testLocation;
++ protected HazelcastNode hazelcastNode;
++
++ @BeforeMethod(alwaysRun = true)
++ public void setup() throws Exception {
++ app = TestApplication.Factory.newManagedInstanceForTests();;
++ testLocation = new LocalhostMachineProvisioningLocation();
++ }
++
++ @AfterMethod(alwaysRun = true)
++ public void shutdown() {
++ Entities.destroyAll(app.getManagementContext());
++ }
++
++ @Test(groups = {"Integration"})
++ public void testHazelcastStartupAndShutdown() {
++ hazelcastNode = app.createAndManageChild(EntitySpec.create(HazelcastNode.class));
++ app.start(ImmutableList.of(testLocation));
++ EntityAsserts.assertAttributeEqualsEventually(hazelcastNode, Startable.SERVICE_UP, true);
++
++ hazelcastNode.stop();
++ EntityAsserts.assertAttributeEqualsEventually(hazelcastNode, Startable.SERVICE_UP, false);
++ }
++
++ @Test(groups = {"Integration"})
++ public void testHazelcastRestInterface() throws URISyntaxException {
++ hazelcastNode = app.createAndManageChild(EntitySpec.create(HazelcastNode.class));
++ app.start(ImmutableList.of(testLocation));
++
++ EntityAsserts.assertAttributeEqualsEventually(hazelcastNode, Startable.SERVICE_UP, true);
++ EntityAsserts.assertAttributeEquals(hazelcastNode, HazelcastNode.NODE_PORT, 5701);
++
++ String baseUri = String.format("http://%s:%d/hazelcast/rest/cluster", hazelcastNode.getAttribute(Attributes.HOSTNAME), hazelcastNode.getAttribute(HazelcastNode.NODE_PORT));
++ HttpToolResponse response = HttpTool.execAndConsume(
++ HttpTool.httpClientBuilder().build(),
++ new HttpGet(baseUri));
++ assertEquals(response.getResponseCode(), 200);
++ }
++
++ @Test(groups = {"Integration"})
++ public void testHazelcastClient() throws URISyntaxException {
++ hazelcastNode = app.createAndManageChild(EntitySpec.create(HazelcastNode.class));
++ app.start(ImmutableList.of(testLocation));
++
++ EntityAsserts.assertAttributeEqualsEventually(hazelcastNode, Startable.SERVICE_UP, true);
++ HazelcastTestHelper helper = new HazelcastTestHelper(hazelcastNode.getAttribute(Attributes.HOSTNAME), hazelcastNode.getAttribute(HazelcastNode.NODE_PORT));
++
++ HazelcastInstance client = helper.getClient();
++ HazelcastInstance client2 = helper.getClient();
++
++ client.getMap(HazelcastTestHelper.GROUP_NAME).put("A", "a");
++ client2.getMap(HazelcastTestHelper.GROUP_NAME).put("B", "b");
++
++ final IMap<Object, Object> map = client.getMap(HazelcastTestHelper.GROUP_NAME);
++ assertEquals("a", map.get("A"));
++ assertEquals("b", map.get("B"));
++
++ client.shutdown();
++ client2.shutdown();
++ }
++}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastTestHelper.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastTestHelper.java
index 0000000,0000000..b48e0bd
new file mode 100644
--- /dev/null
+++ b/brooklyn-library/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/hazelcast/HazelcastTestHelper.java
@@@ -1,0 -1,0 +1,76 @@@
++/*
++ * 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.entity.EntitySpec;
++import org.apache.brooklyn.api.location.Location;
++import org.apache.brooklyn.core.entity.Attributes;
++import org.apache.brooklyn.core.entity.EntityAsserts;
++import org.apache.brooklyn.core.test.entity.TestApplication;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
++import com.google.common.collect.ImmutableList;
++import com.google.common.collect.Iterables;
++import com.hazelcast.client.HazelcastClient;
++import com.hazelcast.client.config.ClientConfig;
++import com.hazelcast.core.HazelcastInstance;
++
++public class HazelcastTestHelper {
++ private static final Logger LOG = LoggerFactory.getLogger(HazelcastTestHelper.class);
++ private static ClientConfig clientConfig;
++
++ public static final String GROUP_NAME = "brooklyn";
++ public static final String GROUP_PASS = "brooklyn";
++
++ public HazelcastTestHelper(String hazelcastAddress, Integer hazelcastPort) {
++ clientConfig = new ClientConfig();
++ clientConfig.getGroupConfig().setName(GROUP_NAME).setPassword(GROUP_PASS);
++ clientConfig.getNetworkConfig().addAddress(String.format("%s:%d", hazelcastAddress, hazelcastPort));
++ }
++
++ public HazelcastInstance getClient() {
++ HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig);
++ LOG.info("Hazelcast client {}", client.getName());
++
++ return client;
++ }
++
++ public static void testHazelcastCluster(TestApplication app, Location loc) {
++ 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));
++
++ EntityAsserts.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);
++
++ EntityAsserts.assertAttributeEqualsEventually(cluster, Attributes.SERVICE_UP, true);
++ }
++
++ private static void assertNodesUpAndInCluster(final HazelcastNode... nodes) {
++ for (final HazelcastNode node : nodes) {
++ EntityAsserts.assertAttributeEqualsEventually(node, HazelcastNode.SERVICE_UP, true);
++ }
++ }
++}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-library/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsService.java
----------------------------------------------------------------------
diff --cc brooklyn-library/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsService.java
index 0000000,2896b48..6e55d5d
mode 000000,100644..100644
--- a/brooklyn-library/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsService.java
+++ b/brooklyn-library/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsService.java
@@@ -1,0 -1,59 +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.dns;
+
+ import java.util.Map;
+
+ import org.apache.brooklyn.api.entity.Entity;
+ import org.apache.brooklyn.api.entity.Group;
+ import org.apache.brooklyn.api.sensor.AttributeSensor;
+ import org.apache.brooklyn.config.ConfigKey;
+ import org.apache.brooklyn.core.config.ConfigKeys;
+ import org.apache.brooklyn.core.entity.Attributes;
+ import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
+ import org.apache.brooklyn.core.entity.trait.Startable;
+ import org.apache.brooklyn.core.location.geo.HostGeoInfo;
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
++import org.apache.brooklyn.core.sensor.Sensors;
++import org.apache.brooklyn.util.core.flags.SetFromFlag;
+
+ import com.google.common.reflect.TypeToken;
+
+ public interface AbstractGeoDnsService extends Entity {
+
- public static final ConfigKey<Boolean> INCLUDE_HOMELESS_ENTITIES = ConfigKeys.newBooleanConfigKey("geodns.includeHomeless", "Whether to include entities whose geo-coordinates cannot be inferred", false);
- public static final ConfigKey<Boolean> USE_HOSTNAMES = ConfigKeys.newBooleanConfigKey("geodns.useHostnames", "Whether to use the hostname for the returned value for routing, rather than IP address (defaults to true)", true);
-
- public static final AttributeSensor<Lifecycle> SERVICE_STATE_ACTUAL = Attributes.SERVICE_STATE_ACTUAL;
- public static final AttributeSensor<Boolean> SERVICE_UP = Startable.SERVICE_UP;
- public static final AttributeSensor<String> HOSTNAME = Attributes.HOSTNAME;
- public static final AttributeSensor<String> ADDRESS = Attributes.ADDRESS;
- @SuppressWarnings("serial")
- public static final AttributeSensor<Map<String,String>> TARGETS = new BasicAttributeSensor<Map<String,String>>(
- new TypeToken<Map<String,String>>() {}, "geodns.targets", "Map of targets currently being managed (entity ID to URL)");
-
- public void setServiceState(Lifecycle state);
++ @SetFromFlag("includeHomelessEntities")
++ ConfigKey<Boolean> INCLUDE_HOMELESS_ENTITIES = ConfigKeys.newBooleanConfigKey(
++ "geodns.includeHomeless", "Whether to include entities whose geo-coordinates cannot be inferred", false);
++
++ @SetFromFlag("useHostnames")
++ ConfigKey<Boolean> USE_HOSTNAMES = ConfigKeys.newBooleanConfigKey(
++ "geodns.useHostnames", "Whether to use the hostname for the returned value for routing, rather than IP address (defaults to true)", true);
++
++ @SetFromFlag("provider")
++ ConfigKey<Group> ENTITY_PROVIDER = ConfigKeys.newConfigKey(Group.class,
++ "geodns.entityProvider", "The group whose members should be tracked");
++
++ /** @see Lifecycle#RUNNING */
++ @SetFromFlag("filterForRunning")
++ ConfigKey<Boolean> FILTER_FOR_RUNNING = ConfigKeys.newBooleanConfigKey(
++ "geodns.filterForRunning", "Whether to only track targets whose status is \"RUNNING\"", true);
++
++ AttributeSensor<Lifecycle> SERVICE_STATE_ACTUAL = Attributes.SERVICE_STATE_ACTUAL;
++ AttributeSensor<Boolean> SERVICE_UP = Startable.SERVICE_UP;
++ AttributeSensor<String> HOSTNAME = Attributes.HOSTNAME;
++ AttributeSensor<String> ADDRESS = Attributes.ADDRESS;
++
++ AttributeSensor<Map<String,String>> TARGETS = Sensors.newSensor(new TypeToken<Map<String, String>>() {},
++ "geodns.targets", "Map of targets currently being managed (entity ID to URL)");
++
++ void setServiceState(Lifecycle state);
+
+ /** sets target to be a group whose *members* will be searched (non-Group items not supported) */
+ // prior to 0.7.0 the API accepted non-group items, but did not handle them correctly
- public void setTargetEntityProvider(final Group entityProvider);
++ void setTargetEntityProvider(final Group entityProvider);
+
+ /** should return the hostname which this DNS service is configuring */
- public String getHostname();
++ String getHostname();
+
- public Map<Entity, HostGeoInfo> getTargetHosts();
++ Map<Entity, HostGeoInfo> getTargetHosts();
+ }