You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2015/07/16 01:09:52 UTC

[08/12] incubator-brooklyn git commit: brooklyn-example-simple-web-cluster: add org.apache package prefix

brooklyn-example-simple-web-cluster: add org.apache package prefix


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

Branch: refs/heads/master
Commit: 9b8bde02dc71d8b7183216d041b0dfc81924cbd3
Parents: 59cc05d
Author: Ciprian Ciubotariu <ch...@gmx.net>
Authored: Wed Jul 15 18:11:11 2015 +0300
Committer: Ciprian Ciubotariu <ch...@gmx.net>
Committed: Wed Jul 15 18:47:01 2015 +0300

----------------------------------------------------------------------
 .../src/main/assembly/scripts/start.sh          |   2 +-
 .../brooklyn/demo/NodeJsTodoApplication.java    |  59 ------
 .../brooklyn/demo/SingleWebServerExample.java   |  67 ------
 .../demo/WebClusterDatabaseExample.java         | 123 -----------
 .../demo/WebClusterDatabaseExampleApp.java      | 175 ----------------
 .../demo/WebClusterDatabaseExampleGroovy.groovy |  93 ---------
 .../java/brooklyn/demo/WebClusterExample.java   |  96 ---------
 .../brooklyn/demo/NodeJsTodoApplication.java    |  59 ++++++
 .../brooklyn/demo/SingleWebServerExample.java   |  67 ++++++
 .../demo/WebClusterDatabaseExample.java         | 123 +++++++++++
 .../demo/WebClusterDatabaseExampleApp.java      | 175 ++++++++++++++++
 .../demo/WebClusterDatabaseExampleGroovy.groovy |  93 +++++++++
 .../apache/brooklyn/demo/WebClusterExample.java |  96 +++++++++
 .../brooklyn/demo/glossy-3d-blue-web-icon.png   | Bin 46490 -> 0 bytes
 .../brooklyn/demo/nodejs-riak-todo.yaml         |  46 -----
 .../resources/brooklyn/demo/nodejs-todo.yaml    |  53 -----
 .../src/main/resources/logback-custom.xml       |   2 +-
 .../brooklyn/demo/glossy-3d-blue-web-icon.png   | Bin 0 -> 46490 bytes
 .../apache/brooklyn/demo/nodejs-riak-todo.yaml  |  46 +++++
 .../org/apache/brooklyn/demo/nodejs-todo.yaml   |  53 +++++
 ...lusterDatabaseExampleAppIntegrationTest.java | 205 ------------------
 ...lusterDatabaseExampleAppIntegrationTest.java | 206 +++++++++++++++++++
 22 files changed, 920 insertions(+), 919 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/assembly/scripts/start.sh
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/assembly/scripts/start.sh b/examples/simple-web-cluster/src/main/assembly/scripts/start.sh
index a4cf2d4..ec4f110 100755
--- a/examples/simple-web-cluster/src/main/assembly/scripts/start.sh
+++ b/examples/simple-web-cluster/src/main/assembly/scripts/start.sh
@@ -19,7 +19,7 @@
 #
 
 if [ -z "$BROOKLYN_APP_CLASS" ] ; then 
-    BROOKLYN_APP_CLASS=brooklyn.demo.WebClusterDatabaseExample
+    BROOKLYN_APP_CLASS=org.apache.brooklyn.demo.WebClusterDatabaseExample
 fi
 
 if [ -z "$JAVA" ] ; then 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/brooklyn/demo/NodeJsTodoApplication.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/brooklyn/demo/NodeJsTodoApplication.java b/examples/simple-web-cluster/src/main/java/brooklyn/demo/NodeJsTodoApplication.java
deleted file mode 100644
index 50d5f74..0000000
--- a/examples/simple-web-cluster/src/main/java/brooklyn/demo/NodeJsTodoApplication.java
+++ /dev/null
@@ -1,59 +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 brooklyn.demo;
-
-import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
-import brooklyn.catalog.Catalog;
-import brooklyn.entity.basic.AbstractApplication;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.nosql.redis.RedisStore;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.trait.Startable;
-import brooklyn.entity.webapp.nodejs.NodeJsWebAppService;
-import brooklyn.event.basic.DependentConfiguration;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * Node.JS Todo Application
- */
-@Catalog(name="NodeJS Todo",
-        description="Node.js is a cross-platform runtime environment for server-side and networking applications. Node.js applications are written in JavaScript",
-        iconUrl="classpath://nodejs-logo.png")
-public class NodeJsTodoApplication extends AbstractApplication implements StartableApplication {
-
-    @Override
-    public void initApp() {
-        RedisStore redis = addChild(EntitySpec.create(RedisStore.class));
-
-        addChild(EntitySpec.create(NodeJsWebAppService.class)
-                .configure(NodeJsWebAppService.APP_GIT_REPOSITORY_URL, "https://github.com/grkvlt/nodejs-todo/")
-                .configure(NodeJsWebAppService.APP_FILE, "server.js")
-                .configure(NodeJsWebAppService.APP_NAME, "nodejs-todo")
-                .configure(NodeJsWebAppService.NODE_PACKAGE_LIST, ImmutableList.of("express", "ejs", "jasmine-node", "underscore", "method-override", "cookie-parser", "express-session", "body-parser", "cookie-session", "redis", "redis-url", "connect"))
-                .configure(SoftwareProcess.SHELL_ENVIRONMENT, ImmutableMap.<String, Object>of(
-                        "REDISTOGO_URL", DependentConfiguration.formatString("redis://%s:%d/",
-                                attributeWhenReady(redis, Attributes.HOSTNAME), attributeWhenReady(redis, RedisStore.REDIS_PORT))))
-                .configure(SoftwareProcess.LAUNCH_LATCH, attributeWhenReady(redis, Startable.SERVICE_UP)));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.java b/examples/simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.java
deleted file mode 100644
index d974e35..0000000
--- a/examples/simple-web-cluster/src/main/java/brooklyn/demo/SingleWebServerExample.java
+++ /dev/null
@@ -1,67 +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 brooklyn.demo;
-
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.AbstractApplication;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.webapp.JavaWebAppService;
-import brooklyn.entity.webapp.jboss.JBoss7Server;
-import brooklyn.launcher.BrooklynLauncher;
-import brooklyn.location.basic.PortRanges;
-import brooklyn.util.CommandLineUtil;
-
-import com.google.common.collect.Lists;
-
-/** This example starts one web app on 8080, waits for a keypress, then stops it. */
-public class SingleWebServerExample extends AbstractApplication {
-
-    public static final Logger LOG = LoggerFactory.getLogger(SingleWebServerExample.class);
-
-    private static final String WAR_PATH = "classpath://hello-world-webapp.war";
-
-    @Override
-    public void initApp() {
-        addChild(EntitySpec.create(JBoss7Server.class)
-                .configure(JavaWebAppService.ROOT_WAR, WAR_PATH)
-                .configure(Attributes.HTTP_PORT, PortRanges.fromString("8080+")));
-    }
-
-    // Shows how to use ApplicationBuilder without sub-classing, but for CLI usage one should sub-class
-    public static void main(String[] argv) throws Exception {
-        List<String> args = Lists.newArrayList(argv);
-        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
-        String location = CommandLineUtil.getCommandLineOption(args, "--location", "localhost");
-
-        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
-                .application(EntitySpec.create(StartableApplication.class, SingleWebServerExample.class).displayName("Brooklyn WebApp example"))
-                .webconsolePort(port)
-                .location(location)
-                .start();
-         
-        Entities.dumpInfo(launcher.getApplications());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.java b/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.java
deleted file mode 100644
index fd7c9ae..0000000
--- a/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExample.java
+++ /dev/null
@@ -1,123 +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 brooklyn.demo;
-
-import static brooklyn.entity.java.JavaEntityMethods.javaSysProp;
-import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
-import static brooklyn.event.basic.DependentConfiguration.formatString;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.enricher.Enrichers;
-import brooklyn.enricher.HttpLatencyDetector;
-import brooklyn.entity.basic.AbstractApplication;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.database.mysql.MySqlNode;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
-import brooklyn.entity.webapp.DynamicWebAppCluster;
-import brooklyn.entity.webapp.JavaWebAppService;
-import brooklyn.entity.webapp.WebAppService;
-import brooklyn.entity.webapp.WebAppServiceConstants;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.Sensors;
-import brooklyn.launcher.BrooklynLauncher;
-import brooklyn.location.basic.PortRanges;
-import brooklyn.policy.autoscaling.AutoScalerPolicy;
-import brooklyn.util.CommandLineUtil;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-/**
- * Launches a 3-tier app with nginx, clustered jboss, and mysql.
- **/
-public class WebClusterDatabaseExample extends AbstractApplication {
-    
-    public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseExample.class);
-    
-    public static final String WAR_PATH = "classpath://hello-world-sql-webapp.war";
-    
-    public static final String DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql";
-    
-    public static final String DB_TABLE = "visitors";
-    public static final String DB_USERNAME = "brooklyn";
-    public static final String DB_PASSWORD = "br00k11n";
-    
-    public static final AttributeSensor<Integer> APPSERVERS_COUNT = Sensors.newIntegerSensor( 
-            "appservers.count", "Number of app servers deployed");
-
-    @Override
-    public void initApp() {
-        MySqlNode mysql = addChild(EntitySpec.create(MySqlNode.class)
-                .configure("creationScriptUrl", DB_SETUP_SQL_URL));
-        
-        ControlledDynamicWebAppCluster web = addChild(EntitySpec.create(ControlledDynamicWebAppCluster.class)
-                .configure(WebAppService.HTTP_PORT, PortRanges.fromString("8080+"))
-                .configure(JavaWebAppService.ROOT_WAR, WAR_PATH)
-                .configure(javaSysProp("brooklyn.example.db.url"), 
-                        formatString("jdbc:%s%s?user=%s\\&password=%s", 
-                                attributeWhenReady(mysql, MySqlNode.DATASTORE_URL), 
-                                DB_TABLE, DB_USERNAME, DB_PASSWORD)) );
-
-        web.addEnricher(HttpLatencyDetector.builder().
-                url(ControlledDynamicWebAppCluster.ROOT_URL).
-                rollup(10, TimeUnit.SECONDS).
-                build());
-
-        // simple scaling policy
-        web.getCluster().addPolicy(AutoScalerPolicy.builder().
-                metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE).
-                metricRange(10, 100).
-                sizeRange(1, 5).
-                build());
-
-        // expose some KPI's
-        addEnricher(Enrichers.builder()
-                .propagating(WebAppServiceConstants.ROOT_URL,
-                        DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW,
-                        HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_IN_WINDOW)
-                .from(web)
-                .build());
-
-        addEnricher(Enrichers.builder()
-                .propagating(ImmutableMap.of(DynamicWebAppCluster.GROUP_SIZE, APPSERVERS_COUNT))
-                .from(web)
-                .build());
-    }
-
-    public static void main(String[] argv) {
-        List<String> args = Lists.newArrayList(argv);
-        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
-        String location = CommandLineUtil.getCommandLineOption(args, "--location", "localhost");
-
-        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
-                .application(EntitySpec.create(StartableApplication.class, WebClusterDatabaseExample.class).displayName("Brooklyn WebApp Cluster with Database example"))
-                .webconsolePort(port)
-                .location(location)
-                .start();
-         
-        Entities.dumpInfo(launcher.getApplications());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleApp.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleApp.java b/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleApp.java
deleted file mode 100644
index 44efa0c..0000000
--- a/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleApp.java
+++ /dev/null
@@ -1,175 +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 brooklyn.demo;
-
-import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
-import static brooklyn.event.basic.DependentConfiguration.formatString;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.catalog.Catalog;
-import brooklyn.catalog.CatalogConfig;
-import brooklyn.config.ConfigKey;
-import brooklyn.enricher.Enrichers;
-import brooklyn.enricher.HttpLatencyDetector;
-import brooklyn.entity.basic.AbstractApplication;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.database.mysql.MySqlNode;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.entity.java.JavaEntityMethods;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
-import brooklyn.entity.webapp.DynamicWebAppCluster;
-import brooklyn.entity.webapp.JavaWebAppService;
-import brooklyn.entity.webapp.WebAppService;
-import brooklyn.entity.webapp.WebAppServiceConstants;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.Sensors;
-import brooklyn.launcher.BrooklynLauncher;
-import brooklyn.location.basic.PortRanges;
-import brooklyn.policy.autoscaling.AutoScalerPolicy;
-import brooklyn.util.BrooklynMavenArtifacts;
-import brooklyn.util.CommandLineUtil;
-import brooklyn.util.ResourceUtils;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-
-/**
- * Launches a 3-tier app with nginx, clustered jboss, and mysql.
- * <p>
- * Includes some advanced features such as KPI / derived sensors,
- * and annotations for use in a catalog.
- * <p>
- * This variant also increases minimum size to 2.  
- * Note the policy min size must have the same value,
- * otherwise it fights with cluster set up trying to reduce the cluster size!
- **/
-@Catalog(name="Elastic Java Web + DB",
-    description="Deploys a WAR to a load-balanced elastic Java AppServer cluster, " +
-            "with an auto-scaling policy, " +
-            "wired to a database initialized with the provided SQL; " +
-            "defaults to a 'Hello World' chatroom app.",
-    iconUrl="classpath://brooklyn/demo/glossy-3d-blue-web-icon.png")
-public class WebClusterDatabaseExampleApp extends AbstractApplication implements StartableApplication {
-    
-    public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseExampleApp.class);
-    
-    public static final String DEFAULT_LOCATION = "localhost";
-
-    public static final String DEFAULT_WAR_PATH = ResourceUtils.create(WebClusterDatabaseExampleApp.class)
-            // take this war, from the classpath, or via maven if not on the classpath
-            .firstAvailableUrl(
-                    "classpath://hello-world-sql-webapp.war",
-                    BrooklynMavenArtifacts.localUrl("example", "brooklyn-example-hello-world-sql-webapp", "war"))
-            .or("classpath://hello-world-sql-webapp.war");
-    
-    @CatalogConfig(label="WAR (URL)", priority=2)
-    public static final ConfigKey<String> WAR_PATH = ConfigKeys.newConfigKey(
-        "app.war", "URL to the application archive which should be deployed", 
-        DEFAULT_WAR_PATH);    
-
-    // TODO to expose in catalog we need to let the keystore url be specified (not hard)
-    // and also confirm that this works for nginx (might be a bit fiddly);
-    // booleans in the gui are working (With checkbox)
-    @CatalogConfig(label="HTTPS")
-    public static final ConfigKey<Boolean> USE_HTTPS = ConfigKeys.newConfigKey(
-            "app.https", "Whether the application should use HTTPS only or just HTTP only (default)", false);
-    
-    public static final String DEFAULT_DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql";
-    
-    @CatalogConfig(label="DB Setup SQL (URL)", priority=1)
-    public static final ConfigKey<String> DB_SETUP_SQL_URL = ConfigKeys.newConfigKey(
-        "app.db_sql", "URL to the SQL script to set up the database", 
-        DEFAULT_DB_SETUP_SQL_URL);
-    
-    public static final String DB_TABLE = "visitors";
-    public static final String DB_USERNAME = "brooklyn";
-    public static final String DB_PASSWORD = "br00k11n";
-    
-    public static final AttributeSensor<Integer> APPSERVERS_COUNT = Sensors.newIntegerSensor( 
-            "appservers.count", "Number of app servers deployed");
-    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW = 
-            WebAppServiceConstants.REQUESTS_PER_SECOND_IN_WINDOW;
-    public static final AttributeSensor<String> ROOT_URL = WebAppServiceConstants.ROOT_URL;
-
-    @Override
-    public void initApp() {
-        MySqlNode mysql = addChild(
-                EntitySpec.create(MySqlNode.class)
-                        .configure(MySqlNode.CREATION_SCRIPT_URL, Entities.getRequiredUrlConfig(this, DB_SETUP_SQL_URL)));
-
-        ControlledDynamicWebAppCluster web = addChild(
-                EntitySpec.create(ControlledDynamicWebAppCluster.class)
-                        .configure(WebAppService.HTTP_PORT, PortRanges.fromString("8080+"))
-                        // to specify a diferrent appserver:
-//                        .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TomcatServer.class))
-                        .configure(JavaWebAppService.ROOT_WAR, Entities.getRequiredUrlConfig(this, WAR_PATH))
-                        .configure(JavaEntityMethods.javaSysProp("brooklyn.example.db.url"), 
-                                formatString("jdbc:%s%s?user=%s\\&password=%s", 
-                                        attributeWhenReady(mysql, MySqlNode.DATASTORE_URL), DB_TABLE, DB_USERNAME, DB_PASSWORD))
-                        .configure(DynamicCluster.INITIAL_SIZE, 2)
-                        .configure(WebAppService.ENABLED_PROTOCOLS, ImmutableSet.of(getConfig(USE_HTTPS) ? "https" : "http")) );
-
-        web.addEnricher(HttpLatencyDetector.builder().
-                url(ROOT_URL).
-                rollup(10, TimeUnit.SECONDS).
-                build());
-        
-        web.getCluster().addPolicy(AutoScalerPolicy.builder().
-                metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE).
-                metricRange(10, 100).
-                sizeRange(2, 5).
-                build());
-
-        addEnricher(Enrichers.builder()
-                .propagating(WebAppServiceConstants.ROOT_URL,
-                        DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW,
-                        HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_IN_WINDOW)
-                .from(web)
-                .build());
-
-        addEnricher(Enrichers.builder()
-                .propagating(ImmutableMap.of(DynamicWebAppCluster.GROUP_SIZE, APPSERVERS_COUNT))
-                .from(web)
-                .build());
-    }
-    
-    public static void main(String[] argv) {
-        List<String> args = Lists.newArrayList(argv);
-        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
-        String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION);
-
-        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
-                 .application(EntitySpec.create(StartableApplication.class, WebClusterDatabaseExampleApp.class)
-                         .displayName("Brooklyn WebApp Cluster with Database example"))
-                 .webconsolePort(port)
-                 .location(location)
-                 .start();
-             
-        Entities.dumpInfo(launcher.getApplications());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy b/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
deleted file mode 100644
index c3f6cc7..0000000
--- a/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
+++ /dev/null
@@ -1,93 +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 brooklyn.demo;
-
-import static brooklyn.entity.java.JavaEntityMethods.javaSysProp
-import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady
-import static brooklyn.event.basic.DependentConfiguration.formatString
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-import brooklyn.entity.basic.AbstractApplication
-import brooklyn.entity.basic.Entities
-import brooklyn.entity.database.mysql.MySqlNode
-import brooklyn.entity.proxying.EntitySpec
-import brooklyn.entity.webapp.ControlledDynamicWebAppCluster
-import brooklyn.entity.webapp.DynamicWebAppCluster
-import brooklyn.launcher.BrooklynLauncher
-import brooklyn.policy.autoscaling.AutoScalerPolicy
-import brooklyn.util.CommandLineUtil
-
-import com.google.common.collect.Lists
-
-/**
- * Launches a 3-tier app with nginx, clustered jboss, and mysql.
- * <p>
- * This variant of {@link WebClusterDatabaseExample} demonstrates <i>Groovy</i> language conveniences.
- **/
-public class WebClusterDatabaseExampleGroovy extends AbstractApplication {
-    
-    public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseExampleGroovy.class);
-    
-    public static final String DEFAULT_LOCATION = "localhost";
-
-    public static final String WAR_PATH = "classpath://hello-world-sql-webapp.war";
-    
-    public static final String DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql";
-    
-    public static final String DB_TABLE = "visitors";
-    public static final String DB_USERNAME = "brooklyn";
-    public static final String DB_PASSWORD = "br00k11n";
-    
-    @Override
-    public void initApp() {
-        MySqlNode mysql = addChild(MySqlNode,
-                creationScriptUrl: DB_SETUP_SQL_URL);
-        
-        ControlledDynamicWebAppCluster web = addChild(ControlledDynamicWebAppCluster,
-                war: WAR_PATH,
-                httpPort: "8080+",
-                (javaSysProp("brooklyn.example.db.url")): 
-                    formatString("jdbc:%s%s?user=%s\\&password=%s", 
-                            attributeWhenReady(mysql, MySqlNode.DATASTORE_URL), 
-                            DB_TABLE, DB_USERNAME, DB_PASSWORD));
-    
-        web.getCluster().addPolicy(AutoScalerPolicy.builder().
-                metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_LAST_PER_NODE).
-                sizeRange(1, 5).
-                metricRange(10, 100).
-                build());
-    }
-
-    public static void main(String[] argv) {
-        List<String> args = Lists.newArrayList(argv);
-        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
-        String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION);
-
-        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
-                .application(EntitySpec.create(WebClusterDatabaseExampleGroovy.class).displayName("Brooklyn WebApp Cluster with Database example"))
-                .webconsolePort(port)
-                .location(location)
-                .start();
-         
-        Entities.dumpInfo(launcher.getApplications());
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.java b/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.java
deleted file mode 100644
index 6a5d064..0000000
--- a/examples/simple-web-cluster/src/main/java/brooklyn/demo/WebClusterExample.java
+++ /dev/null
@@ -1,96 +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 brooklyn.demo;
-
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.BrooklynProperties;
-import brooklyn.entity.basic.AbstractApplication;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.proxy.nginx.NginxController;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
-import brooklyn.entity.webapp.DynamicWebAppCluster;
-import brooklyn.entity.webapp.jboss.JBoss7Server;
-import brooklyn.launcher.BrooklynLauncher;
-import brooklyn.policy.autoscaling.AutoScalerPolicy;
-import brooklyn.util.CommandLineUtil;
-
-import com.google.common.collect.Lists;
-
-/**
- * Launches a clustered and load-balanced set of web servers.
- * Demonstrates syntax, so many of the options used here are the defaults.
- * (So the class could be much simpler, as in WebClusterExampleAlt.)
- * <p>
- * Requires: 
- * -Xmx512m -Xms128m -XX:MaxPermSize=256m
- * and brooklyn-all jar, and this jar or classes dir, on classpath. 
- **/
-public class WebClusterExample extends AbstractApplication {
-    public static final Logger LOG = LoggerFactory.getLogger(WebClusterExample.class);
-    
-    static BrooklynProperties config = BrooklynProperties.Factory.newDefault();
-
-    public static final String DEFAULT_LOCATION = "localhost";
-
-    public static final String WAR_PATH = "classpath://hello-world-webapp.war";
-
-    private NginxController nginxController;
-    private ControlledDynamicWebAppCluster web;
-    
-    @Override
-    public void initApp() {
-        nginxController = addChild(EntitySpec.create(NginxController.class)
-                //.configure("domain", "webclusterexample.brooklyn.local")
-                .configure("port", "8000+"));
-          
-        web = addChild(EntitySpec.create(ControlledDynamicWebAppCluster.class)
-                .displayName("WebApp cluster")
-                .configure(ControlledDynamicWebAppCluster.CONTROLLER, nginxController)
-                .configure(ControlledDynamicWebAppCluster.INITIAL_SIZE, 1)
-                .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class)
-                        .configure("httpPort", "8080+")
-                        .configure("war", WAR_PATH)));
-        
-        web.getCluster().addPolicy(AutoScalerPolicy.builder()
-                .metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE)
-                .sizeRange(1, 5)
-                .metricRange(10, 100)
-                .build());
-    }
-    
-    public static void main(String[] argv) {
-        List<String> args = Lists.newArrayList(argv);
-        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
-        String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION);
-
-        // TODO Want to parse, to handle multiple locations
-        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
-                .application(EntitySpec.create(WebClusterExample.class).displayName("Brooklyn WebApp Cluster example"))
-                .webconsolePort(port)
-                .location(location)
-                .start();
-         
-        Entities.dumpInfo(launcher.getApplications());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/NodeJsTodoApplication.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/NodeJsTodoApplication.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/NodeJsTodoApplication.java
new file mode 100644
index 0000000..bfae7ce
--- /dev/null
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/NodeJsTodoApplication.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.demo;
+
+import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
+import brooklyn.catalog.Catalog;
+import brooklyn.entity.basic.AbstractApplication;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.basic.StartableApplication;
+import brooklyn.entity.nosql.redis.RedisStore;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.trait.Startable;
+import brooklyn.entity.webapp.nodejs.NodeJsWebAppService;
+import brooklyn.event.basic.DependentConfiguration;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Node.JS Todo Application
+ */
+@Catalog(name="NodeJS Todo",
+        description="Node.js is a cross-platform runtime environment for server-side and networking applications. Node.js applications are written in JavaScript",
+        iconUrl="classpath://nodejs-logo.png")
+public class NodeJsTodoApplication extends AbstractApplication implements StartableApplication {
+
+    @Override
+    public void initApp() {
+        RedisStore redis = addChild(EntitySpec.create(RedisStore.class));
+
+        addChild(EntitySpec.create(NodeJsWebAppService.class)
+                .configure(NodeJsWebAppService.APP_GIT_REPOSITORY_URL, "https://github.com/grkvlt/nodejs-todo/")
+                .configure(NodeJsWebAppService.APP_FILE, "server.js")
+                .configure(NodeJsWebAppService.APP_NAME, "nodejs-todo")
+                .configure(NodeJsWebAppService.NODE_PACKAGE_LIST, ImmutableList.of("express", "ejs", "jasmine-node", "underscore", "method-override", "cookie-parser", "express-session", "body-parser", "cookie-session", "redis", "redis-url", "connect"))
+                .configure(SoftwareProcess.SHELL_ENVIRONMENT, ImmutableMap.<String, Object>of(
+                        "REDISTOGO_URL", DependentConfiguration.formatString("redis://%s:%d/",
+                                attributeWhenReady(redis, Attributes.HOSTNAME), attributeWhenReady(redis, RedisStore.REDIS_PORT))))
+                .configure(SoftwareProcess.LAUNCH_LATCH, attributeWhenReady(redis, Startable.SERVICE_UP)));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/SingleWebServerExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/SingleWebServerExample.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/SingleWebServerExample.java
new file mode 100644
index 0000000..4561e2c
--- /dev/null
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/SingleWebServerExample.java
@@ -0,0 +1,67 @@
+/*
+ * 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.demo;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.AbstractApplication;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.StartableApplication;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.webapp.JavaWebAppService;
+import brooklyn.entity.webapp.jboss.JBoss7Server;
+import brooklyn.launcher.BrooklynLauncher;
+import brooklyn.location.basic.PortRanges;
+import brooklyn.util.CommandLineUtil;
+
+import com.google.common.collect.Lists;
+
+/** This example starts one web app on 8080, waits for a keypress, then stops it. */
+public class SingleWebServerExample extends AbstractApplication {
+
+    public static final Logger LOG = LoggerFactory.getLogger(SingleWebServerExample.class);
+
+    private static final String WAR_PATH = "classpath://hello-world-webapp.war";
+
+    @Override
+    public void initApp() {
+        addChild(EntitySpec.create(JBoss7Server.class)
+                .configure(JavaWebAppService.ROOT_WAR, WAR_PATH)
+                .configure(Attributes.HTTP_PORT, PortRanges.fromString("8080+")));
+    }
+
+    // Shows how to use ApplicationBuilder without sub-classing, but for CLI usage one should sub-class
+    public static void main(String[] argv) throws Exception {
+        List<String> args = Lists.newArrayList(argv);
+        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
+        String location = CommandLineUtil.getCommandLineOption(args, "--location", "localhost");
+
+        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
+                .application(EntitySpec.create(StartableApplication.class, SingleWebServerExample.class).displayName("Brooklyn WebApp example"))
+                .webconsolePort(port)
+                .location(location)
+                .start();
+         
+        Entities.dumpInfo(launcher.getApplications());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
new file mode 100644
index 0000000..4f10eb1
--- /dev/null
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExample.java
@@ -0,0 +1,123 @@
+/*
+ * 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.demo;
+
+import static brooklyn.entity.java.JavaEntityMethods.javaSysProp;
+import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
+import static brooklyn.event.basic.DependentConfiguration.formatString;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.enricher.Enrichers;
+import brooklyn.enricher.HttpLatencyDetector;
+import brooklyn.entity.basic.AbstractApplication;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.StartableApplication;
+import brooklyn.entity.database.mysql.MySqlNode;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
+import brooklyn.entity.webapp.DynamicWebAppCluster;
+import brooklyn.entity.webapp.JavaWebAppService;
+import brooklyn.entity.webapp.WebAppService;
+import brooklyn.entity.webapp.WebAppServiceConstants;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.Sensors;
+import brooklyn.launcher.BrooklynLauncher;
+import brooklyn.location.basic.PortRanges;
+import brooklyn.policy.autoscaling.AutoScalerPolicy;
+import brooklyn.util.CommandLineUtil;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+/**
+ * Launches a 3-tier app with nginx, clustered jboss, and mysql.
+ **/
+public class WebClusterDatabaseExample extends AbstractApplication {
+    
+    public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseExample.class);
+    
+    public static final String WAR_PATH = "classpath://hello-world-sql-webapp.war";
+    
+    public static final String DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql";
+    
+    public static final String DB_TABLE = "visitors";
+    public static final String DB_USERNAME = "brooklyn";
+    public static final String DB_PASSWORD = "br00k11n";
+    
+    public static final AttributeSensor<Integer> APPSERVERS_COUNT = Sensors.newIntegerSensor( 
+            "appservers.count", "Number of app servers deployed");
+
+    @Override
+    public void initApp() {
+        MySqlNode mysql = addChild(EntitySpec.create(MySqlNode.class)
+                .configure("creationScriptUrl", DB_SETUP_SQL_URL));
+        
+        ControlledDynamicWebAppCluster web = addChild(EntitySpec.create(ControlledDynamicWebAppCluster.class)
+                .configure(WebAppService.HTTP_PORT, PortRanges.fromString("8080+"))
+                .configure(JavaWebAppService.ROOT_WAR, WAR_PATH)
+                .configure(javaSysProp("brooklyn.example.db.url"), 
+                        formatString("jdbc:%s%s?user=%s\\&password=%s", 
+                                attributeWhenReady(mysql, MySqlNode.DATASTORE_URL), 
+                                DB_TABLE, DB_USERNAME, DB_PASSWORD)) );
+
+        web.addEnricher(HttpLatencyDetector.builder().
+                url(ControlledDynamicWebAppCluster.ROOT_URL).
+                rollup(10, TimeUnit.SECONDS).
+                build());
+
+        // simple scaling policy
+        web.getCluster().addPolicy(AutoScalerPolicy.builder().
+                metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE).
+                metricRange(10, 100).
+                sizeRange(1, 5).
+                build());
+
+        // expose some KPI's
+        addEnricher(Enrichers.builder()
+                .propagating(WebAppServiceConstants.ROOT_URL,
+                        DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW,
+                        HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_IN_WINDOW)
+                .from(web)
+                .build());
+
+        addEnricher(Enrichers.builder()
+                .propagating(ImmutableMap.of(DynamicWebAppCluster.GROUP_SIZE, APPSERVERS_COUNT))
+                .from(web)
+                .build());
+    }
+
+    public static void main(String[] argv) {
+        List<String> args = Lists.newArrayList(argv);
+        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
+        String location = CommandLineUtil.getCommandLineOption(args, "--location", "localhost");
+
+        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
+                .application(EntitySpec.create(StartableApplication.class, WebClusterDatabaseExample.class).displayName("Brooklyn WebApp Cluster with Database example"))
+                .webconsolePort(port)
+                .location(location)
+                .start();
+         
+        Entities.dumpInfo(launcher.getApplications());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
new file mode 100644
index 0000000..3a5d54d
--- /dev/null
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleApp.java
@@ -0,0 +1,175 @@
+/*
+ * 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.demo;
+
+import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
+import static brooklyn.event.basic.DependentConfiguration.formatString;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.catalog.Catalog;
+import brooklyn.catalog.CatalogConfig;
+import brooklyn.config.ConfigKey;
+import brooklyn.enricher.Enrichers;
+import brooklyn.enricher.HttpLatencyDetector;
+import brooklyn.entity.basic.AbstractApplication;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.StartableApplication;
+import brooklyn.entity.database.mysql.MySqlNode;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.entity.java.JavaEntityMethods;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
+import brooklyn.entity.webapp.DynamicWebAppCluster;
+import brooklyn.entity.webapp.JavaWebAppService;
+import brooklyn.entity.webapp.WebAppService;
+import brooklyn.entity.webapp.WebAppServiceConstants;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.Sensors;
+import brooklyn.launcher.BrooklynLauncher;
+import brooklyn.location.basic.PortRanges;
+import brooklyn.policy.autoscaling.AutoScalerPolicy;
+import brooklyn.util.BrooklynMavenArtifacts;
+import brooklyn.util.CommandLineUtil;
+import brooklyn.util.ResourceUtils;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+
+/**
+ * Launches a 3-tier app with nginx, clustered jboss, and mysql.
+ * <p>
+ * Includes some advanced features such as KPI / derived sensors,
+ * and annotations for use in a catalog.
+ * <p>
+ * This variant also increases minimum size to 2.  
+ * Note the policy min size must have the same value,
+ * otherwise it fights with cluster set up trying to reduce the cluster size!
+ **/
+@Catalog(name="Elastic Java Web + DB",
+    description="Deploys a WAR to a load-balanced elastic Java AppServer cluster, " +
+            "with an auto-scaling policy, " +
+            "wired to a database initialized with the provided SQL; " +
+            "defaults to a 'Hello World' chatroom app.",
+    iconUrl="classpath://brooklyn/demo/glossy-3d-blue-web-icon.png")
+public class WebClusterDatabaseExampleApp extends AbstractApplication implements StartableApplication {
+    
+    public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseExampleApp.class);
+    
+    public static final String DEFAULT_LOCATION = "localhost";
+
+    public static final String DEFAULT_WAR_PATH = ResourceUtils.create(WebClusterDatabaseExampleApp.class)
+            // take this war, from the classpath, or via maven if not on the classpath
+            .firstAvailableUrl(
+                    "classpath://hello-world-sql-webapp.war",
+                    BrooklynMavenArtifacts.localUrl("example", "brooklyn-example-hello-world-sql-webapp", "war"))
+            .or("classpath://hello-world-sql-webapp.war");
+    
+    @CatalogConfig(label="WAR (URL)", priority=2)
+    public static final ConfigKey<String> WAR_PATH = ConfigKeys.newConfigKey(
+        "app.war", "URL to the application archive which should be deployed", 
+        DEFAULT_WAR_PATH);    
+
+    // TODO to expose in catalog we need to let the keystore url be specified (not hard)
+    // and also confirm that this works for nginx (might be a bit fiddly);
+    // booleans in the gui are working (With checkbox)
+    @CatalogConfig(label="HTTPS")
+    public static final ConfigKey<Boolean> USE_HTTPS = ConfigKeys.newConfigKey(
+            "app.https", "Whether the application should use HTTPS only or just HTTP only (default)", false);
+    
+    public static final String DEFAULT_DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql";
+    
+    @CatalogConfig(label="DB Setup SQL (URL)", priority=1)
+    public static final ConfigKey<String> DB_SETUP_SQL_URL = ConfigKeys.newConfigKey(
+        "app.db_sql", "URL to the SQL script to set up the database", 
+        DEFAULT_DB_SETUP_SQL_URL);
+    
+    public static final String DB_TABLE = "visitors";
+    public static final String DB_USERNAME = "brooklyn";
+    public static final String DB_PASSWORD = "br00k11n";
+    
+    public static final AttributeSensor<Integer> APPSERVERS_COUNT = Sensors.newIntegerSensor( 
+            "appservers.count", "Number of app servers deployed");
+    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW = 
+            WebAppServiceConstants.REQUESTS_PER_SECOND_IN_WINDOW;
+    public static final AttributeSensor<String> ROOT_URL = WebAppServiceConstants.ROOT_URL;
+
+    @Override
+    public void initApp() {
+        MySqlNode mysql = addChild(
+                EntitySpec.create(MySqlNode.class)
+                        .configure(MySqlNode.CREATION_SCRIPT_URL, Entities.getRequiredUrlConfig(this, DB_SETUP_SQL_URL)));
+
+        ControlledDynamicWebAppCluster web = addChild(
+                EntitySpec.create(ControlledDynamicWebAppCluster.class)
+                        .configure(WebAppService.HTTP_PORT, PortRanges.fromString("8080+"))
+                        // to specify a diferrent appserver:
+//                        .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(TomcatServer.class))
+                        .configure(JavaWebAppService.ROOT_WAR, Entities.getRequiredUrlConfig(this, WAR_PATH))
+                        .configure(JavaEntityMethods.javaSysProp("brooklyn.example.db.url"), 
+                                formatString("jdbc:%s%s?user=%s\\&password=%s", 
+                                        attributeWhenReady(mysql, MySqlNode.DATASTORE_URL), DB_TABLE, DB_USERNAME, DB_PASSWORD))
+                        .configure(DynamicCluster.INITIAL_SIZE, 2)
+                        .configure(WebAppService.ENABLED_PROTOCOLS, ImmutableSet.of(getConfig(USE_HTTPS) ? "https" : "http")) );
+
+        web.addEnricher(HttpLatencyDetector.builder().
+                url(ROOT_URL).
+                rollup(10, TimeUnit.SECONDS).
+                build());
+        
+        web.getCluster().addPolicy(AutoScalerPolicy.builder().
+                metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE).
+                metricRange(10, 100).
+                sizeRange(2, 5).
+                build());
+
+        addEnricher(Enrichers.builder()
+                .propagating(WebAppServiceConstants.ROOT_URL,
+                        DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW,
+                        HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_IN_WINDOW)
+                .from(web)
+                .build());
+
+        addEnricher(Enrichers.builder()
+                .propagating(ImmutableMap.of(DynamicWebAppCluster.GROUP_SIZE, APPSERVERS_COUNT))
+                .from(web)
+                .build());
+    }
+    
+    public static void main(String[] argv) {
+        List<String> args = Lists.newArrayList(argv);
+        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
+        String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION);
+
+        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
+                 .application(EntitySpec.create(StartableApplication.class, WebClusterDatabaseExampleApp.class)
+                         .displayName("Brooklyn WebApp Cluster with Database example"))
+                 .webconsolePort(port)
+                 .location(location)
+                 .start();
+             
+        Entities.dumpInfo(launcher.getApplications());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
new file mode 100644
index 0000000..c3f6cc7
--- /dev/null
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterDatabaseExampleGroovy.groovy
@@ -0,0 +1,93 @@
+/*
+ * 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 brooklyn.demo;
+
+import static brooklyn.entity.java.JavaEntityMethods.javaSysProp
+import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady
+import static brooklyn.event.basic.DependentConfiguration.formatString
+
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+
+import brooklyn.entity.basic.AbstractApplication
+import brooklyn.entity.basic.Entities
+import brooklyn.entity.database.mysql.MySqlNode
+import brooklyn.entity.proxying.EntitySpec
+import brooklyn.entity.webapp.ControlledDynamicWebAppCluster
+import brooklyn.entity.webapp.DynamicWebAppCluster
+import brooklyn.launcher.BrooklynLauncher
+import brooklyn.policy.autoscaling.AutoScalerPolicy
+import brooklyn.util.CommandLineUtil
+
+import com.google.common.collect.Lists
+
+/**
+ * Launches a 3-tier app with nginx, clustered jboss, and mysql.
+ * <p>
+ * This variant of {@link WebClusterDatabaseExample} demonstrates <i>Groovy</i> language conveniences.
+ **/
+public class WebClusterDatabaseExampleGroovy extends AbstractApplication {
+    
+    public static final Logger LOG = LoggerFactory.getLogger(WebClusterDatabaseExampleGroovy.class);
+    
+    public static final String DEFAULT_LOCATION = "localhost";
+
+    public static final String WAR_PATH = "classpath://hello-world-sql-webapp.war";
+    
+    public static final String DB_SETUP_SQL_URL = "classpath://visitors-creation-script.sql";
+    
+    public static final String DB_TABLE = "visitors";
+    public static final String DB_USERNAME = "brooklyn";
+    public static final String DB_PASSWORD = "br00k11n";
+    
+    @Override
+    public void initApp() {
+        MySqlNode mysql = addChild(MySqlNode,
+                creationScriptUrl: DB_SETUP_SQL_URL);
+        
+        ControlledDynamicWebAppCluster web = addChild(ControlledDynamicWebAppCluster,
+                war: WAR_PATH,
+                httpPort: "8080+",
+                (javaSysProp("brooklyn.example.db.url")): 
+                    formatString("jdbc:%s%s?user=%s\\&password=%s", 
+                            attributeWhenReady(mysql, MySqlNode.DATASTORE_URL), 
+                            DB_TABLE, DB_USERNAME, DB_PASSWORD));
+    
+        web.getCluster().addPolicy(AutoScalerPolicy.builder().
+                metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_LAST_PER_NODE).
+                sizeRange(1, 5).
+                metricRange(10, 100).
+                build());
+    }
+
+    public static void main(String[] argv) {
+        List<String> args = Lists.newArrayList(argv);
+        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
+        String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION);
+
+        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
+                .application(EntitySpec.create(WebClusterDatabaseExampleGroovy.class).displayName("Brooklyn WebApp Cluster with Database example"))
+                .webconsolePort(port)
+                .location(location)
+                .start();
+         
+        Entities.dumpInfo(launcher.getApplications());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterExample.java b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterExample.java
new file mode 100644
index 0000000..51642aa
--- /dev/null
+++ b/examples/simple-web-cluster/src/main/java/org/apache/brooklyn/demo/WebClusterExample.java
@@ -0,0 +1,96 @@
+/*
+ * 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.demo;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.basic.AbstractApplication;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxy.nginx.NginxController;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
+import brooklyn.entity.webapp.DynamicWebAppCluster;
+import brooklyn.entity.webapp.jboss.JBoss7Server;
+import brooklyn.launcher.BrooklynLauncher;
+import brooklyn.policy.autoscaling.AutoScalerPolicy;
+import brooklyn.util.CommandLineUtil;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Launches a clustered and load-balanced set of web servers.
+ * Demonstrates syntax, so many of the options used here are the defaults.
+ * (So the class could be much simpler, as in WebClusterExampleAlt.)
+ * <p>
+ * Requires: 
+ * -Xmx512m -Xms128m -XX:MaxPermSize=256m
+ * and brooklyn-all jar, and this jar or classes dir, on classpath. 
+ **/
+public class WebClusterExample extends AbstractApplication {
+    public static final Logger LOG = LoggerFactory.getLogger(WebClusterExample.class);
+    
+    static BrooklynProperties config = BrooklynProperties.Factory.newDefault();
+
+    public static final String DEFAULT_LOCATION = "localhost";
+
+    public static final String WAR_PATH = "classpath://hello-world-webapp.war";
+
+    private NginxController nginxController;
+    private ControlledDynamicWebAppCluster web;
+    
+    @Override
+    public void initApp() {
+        nginxController = addChild(EntitySpec.create(NginxController.class)
+                //.configure("domain", "webclusterexample.brooklyn.local")
+                .configure("port", "8000+"));
+          
+        web = addChild(EntitySpec.create(ControlledDynamicWebAppCluster.class)
+                .displayName("WebApp cluster")
+                .configure(ControlledDynamicWebAppCluster.CONTROLLER, nginxController)
+                .configure(ControlledDynamicWebAppCluster.INITIAL_SIZE, 1)
+                .configure(ControlledDynamicWebAppCluster.MEMBER_SPEC, EntitySpec.create(JBoss7Server.class)
+                        .configure("httpPort", "8080+")
+                        .configure("war", WAR_PATH)));
+        
+        web.getCluster().addPolicy(AutoScalerPolicy.builder()
+                .metric(DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE)
+                .sizeRange(1, 5)
+                .metricRange(10, 100)
+                .build());
+    }
+    
+    public static void main(String[] argv) {
+        List<String> args = Lists.newArrayList(argv);
+        String port =  CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
+        String location = CommandLineUtil.getCommandLineOption(args, "--location", DEFAULT_LOCATION);
+
+        // TODO Want to parse, to handle multiple locations
+        BrooklynLauncher launcher = BrooklynLauncher.newInstance()
+                .application(EntitySpec.create(WebClusterExample.class).displayName("Brooklyn WebApp Cluster example"))
+                .webconsolePort(port)
+                .location(location)
+                .start();
+         
+        Entities.dumpInfo(launcher.getApplications());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/resources/brooklyn/demo/glossy-3d-blue-web-icon.png
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/resources/brooklyn/demo/glossy-3d-blue-web-icon.png b/examples/simple-web-cluster/src/main/resources/brooklyn/demo/glossy-3d-blue-web-icon.png
deleted file mode 100644
index 542a1de..0000000
Binary files a/examples/simple-web-cluster/src/main/resources/brooklyn/demo/glossy-3d-blue-web-icon.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/resources/brooklyn/demo/nodejs-riak-todo.yaml
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/resources/brooklyn/demo/nodejs-riak-todo.yaml b/examples/simple-web-cluster/src/main/resources/brooklyn/demo/nodejs-riak-todo.yaml
deleted file mode 100644
index d963671..0000000
--- a/examples/simple-web-cluster/src/main/resources/brooklyn/demo/nodejs-riak-todo.yaml
+++ /dev/null
@@ -1,46 +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.
-
-name: "Node.JS Todo Application"
-origin: "https://github.com/amirrajan/nodejs-todo/"
-location:
-  jclouds:aws-ec2:us-west-1:
-    imageId: us-west-1/ami-c33cdd87
-services:
-- type: brooklyn.entity.nosql.riak.RiakCluster
-  initialSize: 2
-  id: mycluster
-  brooklyn.config:
-    provisioning.properties:
-      osFamily: centos
-      minCores: 4
-      minRam: 2048
-- type: brooklyn.entity.webapp.nodejs.NodeJsWebAppService
-  id: nodejs-riak1
-  name: "Node.JS"
-  brooklyn.config:
-    gitRepoUrl:
-      "https://github.com/bostko/nodejs-todo.git"
-    appFileName: server.js
-    appName: nodejs-todo
-    nodePackages:
-    - basho-riak-client
-    env:
-      NODE_ENV: production
-      RIAK_NODES: >
-        $brooklyn:component("mycluster").attributeWhenReady("riak.cluster.nodeListPbPort")
-    launch.latch: $brooklyn:component("mycluster").attributeWhenReady("service.isUp")
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/resources/brooklyn/demo/nodejs-todo.yaml
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/resources/brooklyn/demo/nodejs-todo.yaml b/examples/simple-web-cluster/src/main/resources/brooklyn/demo/nodejs-todo.yaml
deleted file mode 100644
index ea17556..0000000
--- a/examples/simple-web-cluster/src/main/resources/brooklyn/demo/nodejs-todo.yaml
+++ /dev/null
@@ -1,53 +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.
-
-id: nodejs-todo-application
-name: "Node.JS Todo Application"
-origin: "https://github.com/amirrajan/nodejs-todo/"
-locations:
-- jclouds:softlayer:ams01
-services:
-- type: brooklyn.entity.nosql.redis.RedisStore
-  id: redis
-  name: "Redis"
-- type: brooklyn.entity.webapp.nodejs.NodeJsWebAppService
-  id: nodejs
-  name: "Node.JS"
-  brooklyn.config:
-    gitRepoUrl:
-      "https://github.com/grkvlt/nodejs-todo/"
-    appFileName: server.js
-    appName: nodejs-todo
-    nodePackages:
-    - express
-    - ejs
-    - jasmine-node
-    - underscore
-    - method-override
-    - cookie-parser
-    - express-session
-    - body-parser
-    - cookie-session
-    - redis
-    - redis-url
-    - connect
-    env:
-      REDISTOGO_URL: >
-        $brooklyn:formatString("redis://%s:%d/",
-          component("redis").attributeWhenReady("host.subnet.hostname"),
-          component("redis").attributeWhenReady("redis.port"))
-    launch.latch: $brooklyn:component("redis").attributeWhenReady("service.isUp")
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/resources/logback-custom.xml
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/resources/logback-custom.xml b/examples/simple-web-cluster/src/main/resources/logback-custom.xml
index 0d403dd..02a8a82 100644
--- a/examples/simple-web-cluster/src/main/resources/logback-custom.xml
+++ b/examples/simple-web-cluster/src/main/resources/logback-custom.xml
@@ -27,7 +27,7 @@
     -->        
   
     <!-- include this category -->
-    <logger name="brooklyn.demo" level="DEBUG"/>
+    <logger name="org.apache.brooklyn.demo" level="DEBUG"/>
     
     <!-- log to simple-web-cluster.log -->
     <property name="logging.basename" scope="context" value="brooklyn-simple-web-cluster" />

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/glossy-3d-blue-web-icon.png
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/glossy-3d-blue-web-icon.png b/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/glossy-3d-blue-web-icon.png
new file mode 100644
index 0000000..542a1de
Binary files /dev/null and b/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/glossy-3d-blue-web-icon.png differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/nodejs-riak-todo.yaml
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/nodejs-riak-todo.yaml b/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/nodejs-riak-todo.yaml
new file mode 100644
index 0000000..d963671
--- /dev/null
+++ b/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/nodejs-riak-todo.yaml
@@ -0,0 +1,46 @@
+# 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.
+
+name: "Node.JS Todo Application"
+origin: "https://github.com/amirrajan/nodejs-todo/"
+location:
+  jclouds:aws-ec2:us-west-1:
+    imageId: us-west-1/ami-c33cdd87
+services:
+- type: brooklyn.entity.nosql.riak.RiakCluster
+  initialSize: 2
+  id: mycluster
+  brooklyn.config:
+    provisioning.properties:
+      osFamily: centos
+      minCores: 4
+      minRam: 2048
+- type: brooklyn.entity.webapp.nodejs.NodeJsWebAppService
+  id: nodejs-riak1
+  name: "Node.JS"
+  brooklyn.config:
+    gitRepoUrl:
+      "https://github.com/bostko/nodejs-todo.git"
+    appFileName: server.js
+    appName: nodejs-todo
+    nodePackages:
+    - basho-riak-client
+    env:
+      NODE_ENV: production
+      RIAK_NODES: >
+        $brooklyn:component("mycluster").attributeWhenReady("riak.cluster.nodeListPbPort")
+    launch.latch: $brooklyn:component("mycluster").attributeWhenReady("service.isUp")
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/nodejs-todo.yaml
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/nodejs-todo.yaml b/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/nodejs-todo.yaml
new file mode 100644
index 0000000..ea17556
--- /dev/null
+++ b/examples/simple-web-cluster/src/main/resources/org/apache/brooklyn/demo/nodejs-todo.yaml
@@ -0,0 +1,53 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+id: nodejs-todo-application
+name: "Node.JS Todo Application"
+origin: "https://github.com/amirrajan/nodejs-todo/"
+locations:
+- jclouds:softlayer:ams01
+services:
+- type: brooklyn.entity.nosql.redis.RedisStore
+  id: redis
+  name: "Redis"
+- type: brooklyn.entity.webapp.nodejs.NodeJsWebAppService
+  id: nodejs
+  name: "Node.JS"
+  brooklyn.config:
+    gitRepoUrl:
+      "https://github.com/grkvlt/nodejs-todo/"
+    appFileName: server.js
+    appName: nodejs-todo
+    nodePackages:
+    - express
+    - ejs
+    - jasmine-node
+    - underscore
+    - method-override
+    - cookie-parser
+    - express-session
+    - body-parser
+    - cookie-session
+    - redis
+    - redis-url
+    - connect
+    env:
+      REDISTOGO_URL: >
+        $brooklyn:formatString("redis://%s:%d/",
+          component("redis").attributeWhenReady("host.subnet.hostname"),
+          component("redis").attributeWhenReady("redis.port"))
+    launch.latch: $brooklyn:component("redis").attributeWhenReady("service.isUp")
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/9b8bde02/examples/simple-web-cluster/src/test/java/brooklyn/demo/RebindWebClusterDatabaseExampleAppIntegrationTest.java
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/src/test/java/brooklyn/demo/RebindWebClusterDatabaseExampleAppIntegrationTest.java b/examples/simple-web-cluster/src/test/java/brooklyn/demo/RebindWebClusterDatabaseExampleAppIntegrationTest.java
deleted file mode 100644
index f2c735c..0000000
--- a/examples/simple-web-cluster/src/test/java/brooklyn/demo/RebindWebClusterDatabaseExampleAppIntegrationTest.java
+++ /dev/null
@@ -1,205 +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 brooklyn.demo;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.enricher.HttpLatencyDetector;
-import brooklyn.enricher.basic.Propagator;
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.database.mysql.MySqlNode;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.entity.java.JavaEntityMethods;
-import brooklyn.entity.proxy.nginx.NginxController;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.rebind.RebindOptions;
-import brooklyn.entity.rebind.RebindTestFixture;
-import brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
-import brooklyn.entity.webapp.DynamicWebAppCluster;
-import brooklyn.entity.webapp.tomcat.Tomcat8Server;
-import brooklyn.location.Location;
-import brooklyn.policy.Enricher;
-import brooklyn.policy.autoscaling.AutoScalerPolicy;
-import brooklyn.test.Asserts;
-import brooklyn.test.EntityTestUtils;
-import brooklyn.test.HttpTestUtils;
-import brooklyn.test.WebAppMonitor;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-
-
-public class RebindWebClusterDatabaseExampleAppIntegrationTest extends RebindTestFixture<StartableApplication> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(RebindWebClusterDatabaseExampleAppIntegrationTest.class);
-
-    private Location origLoc;
-    private List<WebAppMonitor> webAppMonitors = new CopyOnWriteArrayList<WebAppMonitor>();
-    private ExecutorService executor;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        origLoc = origManagementContext.getLocationRegistry().resolve("localhost");
-        executor = Executors.newCachedThreadPool();
-        webAppMonitors.clear();
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        for (WebAppMonitor monitor : webAppMonitors) {
-            monitor.terminate();
-        }
-        if (executor != null) executor.shutdownNow();
-        super.tearDown();
-    }
-    
-    @Override
-    protected StartableApplication createApp() {
-        StartableApplication result = origManagementContext.getEntityManager().createEntity(EntitySpec.create(StartableApplication.class)
-                .impl(WebClusterDatabaseExampleApp.class)
-                .configure(DynamicCluster.INITIAL_SIZE, 2));
-        Entities.startManagement(result, origManagementContext);
-        return result;
-    }
-    
-    private WebAppMonitor newWebAppMonitor(String url, int expectedResponseCode) {
-        WebAppMonitor monitor = new WebAppMonitor(url)
-//              .delayMillis(0) FIXME Re-enable to fast polling
-                .expectedResponseCode(expectedResponseCode)
-                .logFailures(LOG);
-        webAppMonitors.add(monitor);
-        executor.execute(monitor);
-        return monitor;
-    }
-    
-    @Test(groups="Integration")
-    public void testRestoresSimpleApp() throws Exception {
-        origApp.start(ImmutableList.of(origLoc));
-        
-        assertAppFunctional(origApp);
-        
-        String clusterUrl = checkNotNull(origApp.getAttribute(WebClusterDatabaseExampleApp.ROOT_URL), "cluster url");
-        WebAppMonitor monitor = newWebAppMonitor(clusterUrl, 200);
-        
-        newApp = rebind(RebindOptions.create().terminateOrigManagementContext(true));
-        assertAppFunctional(newApp);
-
-        // expect no failures during rebind
-        monitor.assertNoFailures("hitting nginx url");
-        monitor.terminate();
-    }
-    
-    private void assertAppFunctional(StartableApplication app) throws Exception {
-        // expect standard config to (still) be set
-        assertNotNull(app.getConfig(WebClusterDatabaseExampleApp.WAR_PATH));
-        assertEquals(app.getConfig(WebClusterDatabaseExampleApp.USE_HTTPS), Boolean.FALSE);
-        assertNotNull(app.getConfig(WebClusterDatabaseExampleApp.DB_SETUP_SQL_URL));
-
-        // expect entities to be there
-        MySqlNode mysql = (MySqlNode) Iterables.find(app.getChildren(), Predicates.instanceOf(MySqlNode.class));
-        ControlledDynamicWebAppCluster web = (ControlledDynamicWebAppCluster) Iterables.find(app.getChildren(), Predicates.instanceOf(ControlledDynamicWebAppCluster.class));
-        final NginxController nginx = (NginxController) Iterables.find(web.getChildren(), Predicates.instanceOf(NginxController.class));
-        DynamicWebAppCluster webCluster = (DynamicWebAppCluster) Iterables.find(web.getChildren(), Predicates.instanceOf(DynamicWebAppCluster.class));
-        Collection<Entity> appservers = web.getMembers();
-        assertEquals(appservers.size(), 2);
-        String clusterUrl = checkNotNull(app.getAttribute(WebClusterDatabaseExampleApp.ROOT_URL), "cluster url");
-        String dbUrl = checkNotNull(mysql.getAttribute(MySqlNode.DATASTORE_URL), "database url");
-        final String expectedJdbcUrl = String.format("jdbc:%s%s?user=%s\\&password=%s", dbUrl, WebClusterDatabaseExampleApp.DB_TABLE, 
-                WebClusterDatabaseExampleApp.DB_USERNAME, WebClusterDatabaseExampleApp.DB_PASSWORD);
-
-        // expect web-app to be reachable, and wired up to database
-        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(clusterUrl, 200);
-        for (Entity appserver : appservers) {
-            String appserverUrl = checkNotNull(appserver.getAttribute(Tomcat8Server.ROOT_URL), "appserver url of "+appserver);
-
-            HttpTestUtils.assertHttpStatusCodeEventuallyEquals(appserverUrl, 200);
-            assertEquals(expectedJdbcUrl, appserver.getConfig(JavaEntityMethods.javaSysProp("brooklyn.example.db.url")), "of "+appserver);
-        }
-
-        WebAppMonitor monitor = newWebAppMonitor(clusterUrl, 200);
-
-        // expect auto-scaler policy to be there, and to be functional (e.g. can trigger resize)
-        AutoScalerPolicy autoScalerPolicy = (AutoScalerPolicy) Iterables.find(webCluster.getPolicies(), Predicates.instanceOf(AutoScalerPolicy.class));
-        
-        autoScalerPolicy.config().set(AutoScalerPolicy.MIN_POOL_SIZE, 3);
-        EntityTestUtils.assertGroupSizeEqualsEventually(web, 3);
-        final Collection<Entity> webMembersAfterGrow = web.getMembers();
-        
-        for (final Entity appserver : webMembersAfterGrow) {
-            Asserts.succeedsEventually(MutableMap.of("timeout", Duration.TWO_MINUTES), new Runnable() {
-                @Override public void run() {
-                    String appserverUrl = checkNotNull(appserver.getAttribute(Tomcat8Server.ROOT_URL), "appserver url of "+appserver);
-                    HttpTestUtils.assertHttpStatusCodeEquals(appserverUrl, 200);
-                    assertEquals(expectedJdbcUrl, appserver.getConfig(JavaEntityMethods.javaSysProp("brooklyn.example.db.url")), "of "+appserver);
-                    Asserts.assertEqualsIgnoringOrder(nginx.getAttribute(NginxController.SERVER_POOL_TARGETS).keySet(), webMembersAfterGrow);
-                }});
-        }
-
-        // expect enrichers to be there
-        Iterables.find(web.getEnrichers(), Predicates.instanceOf(HttpLatencyDetector.class));
-        Iterable<Enricher> propagatorEnrichers = Iterables.filter(web.getEnrichers(), Predicates.instanceOf(Propagator.class));
-        assertEquals(Iterables.size(propagatorEnrichers), 3, "propagatorEnrichers="+propagatorEnrichers);
-
-        // Check we see evidence of the enrichers having an effect.
-        // Relying on WebAppMonitor to stimulate activity.
-        EntityTestUtils.assertAttributeEqualsEventually(app, WebClusterDatabaseExampleApp.APPSERVERS_COUNT, 3);
-        EntityTestUtils.assertAttributeChangesEventually(web, DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW);
-        EntityTestUtils.assertAttributeChangesEventually(app, DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW);
-        EntityTestUtils.assertAttributeChangesEventually(web, HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_MOST_RECENT);
-        EntityTestUtils.assertAttributeChangesEventually(web, HttpLatencyDetector.REQUEST_LATENCY_IN_SECONDS_IN_WINDOW);
-
-        // Restore the web-cluster to its original size of 2
-        autoScalerPolicy.config().set(AutoScalerPolicy.MIN_POOL_SIZE, 2);
-        EntityTestUtils.assertGroupSizeEqualsEventually(web, 2);
-        
-        final Entity removedAppserver = Iterables.getOnlyElement(Sets.difference(ImmutableSet.copyOf(webMembersAfterGrow), ImmutableSet.copyOf(web.getMembers())));
-        Asserts.succeedsEventually(new Runnable() {
-            @Override public void run() {
-                assertFalse(Entities.isManaged(removedAppserver));
-            }});
-        
-        monitor.assertNoFailures("hitting nginx url");
-        monitor.terminate();
-    }
-}