http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
 
b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
deleted file mode 100644
index b485449..0000000
--- 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
+++ /dev/null
@@ -1,370 +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.entity.proxy.nginx;
-
-import java.net.URI;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.brooklyn.management.SubscriptionHandle;
-import org.apache.brooklyn.policy.PolicySpec;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.enricher.Enrichers;
-import brooklyn.entity.Entity;
-import brooklyn.entity.Group;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Lifecycle;
-import brooklyn.entity.basic.ServiceStateLogic.ServiceNotUpLogic;
-import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
-import brooklyn.entity.proxy.AbstractControllerImpl;
-import brooklyn.entity.proxy.ProxySslConfig;
-import brooklyn.entity.proxy.nginx.NginxController.NginxControllerInternal;
-import brooklyn.event.SensorEvent;
-import brooklyn.event.SensorEventListener;
-import brooklyn.event.feed.ConfigToAttributes;
-import brooklyn.event.feed.http.HttpFeed;
-import brooklyn.event.feed.http.HttpPollConfig;
-import brooklyn.event.feed.http.HttpValueFunctions;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.file.ArchiveUtils;
-import brooklyn.util.guava.Functionals;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicates;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-
-/**
- * Implementation of the {@link NginxController} entity.
- */
-public class NginxControllerImpl extends AbstractControllerImpl implements 
NginxController, NginxControllerInternal {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(NginxControllerImpl.class);
-
-    private volatile HttpFeed httpFeed;
-    private final Set<String> installedKeysCache = Sets.newLinkedHashSet();
-    protected UrlMappingsMemberTrackerPolicy urlMappingsMemberTrackerPolicy;
-    protected SubscriptionHandle targetAddressesHandler;
-
-    @Override
-    public void reload() {
-        NginxSshDriver driver = (NginxSshDriver)getDriver();
-        if (driver==null) {
-            Lifecycle state = 
getAttribute(NginxController.SERVICE_STATE_ACTUAL);
-            throw new IllegalStateException("Cannot reload (no driver 
instance; stopped? (state="+state+")");
-        }
-
-        driver.reload();
-    }
-
-    @Override
-    public boolean isSticky() {
-        return getConfig(STICKY);
-    }
-
-    private class UrlInferencer implements Supplier<URI> {
-        private Map<String, String> parameters;
-        private UrlInferencer(Map<String,String> parameters) {
-            this.parameters = parameters;
-        }
-        @Override public URI get() { 
-            String baseUrl = inferUrl(true);
-            if (parameters==null || parameters.isEmpty())
-                return URI.create(baseUrl);
-            return 
URI.create(baseUrl+"?"+HttpTool.encodeUrlParams(parameters));
-        }
-    }
-    
-    @Override
-    public void connectSensors() {
-        super.connectSensors();
-
-        ConfigToAttributes.apply(this);
-
-        // "up" is defined as returning a valid HTTP response from nginx 
(including a 404 etc)
-        httpFeed = addFeed(HttpFeed.builder()
-                .uniqueTag("nginx-poll")
-                .entity(this)
-                .period(getConfig(HTTP_POLL_PERIOD))
-                .baseUri(new UrlInferencer(null))
-                .poll(new HttpPollConfig<Boolean>(NGINX_URL_ANSWERS_NICELY)
-                        // Any response from Nginx is good.
-                        .checkSuccess(Predicates.alwaysTrue())
-                        // Accept any nginx response (don't assert specific 
version), so that sub-classing
-                        // for a custom nginx build is not strict about custom 
version numbers in headers
-                        .onResult(HttpValueFunctions.containsHeader("Server"))
-                        .setOnException(false)
-                        .suppressDuplicates(true))
-                .build());
-        
-        // TODO PERSISTENCE WORKAROUND kept anonymous function in case 
referenced in persisted state
-        new Function<HttpToolResponse, Boolean>() {
-            @Override
-            public Boolean apply(HttpToolResponse input) {
-                // Accept any nginx response (don't assert specific version), 
so that sub-classing
-                // for a custom nginx build is not strict about custom version 
numbers in headers
-                List<String> actual = input.getHeaderLists().get("Server");
-                return actual != null && actual.size() == 1;
-            }
-        };
-        
-        if (!Lifecycle.RUNNING.equals(getAttribute(SERVICE_STATE_ACTUAL))) {
-            // TODO when updating the map, if it would change from empty to 
empty on a successful run
-            // gate with the above check to prevent flashing on ON_FIRE during 
rebind (this is invoked on rebind as well as during start)
-            ServiceNotUpLogic.updateNotUpIndicator(this, 
NGINX_URL_ANSWERS_NICELY, "No response from nginx yet");
-        }
-        
addEnricher(Enrichers.builder().updatingMap(Attributes.SERVICE_NOT_UP_INDICATORS)
-            .uniqueTag("not-up-unless-url-answers")
-            .from(NGINX_URL_ANSWERS_NICELY)
-            .computing(Functionals.ifNotEquals(true).value("URL where nginx 
listens is not answering correctly (with expected header)") )
-            .build());
-        connectServiceUpIsRunning();
-
-        // Can guarantee that parent/managementContext has been set
-        Group urlMappings = getConfig(URL_MAPPINGS);
-        if (urlMappings!=null && urlMappingsMemberTrackerPolicy==null) {
-            // Listen to the targets of each url-mapping changing
-            targetAddressesHandler = subscribeToMembers(urlMappings, 
UrlMapping.TARGET_ADDRESSES, new SensorEventListener<Collection<String>>() {
-                    @Override public void 
onEvent(SensorEvent<Collection<String>> event) {
-                        updateNeeded();
-                    }
-                });
-
-            // Listen to url-mappings being added and removed
-            urlMappingsMemberTrackerPolicy = 
addPolicy(PolicySpec.create(UrlMappingsMemberTrackerPolicy.class)
-                    .configure("group", urlMappings));
-        }
-    }
-
-    protected void removeUrlMappingsMemberTrackerPolicy() {
-        if (urlMappingsMemberTrackerPolicy != null) {
-            removePolicy(urlMappingsMemberTrackerPolicy);
-            urlMappingsMemberTrackerPolicy = null;
-        }
-        Group urlMappings = getConfig(URL_MAPPINGS);
-        if (urlMappings!=null && targetAddressesHandler!=null) {
-            unsubscribe(urlMappings, targetAddressesHandler);
-            targetAddressesHandler = null;
-        }
-    }
-    
-    public static class UrlMappingsMemberTrackerPolicy extends 
AbstractMembershipTrackingPolicy {
-        @Override
-        protected void onEntityEvent(EventType type, Entity entity) {
-            // relies on policy-rebind injecting the implementation rather 
than the dynamic-proxy
-            ((NginxControllerImpl)super.entity).updateNeeded();
-        }
-    }
-
-    @Override
-    protected void preStop() {
-        super.preStop();
-        removeUrlMappingsMemberTrackerPolicy();
-    }
-    
-    @Override
-    protected void postStop() {
-        // TODO don't want stop to race with the last poll.
-        super.postStop();
-        setAttribute(SERVICE_UP, false);
-    }
-
-    @Override
-    protected void disconnectSensors() {
-        if (httpFeed != null) httpFeed.stop();
-        disconnectServiceUpIsRunning();
-        super.disconnectSensors();
-    }
-
-    @Override
-    public Class<?> getDriverInterface() {
-        return NginxDriver.class;
-    }
-
-    @Override
-    public NginxDriver getDriver() {
-        return (NginxDriver) super.getDriver();
-    }
-
-    public void doExtraConfigurationDuringStart() {
-        computePortsAndUrls();
-        reconfigureService();
-        // reconnect sensors if ports have changed
-        connectSensors();
-    }
-
-    @Override
-    @Effector(description="Gets the current server configuration (by brooklyn 
recalculating what the config should be); does not affect the server")
-    public String getCurrentConfiguration() {
-        return getConfigFile();
-    }
-
-    @Override
-    @Effector(description="Deploys an archive of static content to the server")
-    public void deploy(String archiveUrl) {
-        NginxSshDriver driver = (NginxSshDriver) getDriver();
-        if (driver==null) {
-            if (LOG.isDebugEnabled())
-                LOG.debug("No driver for {}, so not deploying archive (is 
entity stopping? state={})",
-                        this, 
getAttribute(NginxController.SERVICE_STATE_ACTUAL));
-            return;
-        }
-
-        // Copy to the destination machine and extract contents
-        ArchiveUtils.deploy(archiveUrl, driver.getMachine(), 
driver.getRunDir());
-    }
-
-    @Override
-    public void reconfigureService() {
-        String cfg = getConfigFile();
-        if (cfg == null) return;
-
-        if (LOG.isDebugEnabled()) LOG.debug("Reconfiguring {}, targetting {} 
and {}", new Object[] {this, getServerPoolAddresses(), getUrlMappings()});
-        if (LOG.isTraceEnabled()) LOG.trace("Reconfiguring {}, config 
file:\n{}", this, cfg);
-
-        NginxSshDriver driver = (NginxSshDriver) getDriver();
-        if (!driver.isCustomizationCompleted()) {
-            if (LOG.isDebugEnabled()) LOG.debug("Reconfiguring {}, but 
driver's customization not yet complete so aborting", this);
-            return;
-        }
-
-        driver.getMachine().copyTo(Streams.newInputStreamWithContents(cfg), 
driver.getRunDir()+"/conf/server.conf");
-
-        installSslKeys("global", getSslConfig());
-
-        for (UrlMapping mapping : getUrlMappings()) {
-            //cache ensures only the first is installed, which is what is 
assumed below
-            installSslKeys(mapping.getDomain(), 
mapping.getConfig(UrlMapping.SSL_CONFIG));
-        }
-    }
-
-    /**
-     * Installs SSL keys named as {@code id.crt} and {@code id.key} where 
nginx can find them.
-     * <p>
-     * Currently skips re-installs (does not support changing)
-     */
-    public void installSslKeys(String id, ProxySslConfig ssl) {
-        if (ssl == null) return;
-
-        if (installedKeysCache.contains(id)) return;
-
-        NginxSshDriver driver = (NginxSshDriver) getDriver();
-
-        if (!Strings.isEmpty(ssl.getCertificateSourceUrl())) {
-            String certificateDestination = 
Strings.isEmpty(ssl.getCertificateDestination()) ? driver.getRunDir() + 
"/conf/" + id + ".crt" : ssl.getCertificateDestination();
-            driver.getMachine().copyTo(ImmutableMap.of("permissions", "0600"),
-                    
ResourceUtils.create(this).getResourceFromUrl(ssl.getCertificateSourceUrl()),
-                    certificateDestination);
-        }
-
-        if (!Strings.isEmpty(ssl.getKeySourceUrl())) {
-            String keyDestination = Strings.isEmpty(ssl.getKeyDestination()) ? 
driver.getRunDir() + "/conf/" + id + ".key" : ssl.getKeyDestination();
-            driver.getMachine().copyTo(ImmutableMap.of("permissions", "0600"),
-                    
ResourceUtils.create(this).getResourceFromUrl(ssl.getKeySourceUrl()),
-                    keyDestination);
-        }
-
-        installedKeysCache.add(id);
-    }
-
-    @Override
-    public String getConfigFile() {
-        NginxSshDriver driver = (NginxSshDriver) getDriver();
-        if (driver==null) {
-            LOG.debug("No driver for {}, so not generating config file (is 
entity stopping? state={})",
-                    this, getAttribute(NginxController.SERVICE_STATE_ACTUAL));
-            return null;
-        }
-
-        NginxConfigFileGenerator templateGenerator = 
getConfig(NginxController.SERVER_CONF_GENERATOR);
-        return templateGenerator.generateConfigFile(driver, this);
-    }
-
-    @Override
-    public Iterable<UrlMapping> getUrlMappings() {
-        // For mapping by URL
-        Group urlMappingGroup = getConfig(NginxController.URL_MAPPINGS);
-        if (urlMappingGroup != null) {
-            return Iterables.filter(urlMappingGroup.getMembers(), 
UrlMapping.class);
-        } else {
-            return Collections.<UrlMapping>emptyList();
-        }
-    }
-
-    @Override
-    public String getShortName() {
-        return "Nginx";
-    }
-
-    public boolean appendSslConfig(String id,
-            StringBuilder out,
-            String prefix,
-            ProxySslConfig ssl,
-            boolean sslBlock,
-            boolean certificateBlock) {
-        if (ssl == null)
-            return false;
-        if (sslBlock) {
-            out.append(prefix);
-            out.append("ssl on;\n");
-        }
-        if (ssl.getReuseSessions()) {
-            out.append(prefix);
-            out.append("proxy_ssl_session_reuse on;");
-        }
-        if (certificateBlock) {
-            String cert;
-            if (Strings.isEmpty(ssl.getCertificateDestination())) {
-                cert = "" + id + ".crt";
-            } else {
-                cert = ssl.getCertificateDestination();
-            }
-
-            out.append(prefix);
-            out.append("ssl_certificate " + cert + ";\n");
-
-            String key;
-            if (!Strings.isEmpty(ssl.getKeyDestination())) {
-                key = ssl.getKeyDestination();
-            } else if (!Strings.isEmpty(ssl.getKeySourceUrl())) {
-                key = "" + id + ".key";
-            } else {
-                key = null;
-            }
-
-            if (key != null) {
-                out.append(prefix);
-                out.append("ssl_certificate_key " + key + ";\n");
-            }
-        }
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java
 
b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java
deleted file mode 100644
index 1ed7e49..0000000
--- 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDefaultConfigGenerator.java
+++ /dev/null
@@ -1,258 +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.entity.proxy.nginx;
-
-import static java.lang.String.format;
-
-import java.util.Collection;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-
-import brooklyn.entity.proxy.ProxySslConfig;
-import brooklyn.util.text.Strings;
-
-/**
- * Generates the {@code server.conf} configuration file using sensors on an 
{@link NginxController}.
- */
-public class NginxDefaultConfigGenerator implements NginxConfigFileGenerator {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(NginxDefaultConfigGenerator.class);
-
-    public NginxDefaultConfigGenerator() { }
-
-    @Override
-    public String generateConfigFile(NginxDriver driver, NginxController 
nginx) {
-        StringBuilder config = new StringBuilder();
-        config.append("\n");
-        config.append(format("pid %s;\n", driver.getPidFile()));
-        config.append("events {\n");
-        config.append("  worker_connections 8196;\n");
-        config.append("}\n");
-        config.append("http {\n");
-
-        ProxySslConfig globalSslConfig = nginx.getSslConfig();
-
-        if (nginx.isSsl()) {
-            verifyConfig(globalSslConfig);
-            appendSslConfig("global", config, "    ", globalSslConfig, true, 
true);
-        }
-
-        // If no servers, then defaults to returning 404
-        // TODO Give nicer page back
-        if (nginx.getDomain()!=null || nginx.getServerPoolAddresses() == null 
|| nginx.getServerPoolAddresses().isEmpty()) {
-            config.append("  server {\n");
-            config.append(getCodeForServerConfig());
-            config.append("    listen "+nginx.getPort()+";\n");
-            config.append(getCodeFor404());
-            config.append("  }\n");
-        }
-
-        // For basic round-robin across the server-pool
-        if (nginx.getServerPoolAddresses() != null && 
nginx.getServerPoolAddresses().size() > 0) {
-            config.append(format("  upstream "+nginx.getId()+" {\n"));
-            if (nginx.isSticky()){
-                config.append("    sticky;\n");
-            }
-            for (String address : nginx.getServerPoolAddresses()) {
-                config.append("    server "+address+";\n");
-            }
-            config.append("  }\n");
-            config.append("  server {\n");
-            config.append(getCodeForServerConfig());
-            config.append("    listen "+nginx.getPort()+";\n");
-            if (nginx.getDomain()!=null)
-                config.append("    server_name "+nginx.getDomain()+";\n");
-            config.append("    location / {\n");
-            config.append("      proxy_pass "+(globalSslConfig != null && 
globalSslConfig.getTargetIsSsl() ? "https" : "http")+"://"+nginx.getId()+";\n");
-            config.append("    }\n");
-            config.append("  }\n");
-        }
-
-        // For mapping by URL
-        Iterable<UrlMapping> mappings = nginx.getUrlMappings();
-        Multimap<String, UrlMapping> mappingsByDomain = 
LinkedHashMultimap.create();
-        for (UrlMapping mapping : mappings) {
-            Collection<String> addrs = 
mapping.getAttribute(UrlMapping.TARGET_ADDRESSES);
-            if (addrs != null && addrs.size() > 0) {
-                mappingsByDomain.put(mapping.getDomain(), mapping);
-            }
-        }
-
-        for (UrlMapping um : mappings) {
-            Collection<String> addrs = 
um.getAttribute(UrlMapping.TARGET_ADDRESSES);
-            if (addrs != null && addrs.size() > 0) {
-                config.append(format("  upstream "+um.getUniqueLabel()+" 
{\n"));
-                if (nginx.isSticky()){
-                    config.append("    sticky;\n");
-                }
-                for (String address: addrs) {
-                    config.append("    server "+address+";\n");
-                }
-                config.append("  }\n");
-            }
-        }
-
-        for (String domain : mappingsByDomain.keySet()) {
-            config.append("  server {\n");
-            config.append(getCodeForServerConfig());
-            config.append("    listen "+nginx.getPort()+";\n");
-            config.append("    server_name "+domain+";\n");
-            boolean hasRoot = false;
-
-            // set up SSL
-            ProxySslConfig localSslConfig = null;
-            for (UrlMapping mappingInDomain : mappingsByDomain.get(domain)) {
-                ProxySslConfig sslConfig = 
mappingInDomain.getConfig(UrlMapping.SSL_CONFIG);
-                if (sslConfig!=null) {
-                    verifyConfig(sslConfig);
-                    if (localSslConfig!=null) {
-                        if (localSslConfig.equals(sslConfig)) {
-                            //ignore identical config specified on multiple 
mappings
-                        } else {
-                            LOG.warn("{} mapping {} provides SSL config for {} 
when a different config had already been provided by another mapping, ignoring 
this one",
-                                    new Object[] {this, mappingInDomain, 
domain});
-                        }
-                    } else if (globalSslConfig!=null) {
-                        if (globalSslConfig.equals(sslConfig)) {
-                            //ignore identical config specified on multiple 
mappings
-                        } else {
-                            LOG.warn("{} mapping {} provides SSL config for {} 
when a different config had been provided at root nginx scope, ignoring this 
one",
-                                    new Object[] {this, mappingInDomain, 
domain});
-                        }
-                    } else {
-                        //new config, is okay
-                        localSslConfig = sslConfig;
-                    }
-                }
-            }
-            if (localSslConfig != null) {
-                appendSslConfig(domain, config, "    ", localSslConfig, true, 
true);
-            }
-
-            for (UrlMapping mappingInDomain : mappingsByDomain.get(domain)) {
-                // TODO Currently only supports "~" for regex. Could add 
support for other options,
-                // such as "~*", "^~", literals, etc.
-                boolean isRoot = mappingInDomain.getPath()==null || 
mappingInDomain.getPath().length()==0 || mappingInDomain.getPath().equals("/");
-                if (isRoot && hasRoot) {
-                    LOG.warn(""+this+" mapping "+mappingInDomain+" provides a 
duplicate / proxy, ignoring");
-                } else {
-                    hasRoot |= isRoot;
-                    String location = isRoot ? "/" : "~ " + 
mappingInDomain.getPath();
-                    config.append("    location "+location+" {\n");
-                    Collection<UrlRewriteRule> rewrites = 
mappingInDomain.getConfig(UrlMapping.REWRITES);
-                    if (rewrites != null && rewrites.size() > 0) {
-                        for (UrlRewriteRule rule: rewrites) {
-                            config.append("      rewrite 
\"^"+rule.getFrom()+"$\" \""+rule.getTo()+"\"");
-                            if (rule.isBreak()) config.append(" break");
-                            config.append(" ;\n");
-                        }
-                    }
-                    config.append("      proxy_pass "+
-                        (localSslConfig != null && 
localSslConfig.getTargetIsSsl() ? "https" :
-                         (localSslConfig == null && globalSslConfig != null && 
globalSslConfig.getTargetIsSsl()) ? "https" :
-                         "http")+
-                        "://"+mappingInDomain.getUniqueLabel()+" ;\n");
-                    config.append("    }\n");
-                }
-            }
-            if (!hasRoot) {
-                //provide a root block giving 404 if there isn't one for this 
server
-                config.append("    location / { \n"+getCodeFor404()+"    }\n");
-            }
-            config.append("  }\n");
-        }
-
-        config.append("}\n");
-
-        return config.toString();
-    }
-
-    protected String getCodeForServerConfig() {
-        // See http://wiki.nginx.org/HttpProxyModule
-        return ""+
-            // this prevents nginx from reporting version number on error pages
-            "    server_tokens off;\n"+
-
-            // this prevents nginx from using the internal proxy_pass codename 
as Host header passed upstream.
-            // Not using $host, as that causes integration test to fail with a 
"connection refused" testing
-            // url-mappings, at URL "http://localhost:${port}/atC0"; (with a 
trailing slash it does work).
-            "    proxy_set_header Host $http_host;\n"+
-
-            // following added, as recommended for wordpress in:
-            // 
http://zeroturnaround.com/labs/wordpress-protips-go-with-a-clustered-approach/#!/
-            "    proxy_set_header X-Forwarded-For 
$proxy_add_x_forwarded_for;\n"+
-            "    proxy_set_header X-Real-IP $remote_addr;\n";
-    }
-
-    protected String getCodeFor404() {
-        return "    return 404;\n";
-    }
-
-    protected void verifyConfig(ProxySslConfig proxySslConfig) {
-          if(Strings.isEmpty(proxySslConfig.getCertificateDestination()) && 
Strings.isEmpty(proxySslConfig.getCertificateSourceUrl())){
-            throw new IllegalStateException("ProxySslConfig can't have a null 
certificateDestination and null certificateSourceUrl. One or both need to be 
set");
-        }
-    }
-
-    protected boolean appendSslConfig(String id, StringBuilder out, String 
prefix, ProxySslConfig ssl,
-                                   boolean sslBlock, boolean certificateBlock) 
{
-        if (ssl == null) return false;
-        if (sslBlock) {
-            out.append(prefix);
-            out.append("ssl on;\n");
-        }
-        if (ssl.getReuseSessions()) {
-            out.append(prefix);
-            out.append("");
-        }
-        if (certificateBlock) {
-            String cert;
-            if (Strings.isEmpty(ssl.getCertificateDestination())) {
-                cert = "" + id + ".crt";
-            } else {
-                cert = ssl.getCertificateDestination();
-            }
-
-            out.append(prefix);
-            out.append("ssl_certificate " + cert + ";\n");
-
-            String key;
-            if (!Strings.isEmpty(ssl.getKeyDestination())) {
-                key = ssl.getKeyDestination();
-            } else if (!Strings.isEmpty(ssl.getKeySourceUrl())) {
-                key = "" + id + ".key";
-            } else {
-                key = null;
-            }
-
-            if (key != null) {
-                out.append(prefix);
-                out.append("ssl_certificate_key " + key + ";\n");
-            }
-
-            out.append("ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n");
-        }
-        return true;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDriver.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDriver.java 
b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDriver.java
deleted file mode 100644
index 1ef651f..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxDriver.java
+++ /dev/null
@@ -1,31 +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.entity.proxy.nginx;
-
-import brooklyn.entity.basic.SoftwareProcessDriver;
-
-public interface NginxDriver extends SoftwareProcessDriver {
-
-    String getRunDir();
-
-    String getPidFile();
-
-    boolean isCustomizationCompleted();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java 
b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
deleted file mode 100644
index 023067a..0000000
--- 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxSshDriver.java
+++ /dev/null
@@ -1,477 +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.entity.proxy.nginx;
-
-import static java.lang.String.format;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.apache.brooklyn.management.ManagementContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.entity.basic.Lifecycle;
-import brooklyn.entity.basic.lifecycle.ScriptHelper;
-import brooklyn.entity.drivers.downloads.DownloadResolver;
-import brooklyn.entity.proxy.AbstractController;
-import brooklyn.location.OsDetails;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.ssh.SshTasks.OnFailingTask;
-import brooklyn.util.text.Strings;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-/**
- * Start a {@link NginxController} in a {@link brooklyn.location.Location} 
accessible over ssh.
- */
-public class NginxSshDriver extends AbstractSoftwareProcessSshDriver 
implements NginxDriver {
-
-    // TODO An alternative way of installing nginx is described at:
-    //   http://sjp.co.nz/posts/building-nginx-for-debian-systems/
-    // It's use of `apt-get source nginx` and `apt-get build-dep nginx` makes
-    // it look higher level and therefore more appealing.
-
-    public static final Logger log = 
LoggerFactory.getLogger(NginxSshDriver.class);
-    public static final String NGINX_PID_FILE = "logs/nginx.pid";
-
-    private boolean customizationCompleted = false;
-
-    public NginxSshDriver(NginxControllerImpl entity, SshMachineLocation 
machine) {
-        super(entity, machine);
-
-        entity.setAttribute(Attributes.LOG_FILE_LOCATION, 
getLogFileLocation());
-        entity.setAttribute(NginxController.ACCESS_LOG_LOCATION, 
getAccessLogLocation());
-        entity.setAttribute(NginxController.ERROR_LOG_LOCATION, 
getErrorLogLocation());
-    }
-
-    @Override
-    public NginxControllerImpl getEntity() {
-        return (NginxControllerImpl) super.getEntity();
-    }
-
-    public String getLogFileLocation() {
-        return format("%s/console", getRunDir());
-    }
-
-    public String getAccessLogLocation() {
-        String accessLog = 
entity.getConfig(NginxController.ACCESS_LOG_LOCATION);
-        return format("%s/%s", getRunDir(), accessLog);
-    }
-
-    public String getErrorLogLocation() {
-        String errorLog = entity.getConfig(NginxController.ERROR_LOG_LOCATION);
-        return format("%s/%s", getRunDir(), errorLog);
-    }
-
-    /** By default Nginx writes the pid of the master process to {@code 
logs/nginx.pid} */
-    @Override
-    public String getPidFile() {
-        return format("%s/%s", getRunDir(), NGINX_PID_FILE);
-    }
-
-    @Deprecated /** @deprecated since 0.7.0 use #getPort */
-    public Integer getHttpPort() {
-        return getEntity().getPort();
-    }
-
-    public Integer getPort() {
-        return getEntity().getPort();
-    }
-
-    @Override
-    public void rebind() {
-        customizationCompleted = true;
-    }
-
-    @Override
-    public void postLaunch() {
-        entity.setAttribute(NginxController.PID_FILE, getRunDir() + "/" + 
AbstractSoftwareProcessSshDriver.PID_FILENAME);
-        if (((AbstractController)entity).isSsl()) {
-            entity.setAttribute(Attributes.HTTPS_PORT, getPort());
-            ((EntityInternal)entity).removeAttribute(Attributes.HTTP_PORT);
-        } else {
-            entity.setAttribute(Attributes.HTTP_PORT, getPort());
-            ((EntityInternal)entity).removeAttribute(Attributes.HTTPS_PORT);
-        }
-        super.postLaunch();
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), 
resolver.getUnpackedDirectoryName(format("nginx-%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        // inessential here, installation will fail later if it needs to sudo 
(eg if using port 80)
-        
DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(getMachine(), 
OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL)).orSubmitAndBlock();
-
-        List<String> nginxUrls = resolver.getTargets();
-        String nginxSaveAs = resolver.getFilename();
-
-        boolean sticky = ((NginxController) entity).isSticky();
-        boolean isMac = getMachine().getOsDetails().isMac();
-
-        MutableMap<String, String> installGccPackageFlags = MutableMap.of(
-                "onlyifmissing", "gcc",
-                "yum", "gcc",
-                "apt", "gcc",
-                "zypper", "gcc",
-                "port", null);
-        MutableMap<String, String> installMakePackageFlags = MutableMap.of(
-                "onlyifmissing", "make",
-                "yum", "make",
-                "apt", "make",
-                "zypper", "make",
-                "port", null);
-        MutableMap<String, String> installPackageFlags = MutableMap.of(
-                "yum", "openssl-devel pcre-devel",
-                "apt", "libssl-dev zlib1g-dev libpcre3-dev",
-                "zypper", "libopenssl-devel pcre-devel",
-                "port", null);
-
-        String stickyModuleVersion = 
entity.getConfig(NginxController.STICKY_VERSION);
-        DownloadResolver stickyModuleResolver = 
mgmt().getEntityDownloadsManager().newDownloader(
-                this, "stickymodule", ImmutableMap.of("addonversion", 
stickyModuleVersion));
-        List<String> stickyModuleUrls = stickyModuleResolver.getTargets();
-        String stickyModuleSaveAs = stickyModuleResolver.getFilename();
-        String stickyModuleExpandedInstallDir = String.format("%s/src/%s", 
getExpandedInstallDir(),
-                
stickyModuleResolver.getUnpackedDirectoryName("nginx-sticky-module-"+stickyModuleVersion));
-
-        List<String> cmds = Lists.newArrayList();
-
-        cmds.add(BashCommands.INSTALL_TAR);
-        cmds.add(BashCommands.alternatives(
-                BashCommands.ifExecutableElse0("apt-get", 
BashCommands.installPackage("build-essential")),
-                BashCommands.ifExecutableElse0("yum", BashCommands.sudo("yum 
-y --nogpgcheck groupinstall \"Development Tools\""))));
-        cmds.add(BashCommands.installPackage(installGccPackageFlags, 
"nginx-prerequisites-gcc"));
-        cmds.add(BashCommands.installPackage(installMakePackageFlags, 
"nginx-prerequisites-make"));
-        cmds.add(BashCommands.installPackage(installPackageFlags, 
"nginx-prerequisites"));
-        cmds.addAll(BashCommands.commandsToDownloadUrlsAs(nginxUrls, 
nginxSaveAs));
-
-        String pcreExpandedInstallDirname = "";
-        if (isMac) {
-            String pcreVersion = 
entity.getConfig(NginxController.PCRE_VERSION);
-            DownloadResolver pcreResolver = 
mgmt().getEntityDownloadsManager().newDownloader(
-                    this, "pcre", ImmutableMap.of("addonversion", 
pcreVersion));
-            List<String> pcreUrls = pcreResolver.getTargets();
-            String pcreSaveAs = pcreResolver.getFilename();
-            pcreExpandedInstallDirname = 
pcreResolver.getUnpackedDirectoryName("pcre-"+pcreVersion);
-
-            // Install PCRE
-            cmds.addAll(BashCommands.commandsToDownloadUrlsAs(pcreUrls, 
pcreSaveAs));
-            cmds.add(format("mkdir -p %s/pcre-dist", getInstallDir()));
-            cmds.add(format("tar xvzf %s", pcreSaveAs));
-            cmds.add(format("cd %s", pcreExpandedInstallDirname));
-            cmds.add(format("./configure --prefix=%s/pcre-dist", 
getInstallDir()));
-            cmds.add("make");
-            cmds.add("make install");
-            cmds.add("cd ..");
-        }
-
-        cmds.add(format("tar xvzf %s", nginxSaveAs));
-        cmds.add(format("cd %s", getExpandedInstallDir()));
-
-        if (sticky) {
-            // Latest versions of sticky module expand to a different folder 
than the file name.
-            // Extract to folder set by us so we know where the sources are.
-            cmds.add(format("mkdir -p %s", stickyModuleExpandedInstallDir));
-            cmds.add(format("pushd %s", stickyModuleExpandedInstallDir));
-            
cmds.addAll(BashCommands.commandsToDownloadUrlsAs(stickyModuleUrls, 
stickyModuleSaveAs));
-            cmds.add(format("tar --strip-component=1 -xvzf %s", 
stickyModuleSaveAs));
-            cmds.add("popd");
-        }
-
-        // Note that for OS X, not including space after "-L" because broken 
in 10.6.8 (but fixed in 10.7.x)
-        //      see http://trac.nginx.org/nginx/ticket/227
-        String withLdOpt = entity.getConfig(NginxController.WITH_LD_OPT);
-        if (isMac) withLdOpt = format("-L%s/pcre-dist/lib", getInstallDir()) + 
(Strings.isBlank(withLdOpt) ? "" : " " + withLdOpt);
-        String withCcOpt = entity.getConfig(NginxController.WITH_CC_OPT);
-        
-        if (isMac) {
-            // TODO Upgrade sticky module as soon as a fix for 
https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng/issue/16/can-not-compile-on-macosx-yosemite
-            // is released and remove this block.
-            withCcOpt = (Strings.isBlank(withCcOpt) ? "" : (withCcOpt + " ")) 
+ "-Wno-error";
-        }
-
-        StringBuilder configureCommand = new StringBuilder("./configure")
-                .append(format(" --prefix=%s/dist", getExpandedInstallDir()))
-                .append(" --with-http_ssl_module")
-                .append(sticky ? format(" --add-module=%s ", 
stickyModuleExpandedInstallDir) : "")
-                .append(!Strings.isBlank(withLdOpt) ? format(" 
--with-ld-opt=\"%s\"", withLdOpt) : "")
-                .append(!Strings.isBlank(withCcOpt) ? format(" 
--with-cc-opt=\"%s\"", withCcOpt) : "")
-                ;
-        if (isMac) {
-            configureCommand.append(" --with-pcre=")
-                    
.append(getInstallDir()).append("/").append(pcreExpandedInstallDirname);
-        }
-
-        cmds.addAll(ImmutableList.of(
-                "mkdir -p dist",
-                configureCommand.toString(),
-                "make install"));
-
-        ScriptHelper script = newScript(INSTALLING)
-                .body.append(cmds)
-                .header.prepend("set -x")
-                .gatherOutput()
-                .failOnNonZeroResultCode(false);
-
-        int result = script.execute();
-
-        if (result != 0) {
-            String notes = "likely an error building nginx. consult the 
brooklyn log ssh output for further details.\n"+
-                    "note that this Brooklyn nginx driver compiles nginx from 
source. " +
-                    "it attempts to install common prerequisites but this does 
not always succeed.\n";
-            OsDetails os = getMachine().getOsDetails();
-            if (os.isMac()) {
-                notes += "deploying to Mac OS X, you will require Xcode and 
Xcode command-line tools, and on " +
-                        "some versions the pcre library (e.g. using macports, 
sudo port install pcre).\n";
-            }
-            if (os.isWindows()) {
-                notes += "this nginx driver is not designed for windows, 
unless cygwin is installed, and you are patient.\n";
-            }
-            if 
(getEntity().getApplication().getClass().getCanonicalName().startsWith("brooklyn.demo."))
 {
-                // this is maybe naughty ... but since we use nginx in the 
first demo example,
-                // and since it's actually pretty complicated, let's give a 
little extra hand-holding
-                notes +=
-                        "if debugging this is all a bit much and you just want 
to run a demo, " +
-                        "you have two fairly friendly options.\n" +
-                        "1. you can use a well known cloud, like AWS or 
Rackspace, where this should run " +
-                        "in a tried-and-tested Ubuntu or CentOS environment, 
without any problems " +
-                        "(and if it does let us know and we'll fix it!).\n"+
-                        "2. or you can just use the demo without nginx, 
instead access the appserver instances directly.\n";
-            }
-
-            if (!script.getResultStderr().isEmpty()) {
-                notes += "\n" + "STDERR\n" + script.getResultStderr()+"\n";
-                Streams.logStreamTail(log, "STDERR of problem in 
"+Tasks.current(), Streams.byteArrayOfString(script.getResultStderr()), 1024);
-            }
-            if (!script.getResultStdout().isEmpty()) {
-                notes += "\n" + "STDOUT\n" + script.getResultStdout()+"\n";
-                Streams.logStreamTail(log, "STDOUT of problem in 
"+Tasks.current(), Streams.byteArrayOfString(script.getResultStdout()), 1024);
-            }
-
-            Tasks.setExtraStatusDetails(notes.trim());
-
-            throw new IllegalStateException("Installation of nginx failed 
(shell returned non-zero result "+result+")");
-        }
-    }
-
-    private ManagementContext mgmt() {
-        return ((EntityInternal) entity).getManagementContext();
-    }
-
-    @Override
-    public void customize() {
-        newScript(CUSTOMIZING)
-                .body.append(
-                        format("mkdir -p %s", getRunDir()),
-                        format("cp -R %s/dist/{conf,html,logs,sbin} %s", 
getExpandedInstallDir(), getRunDir()))
-                .execute();
-
-        // Install static content archive, if specified
-        String archiveUrl = 
entity.getConfig(NginxController.STATIC_CONTENT_ARCHIVE_URL);
-        if (Strings.isNonBlank(archiveUrl)) {
-            getEntity().deploy(archiveUrl);
-        }
-
-        customizationCompleted = true;
-    }
-
-    @Override
-    public boolean isCustomizationCompleted() {
-        return customizationCompleted;
-    }
-
-    @Override
-    public void launch() {
-        // TODO if can't be root, and ports > 1024 are in the allowed port 
range,
-        // prefer that; could do this on SshMachineLocation which implements 
PortSupplier,
-        // invoked from PortAttrSensorAndConfigKey, which is invoked from 
MachineLifecycleTasks.preStartCustom
-        Networking.checkPortsValid(MutableMap.of("port", getPort()));
-
-        getEntity().doExtraConfigurationDuringStart();
-
-        // We wait for evidence of running because, using
-        // 
brooklyn.ssh.config.tool.class=brooklyn.util.internal.ssh.cli.SshCliTool,
-        // we saw the ssh session return before the tomcat process was fully 
running
-        // so the process failed to start.
-        newScript(MutableMap.of("usePidFile", false), LAUNCHING)
-                .body.append(
-                        format("cd %s", getRunDir()),
-                        BashCommands.requireExecutable("./sbin/nginx"),
-                        sudoBashCIfPrivilegedPort(getPort(), format(
-                                "nohup ./sbin/nginx -p %s/ -c conf/server.conf 
> %s 2>&1 &", getRunDir(), getLogFileLocation())),
-                        format("for i in {1..10}\n" +
-                                "do\n" +
-                                "    test -f %1$s && ps -p `cat %1$s` && 
exit\n" +
-                                "    sleep 1\n" +
-                                "done\n" +
-                                "echo \"No explicit error launching nginx but 
couldn't find process by pid; continuing but may subsequently fail\"\n" +
-                                "cat %2$s | tee /dev/stderr",
-                                getPidFile(), getLogFileLocation()))
-                .execute();
-    }
-
-    public static String sudoIfPrivilegedPort(int port, String command) {
-        return port < 1024 ? BashCommands.sudo(command) : command;
-    }
-
-    public static String sudoBashCIfPrivilegedPort(int port, String command) {
-        return port < 1024 ? BashCommands.sudo("bash -c '"+command+"'") : 
command;
-    }
-
-    @Override
-    public boolean isRunning() {
-        return newScript(MutableMap.of("usePidFile", getPidFile()), 
CHECK_RUNNING).execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        // Don't `kill -9`, as that doesn't stop the worker processes
-        newScript(MutableMap.of("usePidFile", false), STOPPING).
-                body.append(
-                        format("cd %s", getRunDir()),
-                        format("export PID=`cat %s`", getPidFile()),
-                        "test -n \"$PID\" || exit 0",
-                        sudoIfPrivilegedPort(getPort(), "kill $PID"))
-                .execute();
-    }
-
-    @Override
-    public void kill() {
-        stop();
-    }
-
-    private final ExecController reloadExecutor = new ExecController(
-            entity+"->reload",
-            new Runnable() {
-                @Override
-                public void run() {
-                    reloadImpl();
-                }
-            });
-
-    public void reload() {
-        // If there are concurrent calls to reload (such that some calls come 
in when another call is queued), then
-        // don't bother doing the subsequent calls. Instead just rely on the 
currently queued call.
-        //
-        // Motivation is that calls to nginx.reload were backing up: we ended 
up executing lots of them in parallel
-        // when there were several changes to the nginx conifg that requiring 
a reload. The problem can be particularly
-        // bad because the ssh commands take a second or two - if 10 changes 
were made to the config in that time, we'd
-        // end up executing reload 10 times in parallel.
-
-        reloadExecutor.run();
-    }
-
-    private void reloadImpl() {
-        // Note that previously, if serviceUp==false then we'd restart nginx.
-        // That caused a race on stop()+reload(): nginx could simultaneously 
be stopping and also reconfiguring
-        // (e.g. due to a cluster-resize), the restart() would leave nginx 
running even after stop() had returned.
-        //
-        // Now we rely on NginxController always calling update (and thus 
reload) once it has started. This is
-        // done in AbstractController.postActivation().
-        //
-        // If our blocking check sees that !isRunning() (and if a separate 
thread is starting it, and subsequently
-        // calling waitForEntityStart()), we can guarantee that the 
start-thread's call to update will happen after
-        // this call to reload. So we this can be a no-op, and just rely on 
that subsequent call to update.
-
-        Lifecycle lifecycle = 
entity.getAttribute(NginxController.SERVICE_STATE_ACTUAL);
-        if (lifecycle==Lifecycle.STOPPING || lifecycle==Lifecycle.STOPPED || 
!isRunning()) {
-            log.debug("Ignoring reload of nginx "+entity+", because service is 
not running (state "+lifecycle+")");
-            return;
-        }
-
-        doReloadNow();
-    }
-
-    /**
-     * Instructs nginx to reload its configuration (without restarting, so 
don't lose any requests).
-     * Can be overridden if necessary, to change the call used for reloading.
-     */
-    private void doReloadNow() {
-        // We use kill -HUP because that is recommended at 
http://wiki.nginx.org/CommandLine,
-        // but there is no noticeable difference (i.e. no impact on #365) 
compared to:
-        //   sudoIfPrivilegedPort(getHttpPort(), format("./sbin/nginx -p %s/ 
-c conf/server.conf -s reload", getRunDir()))
-        //
-        // Note that if conf file is invalid, you'll get no stdout/stderr from 
`kill` but you
-        // do from using `nginx ... -s reload` so that can be handy when 
manually debugging.
-
-        log.debug("reloading nginx by simularing restart (kill -HUP) - {}", 
entity);
-        newScript(RESTARTING)
-                .body.append(
-                        format("cd %s", getRunDir()),
-                        format("export PID=`cat %s`", getPidFile()),
-                        sudoIfPrivilegedPort(getPort(), "kill -HUP $PID"))
-                .execute();
-    }
-
-    /**
-     * Executes the given task, but only if another thread hasn't executed it 
for us (where the other thread
-     * began executing it after the current caller of {@link #run()} began 
attempting to do so itself).
-     *
-     * @author aled
-     */
-    private static class ExecController {
-        private final String summary;
-        private final Runnable task;
-        private final AtomicLong counter = new AtomicLong();
-
-        ExecController(String summary, Runnable task) {
-            this.summary = summary;
-            this.task = task;
-        }
-
-        void run() {
-            long preCount = counter.get();
-            synchronized (this) {
-                if (counter.compareAndSet(preCount, preCount+1)) {
-                    try {
-                        if (log.isDebugEnabled()) log.debug("Executing {}; 
incremented count to {}", new Object[] {summary, counter});
-                        task.run();
-                    } catch (Exception e) {
-                        if (log.isDebugEnabled()) log.debug("Failed executing 
{}; reseting count to {} and propagating exception: {}", new Object[] {summary, 
preCount, e});
-                        counter.set(preCount);
-                        throw Exceptions.propagate(e);
-                    }
-                } else {
-                    if (log.isDebugEnabled()) log.debug("Not executing {} 
because executed by another thread subsequent to us attempting (preCount {}; 
count {})", new Object[] {summary, preCount, counter});
-                }
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
 
b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
deleted file mode 100644
index aea735f..0000000
--- 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
+++ /dev/null
@@ -1,82 +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.entity.proxy.nginx;
-
-import java.util.Collection;
-import java.util.Map;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.proxy.ProxySslConfig;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
-
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-
-/**
- * Processes a FreeMarker template to generate the {@code server.conf} 
configuration file for an 
- * {@link NginxController}.
- * <p>
- * Note this must be explicitly enabled via {@link 
NginxController#SERVER_CONF_GENERATOR}.
- */
-public class NginxTemplateConfigGenerator implements NginxConfigFileGenerator {
-
-    public static final ConfigKey<String> SERVER_CONF_TEMPLATE_URL = 
ConfigKeys.newStringConfigKey(
-            "nginx.config.templateUrl", "The server.conf configuration file 
URL (FreeMarker template). "
-                + "Only applies if 'nginx.config.generator' specifies a 
generator which uses a template.", 
-                "classpath://brooklyn/entity/proxy/nginx/server.conf");
-
-    public NginxTemplateConfigGenerator() { }
-
-    @Override
-    public String generateConfigFile(NginxDriver driver, NginxController 
nginx) {
-        // Check template URL exists
-        String templateUrl = 
driver.getEntity().getConfig(NginxController.SERVER_CONF_TEMPLATE_URL);
-        ResourceUtils.create(this).checkUrlExists(templateUrl);
-
-        // Check SSL configuration
-        ProxySslConfig ssl = 
driver.getEntity().getConfig(NginxController.SSL_CONFIG);
-        if (ssl != null && Strings.isEmpty(ssl.getCertificateDestination()) && 
Strings.isEmpty(ssl.getCertificateSourceUrl())) {
-            throw new IllegalStateException("ProxySslConfig can't have a null 
certificateDestination and null certificateSourceUrl. One or both need to be 
set");
-        }
-
-        // For mapping by URL
-        Iterable<UrlMapping> mappings = ((NginxController) 
driver.getEntity()).getUrlMappings();
-        Multimap<String, UrlMapping> mappingsByDomain = 
LinkedHashMultimap.create();
-        for (UrlMapping mapping : mappings) {
-            Collection<String> addrs = 
mapping.getAttribute(UrlMapping.TARGET_ADDRESSES);
-            if (addrs != null && addrs.size() > 0) {
-                mappingsByDomain.put(mapping.getDomain(), mapping);
-            }
-        }
-        Map<String, Object> substitutions = MutableMap.<String, 
Object>builder()
-                .putIfNotNull("ssl", ssl)
-                .put("urlMappings", mappings)
-                .put("domainMappings", mappingsByDomain)
-                .build();
-
-        // Get template contents and process
-        String contents = 
ResourceUtils.create(driver.getEntity()).getResourceAsString(templateUrl);
-        return TemplateProcessor.processTemplateContents(contents, driver, 
substitutions);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlMapping.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlMapping.java 
b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlMapping.java
deleted file mode 100644
index d8a0377..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlMapping.java
+++ /dev/null
@@ -1,102 +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.entity.proxy.nginx;
-
-import java.util.Collection;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.Entity;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.basic.AbstractGroup;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.MethodEffector;
-import brooklyn.entity.proxy.AbstractController;
-import brooklyn.entity.proxy.ProxySslConfig;
-import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
-
-import com.google.common.reflect.TypeToken;
-
-/**
- * This is a group whose members will be made available to a load-balancer / 
URL forwarding service (such as nginx).
- * Configuration requires a <b>domain</b> and some mechanism for finding 
members.
- * The easiest way to find members is using a <b>target</b> whose children 
will be tracked,
- * but alternative membership policies can also be used.
- */
-@ImplementedBy(UrlMappingImpl.class)
-public interface UrlMapping extends AbstractGroup {
-
-    MethodEffector<Void> DISCARD = new MethodEffector<Void>(UrlMapping.class, 
"discard");
-
-    @SetFromFlag("label")
-    ConfigKey<String> LABEL = ConfigKeys.newStringConfigKey(
-            "urlmapping.label", "optional human-readable label to identify a 
server");
-
-    @SetFromFlag("domain")
-    ConfigKey<String> DOMAIN = ConfigKeys.newStringConfigKey(
-            "urlmapping.domain", "domain (hostname, e.g. www.foo.com) to 
present for this URL map rule; required.");
-
-    @SetFromFlag("path")
-    ConfigKey<String> PATH = ConfigKeys.newStringConfigKey(
-            "urlmapping.path", "URL path (pattern) for this URL map rule. 
Currently only supporting regex matches "+
-            "(if not supplied, will match all paths at the indicated domain)");
-
-    @SetFromFlag("ssl")
-    ConfigKey<ProxySslConfig> SSL_CONFIG = AbstractController.SSL_CONFIG;
-
-    @SetFromFlag("rewrites")
-    @SuppressWarnings("serial")
-    ConfigKey<Collection<UrlRewriteRule>> REWRITES = 
ConfigKeys.newConfigKey(new TypeToken<Collection<UrlRewriteRule>>() { },
-            "urlmapping.rewrites", "Set of URL rewrite rules to apply");
-
-    @SetFromFlag("target")
-    ConfigKey<Entity> TARGET_PARENT = ConfigKeys.newConfigKey(Entity.class,
-            "urlmapping.target.parent", "optional target entity whose children 
will be pointed at by this mapper");
-
-    @SuppressWarnings("serial")
-    AttributeSensor<Collection<String>> TARGET_ADDRESSES = 
Sensors.newSensor(new TypeToken<Collection<String>>() { },
-            "urlmapping.target.addresses", "set of addresses which should be 
forwarded to by this URL mapping");
-
-    String getUniqueLabel();
-
-    /** Adds a rewrite rule, must be called at config time. See {@link 
UrlRewriteRule} for more info. */
-    UrlMapping addRewrite(String from, String to);
-
-    /** Adds a rewrite rule, must be called at config time. See {@link 
UrlRewriteRule} for more info. */
-    UrlMapping addRewrite(UrlRewriteRule rule);
-
-    String getDomain();
-
-    String getPath();
-
-    Entity getTarget();
-
-    void setTarget(Entity target);
-
-    void recompute();
-
-    Collection<String> getTargetAddresses();
-
-    ProxySslConfig getSsl();
-
-    @Effector(description="Unmanages the url-mapping, so it is discarded and 
no longer applies")
-    void discard();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlMappingImpl.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlMappingImpl.java 
b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlMappingImpl.java
deleted file mode 100644
index 482e317..0000000
--- 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlMappingImpl.java
+++ /dev/null
@@ -1,223 +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.entity.proxy.nginx;
-
-import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-import org.apache.brooklyn.management.SubscriptionHandle;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.AbstractGroupImpl;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.EntityPredicates;
-import brooklyn.entity.proxy.ProxySslConfig;
-import brooklyn.entity.trait.Changeable;
-import brooklyn.entity.trait.Startable;
-import brooklyn.entity.webapp.WebAppServiceConstants;
-import brooklyn.event.SensorEvent;
-import brooklyn.event.SensorEventListener;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-
-/**
- * This is a group whose members will be made available to a load-balancer / 
URL forwarding service (such as nginx).
- * <p>
- * Configuration requires a <b>domain</b> and some mechanism for finding 
members.
- * The easiest way to find members is using a <b>target</b> whose children 
will be tracked,
- * but alternative membership policies can also be used.
- */
-public class UrlMappingImpl extends AbstractGroupImpl implements UrlMapping {
-
-    private static final Logger log = 
LoggerFactory.getLogger(UrlMapping.class);
-
-    public UrlMappingImpl() {
-        super();
-    }
-
-    @Override
-    public String getUniqueLabel() {
-        String l = getConfig(LABEL);
-        if (groovyTruth(l)) return getId()+"-"+l;
-        else return getId();
-    }
-
-    /** adds a rewrite rule, must be called at config time.  see {@link 
UrlRewriteRule} for more info. */
-    @Override
-    public synchronized UrlMapping addRewrite(String from, String to) {
-        return addRewrite(new UrlRewriteRule(from, to));
-    }
-
-    /** adds a rewrite rule, must be called at config time.  see {@link 
UrlRewriteRule} for more info. */
-    @Override
-    public synchronized UrlMapping addRewrite(UrlRewriteRule rule) {
-        Collection<UrlRewriteRule> rewrites = getConfig(REWRITES);
-        if (rewrites==null) {
-            rewrites = new ArrayList<UrlRewriteRule>();
-        }
-        rewrites.add(rule);
-        setConfig(REWRITES, rewrites);
-        return this;
-    }
-
-    @Override
-    public String getDomain() {
-        return Preconditions.checkNotNull( getConfig(DOMAIN), "domain config 
argument required");
-    }
-
-    @Override
-    public String getPath() {
-        return getConfig(PATH);
-    }
-
-    @Override
-    public Entity getTarget() {
-        return getConfig(TARGET_PARENT);
-    }
-
-    @Override
-    public void setTarget(Entity target) {
-        setConfig(TARGET_PARENT, target);
-        recompute();
-    }
-
-    @Override
-    public void onManagementStarting() {
-        super.onManagementStarting();
-
-        if (getConfig(TARGET_PARENT) != null) {
-            recompute();
-            // following line could be more efficient (just modify the 
addresses set, not clearing it each time;
-            // but since addresses is lazy loaded not that big a deal)
-            // subscribe(this, Changeable.GROUP_SIZE, { resetAddresses(true) } 
as SensorEventListener);
-            // above not needed since our target tracking figures this out
-        }
-    }
-
-    /** defines how address string, ie  hostname:port, is constructed from a 
given entity.
-     * returns null if not possible.
-     * <p>
-     * the default is to look at HOSTNAME and HTTPS_PORT or HTTP_PORT 
attribute sensors (depending on SSL_CONFIG being set with targetIsSsl).
-     * <p>
-     * this method is suitable (intended) for overriding if needed.
-     */
-    protected String getAddressOfEntity(Entity s) {
-        String h = s.getAttribute(Attributes.HOSTNAME);
-
-        Integer p = null;
-        Set<String> protos = 
s.getAttribute(WebAppServiceConstants.ENABLED_PROTOCOLS);
-        ProxySslConfig sslConfig = getConfig(SSL_CONFIG);
-        if (sslConfig != null && sslConfig.getTargetIsSsl()) {
-            // use ssl
-            if (protos != null && hasProtocol(protos, "https")) {
-                // proto configured correctly
-            } else {
-                // proto not defined; use https anyway, but it might fail
-                log.warn("Misconfiguration for "+this+": 
ENABLED_PROTOCOLS='"+protos+"' for "+s+" but sslConfig="+sslConfig);
-            }
-            p = s.getAttribute(Attributes.HTTPS_PORT);
-            if (p == null)
-                log.warn("Misconfiguration for "+this+": 
sslConfig="+sslConfig+" but no HTTPS_PORT on "+s);
-        }
-        if (p == null) {
-            // default to http
-            p = s.getAttribute(Attributes.HTTP_PORT);
-        }
-
-        if (groovyTruth(h) && p != null) return h+":"+p;
-        log.error("Unable to construct hostname:port representation for "+s+"; 
skipping in "+this);
-        return null;
-    }
-
-    protected synchronized void recomputeAddresses() {
-        Set<String> resultM = Sets.newLinkedHashSet();
-        for (Entity s: getMembers()) {
-            String hp = getAddressOfEntity(s);
-            if (hp != null) resultM.add(hp);
-        }
-        Set<String> result = Collections.unmodifiableSet(resultM);
-        Collection<String> oldAddresses = getAttribute(TARGET_ADDRESSES);
-        if (oldAddresses == null || 
!result.equals(ImmutableSet.copyOf(oldAddresses))) {
-            setAttribute(TARGET_ADDRESSES, result);
-        }
-    }
-
-    public Collection<String> getTargetAddresses() {
-        return getAttribute(TARGET_ADDRESSES);
-    }
-
-    public ProxySslConfig getSsl() {
-        return getConfig(SSL_CONFIG);
-    }
-
-    // FIXME Do we really need this?!
-    protected SubscriptionHandle getSubscriptionHandle() {
-        return subscriptionHandle;
-    }
-
-    private SubscriptionHandle subscriptionHandle;
-    private SubscriptionHandle subscriptionHandle2;
-
-    @Override
-    public synchronized void recompute() {
-        if (subscriptionHandle != null) 
getSubscriptionContext().unsubscribe(subscriptionHandle);
-        if (subscriptionHandle2 != null) 
getSubscriptionContext().unsubscribe(subscriptionHandle2);
-
-        Entity t = getTarget();
-        if (t != null) {
-            subscriptionHandle = subscribeToChildren(t, Startable.SERVICE_UP, 
new SensorEventListener<Boolean>() {
-                @Override public void onEvent(SensorEvent<Boolean> event) {
-                    boolean changed = (event.getValue()) ? 
addMember(event.getSource()) : removeMember(event.getSource());
-                    if (changed) {
-                        recomputeAddresses();
-                    }
-                }});
-            subscriptionHandle2 = subscribe(t, Changeable.MEMBER_REMOVED, new 
SensorEventListener<Entity>() {
-                @Override public void onEvent(SensorEvent<Entity> event) {
-                    removeMember(event.getValue());
-                    // recompute, irrespective of change, because framework 
may have already invoked the removeMember call
-                    recomputeAddresses();
-                }});
-            setMembers(t.getChildren(), 
EntityPredicates.attributeEqualTo(Startable.SERVICE_UP, true));
-        }
-
-        recomputeAddresses();
-    }
-
-    @Override
-    public void discard() {
-        Entities.unmanage(this);
-    }
-
-    private boolean hasProtocol(Collection<String> protocols, String desired) {
-        for (String contender : protocols) {
-            if ("https".equals(contender.toLowerCase())) return true;
-        }
-        return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlRewriteRule.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlRewriteRule.java 
b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlRewriteRule.java
deleted file mode 100644
index ee690b5..0000000
--- 
a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/UrlRewriteRule.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.proxy.nginx;
-
-import java.io.Serializable;
-
-/** records a rewrite rule for use in URL rewriting such as by nginx;
- * from and to are expected to be usual regex replacement strings,
- * with the convention here (for portability) that:
- * <li>
- * <it> from should match the entire path (internally is wrapped with ^ and $ 
for nginx);
- * <it> to can refer to $1, $2 from the groups in from
- * </li>
- * so eg use from = (.*)A(.*)  and to = $1B$2 to change all occurrences of A 
to B
- */
-public class UrlRewriteRule implements Serializable {
-    
-    private static final long serialVersionUID = -8457441487467968553L;
-    
-    String from, to;
-    boolean isBreak;
-    
-    /* there is also a flag "last" possible on nginx which might be useful,
-     * but i don't know how portable that is --
-     * we'll know e.g. when we support HA Proxy and others.
-     * presumably everything has at least one "break-after-this-rewrite" mode
-     * so i think we're safe having one in here.
-     */
-
-    public UrlRewriteRule() {}
-    public UrlRewriteRule(String from, String to) {
-        this.from = from;
-        this.to = to;
-    }
-    
-    public String getFrom() {
-        return from;
-    }
-    public void setFrom(String from) {
-        this.from = from;
-    }
-    public String getTo() {
-        return to;
-    }
-    public void setTo(String to) {
-        this.to = to;
-    }
-        
-    public boolean isBreak() {
-        return isBreak;
-    }
-    public void setBreak(boolean isBreak) {
-        this.isBreak = isBreak;
-    }
-
-    public UrlRewriteRule setBreak() { setBreak(true); return this; }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
----------------------------------------------------------------------
diff --git 
a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
 
b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
deleted file mode 100644
index 7da9e11..0000000
--- 
a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppCluster.java
+++ /dev/null
@@ -1,113 +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.entity.webapp;
-
-import org.apache.brooklyn.catalog.Catalog;
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.Entity;
-import brooklyn.entity.Group;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.ConfigurableEntityFactory;
-import brooklyn.entity.basic.DynamicGroup;
-import brooklyn.entity.basic.Lifecycle;
-import brooklyn.entity.group.Cluster;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.entity.proxy.LoadBalancer;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.entity.trait.MemberReplaceable;
-import brooklyn.entity.trait.Resizable;
-import brooklyn.entity.trait.Startable;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
-
-/**
- * This entity contains the sub-groups and entities that go in to a single 
location (e.g. datacenter)
- * to provide web-app cluster functionality, viz load-balancer (controller) 
and webapp software processes.
- * <p>
- * You can customise the web server by customising the memberSpec.
- * <p>
- * The children of this entity are:
- * <ul>
- * <li>a {@link brooklyn.entity.group.DynamicCluster} of {@link 
WebAppService}s (defaults to JBoss7Server)
- * <li>a cluster controller (defaulting to Nginx if none supplied)
- * </ul>
- * 
- * This entity is also a group whose members mirror those of the child 
DynamicCluster (so do not include the load balancer).
- * This is convenient for associating policies such as ServiceReplacer with 
this entity, rather 
- * than with the child {@link brooklyn.entity.group.DynamicCluster}. However, 
note that changing this entity's
- * members has no effect on the members of the underlying DynamicCluster - 
treat this as a read-only view.
- */
-@Catalog(name="Controlled Dynamic Web-app Cluster", description="A cluster of 
load-balanced web-apps, which can be dynamically re-sized")
-@ImplementedBy(ControlledDynamicWebAppClusterImpl.class)
-public interface ControlledDynamicWebAppCluster extends DynamicGroup, Entity, 
Startable, Resizable, MemberReplaceable,
-        Group, ElasticJavaWebAppService, 
JavaWebAppService.CanDeployAndUndeploy, JavaWebAppService.CanRedeployAll {
-    
-    @SetFromFlag("initialSize")
-    public static ConfigKey<Integer> INITIAL_SIZE = 
ConfigKeys.newConfigKeyWithDefault(Cluster.INITIAL_SIZE, 1);
-
-    @SetFromFlag("controller")
-    public static BasicAttributeSensorAndConfigKey<LoadBalancer> CONTROLLER = 
new BasicAttributeSensorAndConfigKey<LoadBalancer>(
-        LoadBalancer.class, "controlleddynamicwebappcluster.controller", 
"Controller for the cluster; if null a default will created (using 
controllerSpec)");
-
-    @SetFromFlag("controlledGroup")
-    public static BasicAttributeSensorAndConfigKey<Group> CONTROLLED_GROUP = 
new BasicAttributeSensorAndConfigKey<Group>(
-        Group.class, "controlleddynamicwebappcluster.controlledgroup", "The 
group of web servers that the controller should point at; if null, will use the 
CLUSTER");
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @SetFromFlag("controllerSpec")
-    public static BasicAttributeSensorAndConfigKey<EntitySpec<? extends 
LoadBalancer>> CONTROLLER_SPEC = new BasicAttributeSensorAndConfigKey(
-            EntitySpec.class, "controlleddynamicwebappcluster.controllerSpec", 
"Spec for creating the controller (if one not supplied explicitly); if null an 
NGINX instance will be created");
-
-    @SuppressWarnings({ "unchecked", "rawtypes", "deprecation" })
-    /** factory (or closure) to create the web server, given flags */
-    @SetFromFlag("factory")
-    public static BasicAttributeSensorAndConfigKey<ConfigurableEntityFactory<? 
extends WebAppService>> FACTORY = new BasicAttributeSensorAndConfigKey(
-            ConfigurableEntityFactory.class, DynamicCluster.FACTORY.getName(), 
"factory (or closure) to create the web server");
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    /** Spec for web server entiites to be created */
-    @SetFromFlag("memberSpec")
-    public static BasicAttributeSensorAndConfigKey<EntitySpec<? extends 
WebAppService>> MEMBER_SPEC = new BasicAttributeSensorAndConfigKey(
-            EntitySpec.class, DynamicCluster.MEMBER_SPEC.getName(), "Spec for 
web server entiites to be created");
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @SetFromFlag("webClusterSpec")
-    public static BasicAttributeSensorAndConfigKey<EntitySpec<? extends 
DynamicWebAppCluster>> WEB_CLUSTER_SPEC = new BasicAttributeSensorAndConfigKey(
-            EntitySpec.class, "controlleddynamicwebappcluster.webClusterSpec", 
"Spec for creating the cluster; if null a DynamicWebAppCluster will be 
created");
-
-    public static AttributeSensor<DynamicWebAppCluster> CLUSTER = new 
BasicAttributeSensor<DynamicWebAppCluster>(
-            DynamicWebAppCluster.class, 
"controlleddynamicwebappcluster.cluster", "Underlying web-app cluster");
-
-    public static final AttributeSensor<String> HOSTNAME = Attributes.HOSTNAME;
-
-    public static final AttributeSensor<Lifecycle> SERVICE_STATE_ACTUAL = 
Attributes.SERVICE_STATE_ACTUAL;
-
-    
-    public LoadBalancer getController();
-    
-    public ConfigurableEntityFactory<WebAppService> getFactory();
-    
-    public DynamicWebAppCluster getCluster();
-    
-    public Group getControlledGroup();
-}

Reply via email to