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/08/12 17:55:42 UTC

[24/35] incubator-brooklyn git commit: [BROOKLYN-162] package rename to org.apache.brooklyn: software/webapp

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
deleted file mode 100644
index b5af827..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
+++ /dev/null
@@ -1,327 +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 java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.enricher.Enrichers;
-import brooklyn.entity.Entity;
-import brooklyn.entity.Group;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigurableEntityFactory;
-import brooklyn.entity.basic.DynamicGroupImpl;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.EntityPredicates;
-import brooklyn.entity.basic.Lifecycle;
-import brooklyn.entity.basic.ServiceStateLogic;
-import brooklyn.entity.proxy.LoadBalancer;
-import brooklyn.entity.proxy.nginx.NginxController;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.trait.Startable;
-import brooklyn.entity.trait.StartableMethods;
-import brooklyn.entity.webapp.tomcat.TomcatServer;
-import brooklyn.event.SensorEvent;
-import brooklyn.event.SensorEventListener;
-import brooklyn.event.feed.ConfigToAttributes;
-import brooklyn.location.Location;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.collections.QuorumCheck.QuorumChecks;
-import brooklyn.util.exceptions.Exceptions;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl implements ControlledDynamicWebAppCluster {
-
-    public static final Logger log = LoggerFactory.getLogger(ControlledDynamicWebAppClusterImpl.class);
-
-    public ControlledDynamicWebAppClusterImpl() {
-        this(MutableMap.of(), null);
-    }
-    
-    public ControlledDynamicWebAppClusterImpl(Map<?,?> flags) {
-        this(flags, null);
-    }
-    
-    public ControlledDynamicWebAppClusterImpl(Entity parent) {
-        this(MutableMap.of(), parent);
-    }
-    
-    @Deprecated
-    public ControlledDynamicWebAppClusterImpl(Map<?,?> flags, Entity parent) {
-        super(flags, parent);
-    }
-
-    @Override
-    public void init() {
-        super.init();
-        
-        ConfigToAttributes.apply(this, FACTORY);
-        ConfigToAttributes.apply(this, MEMBER_SPEC);
-        ConfigToAttributes.apply(this, CONTROLLER);
-        ConfigToAttributes.apply(this, CONTROLLER_SPEC);
-        ConfigToAttributes.apply(this, WEB_CLUSTER_SPEC);
-        ConfigToAttributes.apply(this, CONTROLLED_GROUP);
-        
-        ConfigurableEntityFactory<? extends WebAppService> webServerFactory = getAttribute(FACTORY);
-        EntitySpec<? extends WebAppService> webServerSpec = getAttribute(MEMBER_SPEC);
-        if (webServerFactory == null && webServerSpec == null) {
-            log.debug("creating default web server spec for {}", this);
-            webServerSpec = EntitySpec.create(TomcatServer.class);
-            setAttribute(MEMBER_SPEC, webServerSpec);
-        }
-        
-        log.debug("creating cluster child for {}", this);
-        // Note relies on initial_size being inherited by DynamicWebAppCluster, because key id is identical
-        EntitySpec<? extends DynamicWebAppCluster> webClusterSpec = getAttribute(WEB_CLUSTER_SPEC);
-        Map<String,Object> webClusterFlags;
-        if (webServerSpec != null) {
-            webClusterFlags = MutableMap.<String,Object>of("memberSpec", webServerSpec);
-        } else {
-            webClusterFlags = MutableMap.<String,Object>of("factory", webServerFactory);
-        }
-        if (webClusterSpec == null) {
-            log.debug("creating default web cluster spec for {}", this);
-            webClusterSpec = EntitySpec.create(DynamicWebAppCluster.class);
-        }
-        boolean hasMemberSpec = webClusterSpec.getConfig().containsKey(DynamicWebAppCluster.MEMBER_SPEC) || webClusterSpec.getFlags().containsKey("memberSpec");
-        @SuppressWarnings("deprecation")
-        boolean hasMemberFactory = webClusterSpec.getConfig().containsKey(DynamicWebAppCluster.FACTORY) || webClusterSpec.getFlags().containsKey("factory");
-        if (!(hasMemberSpec || hasMemberFactory)) {
-            webClusterSpec.configure(webClusterFlags);
-        } else {
-            log.warn("In {}, not setting cluster's {} because already set on webClusterSpec", new Object[] {this, webClusterFlags.keySet()});
-        }
-        setAttribute(WEB_CLUSTER_SPEC, webClusterSpec);
-        
-        DynamicWebAppCluster cluster = addChild(webClusterSpec);
-        if (Entities.isManaged(this)) Entities.manage(cluster);
-        setAttribute(CLUSTER, cluster);
-        setEntityFilter(EntityPredicates.isMemberOf(cluster));
-        
-        LoadBalancer controller = getAttribute(CONTROLLER);
-        if (controller == null) {
-            EntitySpec<? extends LoadBalancer> controllerSpec = getAttribute(CONTROLLER_SPEC);
-            if (controllerSpec == null) {
-                log.debug("creating controller using default spec for {}", this);
-                controllerSpec = EntitySpec.create(NginxController.class);
-                setAttribute(CONTROLLER_SPEC, controllerSpec);
-            } else {
-                log.debug("creating controller using custom spec for {}", this);
-            }
-            controller = addChild(controllerSpec);
-            addEnricher(Enrichers.builder().propagating(LoadBalancer.PROXY_HTTP_PORT, LoadBalancer.PROXY_HTTPS_PORT).from(controller).build());
-            if (Entities.isManaged(this)) Entities.manage(controller);
-            setAttribute(CONTROLLER, controller);
-        }
-        
-        Group controlledGroup = getAttribute(CONTROLLED_GROUP);
-        if (controlledGroup == null) {
-            log.debug("using cluster as controlledGroup for {}", this);
-            controlledGroup = cluster;
-            setAttribute(CONTROLLED_GROUP, cluster);
-        } else {
-            log.debug("using custom controlledGroup {} for {}", controlledGroup, this);
-        }
-        
-        doBind();
-    }
-
-    @Override
-    protected void initEnrichers() {
-        if (config().getLocalRaw(UP_QUORUM_CHECK).isAbsent()) {
-            config().set(UP_QUORUM_CHECK, QuorumChecks.newInstance(2, 1.0, false));
-        }
-        super.initEnrichers();
-        ServiceStateLogic.newEnricherFromChildrenUp().checkChildrenOnly().requireUpChildren(getConfig(UP_QUORUM_CHECK)).addTo(this);
-    }
-    
-    @Override
-    public void rebind() {
-        super.rebind();
-        doBind();
-    }
-
-    protected void doBind() {
-        DynamicWebAppCluster cluster = getAttribute(CLUSTER);
-        if (cluster != null) {
-            subscribe(cluster, DynamicWebAppCluster.GROUP_MEMBERS, new SensorEventListener<Object>() {
-                @Override public void onEvent(SensorEvent<Object> event) {
-                    // TODO inefficient impl; also worth extracting this into a mixin of some sort.
-                    rescanEntities();
-                }});
-        }
-    }
-    
-    @Override
-    public LoadBalancer getController() {
-        return getAttribute(CONTROLLER);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public synchronized ConfigurableEntityFactory<WebAppService> getFactory() {
-        return (ConfigurableEntityFactory<WebAppService>) getAttribute(FACTORY);
-    }
-    
-    // TODO convert to an entity reference which is serializable
-    @Override
-    public synchronized DynamicWebAppCluster getCluster() {
-        return getAttribute(CLUSTER);
-    }
-    
-    @Override
-    public Group getControlledGroup() {
-        return getAttribute(CONTROLLED_GROUP);
-    }
-    
-    @Override
-    public void start(Collection<? extends Location> locations) {
-        ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);
-
-        try {
-            if (isLegacyConstruction()) {
-                init();
-            }
-
-            if (locations.isEmpty()) locations = getLocations();
-            addLocations(locations);
-
-            LoadBalancer loadBalancer = getController();
-            loadBalancer.bind(MutableMap.of("serverPool", getControlledGroup()));
-
-            List<Entity> childrenToStart = MutableList.<Entity>of(getCluster());
-            // Set controller as child of cluster, if it does not already have a parent
-            if (getController().getParent() == null) {
-                addChild(getController());
-            }
-
-            // And only start controller if we are parent. Favour locations defined on controller, if present
-            Task<List<Void>> startControllerTask = null;
-            if (this.equals(getController().getParent())) {
-                if (getController().getLocations().size() == 0) {
-                    childrenToStart.add(getController());
-                } else {
-                     startControllerTask = Entities.invokeEffectorList(this, MutableList.<Entity>of(getController()), Startable.START, ImmutableMap.of("locations", getController().getLocations()));
-                }
-            }
-
-            Entities.invokeEffectorList(this, childrenToStart, Startable.START, ImmutableMap.of("locations", locations)).get();
-            if (startControllerTask != null) {
-                startControllerTask.get();
-            }
-
-            // wait for everything to start, then update controller, to ensure it is up to date
-            // (will happen asynchronously as members come online, but we want to force it to happen)
-            getController().update();
-
-            ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
-        } catch (Exception e) {
-            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
-            throw Exceptions.propagate(e);
-        } finally {
-            connectSensors();
-        }
-    }
-
-    @Override
-    public void stop() {
-        ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPING);
-
-        try {
-            List<Startable> tostop = Lists.newArrayList();
-            if (this.equals(getController().getParent())) tostop.add(getController());
-            tostop.add(getCluster());
-
-            StartableMethods.stopSequentially(tostop);
-
-            clearLocations();
-
-            ServiceStateLogic.setExpectedState(this, Lifecycle.STOPPED);
-        } catch (Exception e) {
-            ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    @Override
-    public void restart() {
-        // TODO prod the entities themselves to restart, instead?
-        Collection<Location> locations = Lists.newArrayList(getLocations());
-
-        stop();
-        start(locations);
-    }
-    
-    void connectSensors() {
-        // FIXME no longer needed
-        addEnricher(Enrichers.builder()
-                .propagatingAllButUsualAnd(Attributes.MAIN_URI, ROOT_URL, GROUP_MEMBERS, GROUP_SIZE)
-                .from(getCluster())
-                .build());
-        addEnricher(Enrichers.builder()
-                // include hostname and address of controller (need both in case hostname only resolves to internal/private ip)
-                .propagating(LoadBalancer.HOSTNAME, Attributes.ADDRESS, Attributes.MAIN_URI, ROOT_URL)
-                .from(getController())
-                .build());
-    }
-
-    @Override
-    public Integer resize(Integer desiredSize) {
-        return getCluster().resize(desiredSize);
-    }
-
-    @Override
-    public String replaceMember(String memberId) {
-        return getCluster().replaceMember(memberId);
-    }
-
-    /**
-     * @return the current size of the group.
-     */
-    @Override
-    public Integer getCurrentSize() {
-        return getCluster().getCurrentSize();
-    }
-
-    @Override
-    public void deploy(String url, String targetName) {
-        DynamicWebAppClusterImpl.addToWarsByContext(this, url, targetName);
-        getCluster().deploy(url, targetName);
-    }
-
-    @Override
-    public void undeploy(String targetName) {
-        DynamicWebAppClusterImpl.removeFromWarsByContext(this, targetName);
-        getCluster().undeploy(targetName);
-    }
-
-    @Override
-    public void redeployAll() {
-        getCluster().redeployAll();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java
deleted file mode 100644
index c1b027b..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java
+++ /dev/null
@@ -1,69 +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.render.RendererHints;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
-import brooklyn.util.time.Duration;
-
-/**
- * DynamicWebAppClusters provide cluster-wide aggregates of entity attributes.  Currently totals and averages:
- * <ul>
- *   <li>Entity request counts</li>
- *   <li>Entity error counts</li>
- *   <li>Requests per second</li>
- *   <li>Entity processing time</li>
- * </ul>
- */
-@Catalog(name="Dynamic Web-app Cluster", description="A cluster of web-apps, which can be dynamically re-sized; this does not include a load-balancer")
-@ImplementedBy(DynamicWebAppClusterImpl.class)
-public interface DynamicWebAppCluster extends DynamicCluster, WebAppService, JavaWebAppService,
-        JavaWebAppService.CanDeployAndUndeploy, JavaWebAppService.CanRedeployAll {
-
-    public static final AttributeSensor<Double> REQUEST_COUNT_PER_NODE = new BasicAttributeSensor<Double>(
-            Double.class, "webapp.reqs.total.perNode", "Cluster entity request average");
-
-    public static final AttributeSensor<Integer> ERROR_COUNT_PER_NODE = new BasicAttributeSensor<Integer>(
-            Integer.class, "webapp.reqs.errors.perNode", "Cluster entity request error average");
-
-    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_LAST_PER_NODE = new BasicAttributeSensor<Double>(
-            Double.class, "webapp.reqs.perSec.last.perNode", "Reqs/sec (last datapoint) averaged over all nodes");
-
-    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE = new BasicAttributeSensor<Double>(
-            Double.class, "webapp.reqs.perSec.windowed.perNode", "Reqs/sec (over time window) averaged over all nodes");
-
-    public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME_PER_NODE = ApplyDisplayHints.TOTAL_PROCESSING_TIME_PER_NODE;
-
-    public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_IN_WINDOW_PER_NODE = new BasicAttributeSensor<Double>(
-            Double.class, "webapp.reqs.processingTime.fraction.windowed.perNode", "Fraction of time spent processing " +
-            "reported by webserver (percentage, over time window) averaged over all nodes");
-
-    class ApplyDisplayHints {
-        public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME_PER_NODE = new BasicAttributeSensor<Integer>(
-            Integer.class, "webapp.reqs.processingTime.perNode", "Total processing time per node (millis)");
-        static {
-            RendererHints.register(TOTAL_PROCESSING_TIME_PER_NODE, RendererHints.displayValue(Duration.millisToStringRounded()));
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
deleted file mode 100644
index e364618..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ /dev/null
@@ -1,263 +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 static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.management.Task;
-import org.apache.brooklyn.management.TaskAdaptable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.enricher.Enrichers;
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.entity.effector.Effectors;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.entity.group.DynamicClusterImpl;
-import brooklyn.event.AttributeSensor;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.collections.MutableSet;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-/**
- * DynamicWebAppClusters provide cluster-wide aggregates of entity attributes.  Currently totals and averages:
- * <ul>
- *   <li>Entity request counts</li>
- *   <li>Entity error counts</li>
- *   <li>Requests per second</li>
- *   <li>Entity processing time</li>
- * </ul>
- */
-public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements DynamicWebAppCluster {
-
-    private static final Logger log = LoggerFactory.getLogger(DynamicWebAppClusterImpl.class);
-    private static final FilenameToWebContextMapper FILENAME_TO_WEB_CONTEXT_MAPPER = new FilenameToWebContextMapper();
-    
-    /**
-     * Instantiate a new DynamicWebAppCluster.  Parameters as per {@link DynamicCluster#DynamicCluster()}
-     */
-    public DynamicWebAppClusterImpl() {
-        super();
-    }
-    
-    @Override
-    public void init() {
-        super.init();
-        // Enricher attribute setup.  A way of automatically discovering these (but avoiding
-        // averaging things like HTTP port and response codes) would be neat.
-        List<? extends List<? extends AttributeSensor<? extends Number>>> summingEnricherSetup = ImmutableList.of(
-                ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT),
-                ImmutableList.of(ERROR_COUNT, ERROR_COUNT),
-                ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST),
-                ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW),
-                ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME),
-                ImmutableList.of(PROCESSING_TIME_FRACTION_IN_WINDOW, PROCESSING_TIME_FRACTION_IN_WINDOW)
-        );
-        
-        List<? extends List<? extends AttributeSensor<? extends Number>>> averagingEnricherSetup = ImmutableList.of(
-                ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT_PER_NODE),
-                ImmutableList.of(ERROR_COUNT, ERROR_COUNT_PER_NODE),
-                ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST_PER_NODE),
-                ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE),
-                ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME_PER_NODE),
-                ImmutableList.of(PROCESSING_TIME_FRACTION_IN_WINDOW, PROCESSING_TIME_FRACTION_IN_WINDOW_PER_NODE)
-        );
-        
-        for (List<? extends AttributeSensor<? extends Number>> es : summingEnricherSetup) {
-            AttributeSensor<? extends Number> t = es.get(0);
-            AttributeSensor<? extends Number> total = es.get(1);
-            addEnricher(Enrichers.builder()
-                    .aggregating(t)
-                    .publishing(total)
-                    .fromMembers()
-                    .computingSum()
-                    .build());
-        }
-        
-        for (List<? extends AttributeSensor<? extends Number>> es : averagingEnricherSetup) {
-            @SuppressWarnings("unchecked")
-            AttributeSensor<Number> t = (AttributeSensor<Number>) es.get(0);
-            @SuppressWarnings("unchecked")
-            AttributeSensor<Double> average = (AttributeSensor<Double>) es.get(1);
-            addEnricher(Enrichers.builder()
-                    .aggregating(t)
-                    .publishing(average)
-                    .fromMembers()
-                    .computingAverage()
-                    .defaultValueForUnreportedSensors(0)
-                    .build());
-        }
-    }
-    
-    // TODO this will probably be useful elsewhere ... but where to put it?
-    // TODO add support for this in DependentConfiguration (see TODO there)
-    /** Waits for the given target to report service up, then runs the given task
-     * (often an invocation on that entity), with the given name.
-     * If the target goes away, this task marks itself inessential
-     * before failing so as not to cause a parent task to fail. */
-    static <T> Task<T> whenServiceUp(final Entity target, final TaskAdaptable<T> task, String name) {
-        return Tasks.<T>builder().name(name).dynamic(true).body(new Callable<T>() {
-            @Override
-            public T call() {
-                try {
-                    while (true) {
-                        if (!Entities.isManaged(target)) {
-                            Tasks.markInessential();
-                            throw new IllegalStateException("Target "+target+" is no longer managed");
-                        }
-                        if (Boolean.TRUE.equals(target.getAttribute(Attributes.SERVICE_UP))) {
-                            Tasks.resetBlockingDetails();
-                            TaskTags.markInessential(task);
-                            DynamicTasks.queue(task);
-                            try {
-                                return task.asTask().getUnchecked();
-                            } catch (Exception e) {
-                                if (Entities.isManaged(target)) {
-                                    throw Exceptions.propagate(e);
-                                } else {
-                                    Tasks.markInessential();
-                                    throw new IllegalStateException("Target "+target+" is no longer managed", e);
-                                }
-                            }
-                        } else {
-                            Tasks.setBlockingDetails("Waiting on "+target+" to be ready");
-                        }
-                        // TODO replace with subscription?
-                        Time.sleep(Duration.ONE_SECOND);
-                    }
-                } finally {
-                    Tasks.resetBlockingDetails();
-                }
-            }
-        }).build();        
-    }
-
-    @Override
-    public void deploy(String url, String targetName) {
-        checkNotNull(url, "url");
-        checkNotNull(targetName, "targetName");
-        targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName);
-
-        // set it up so future nodes get the right wars
-        addToWarsByContext(this, url, targetName);
-        
-        log.debug("Deploying "+targetName+"->"+url+" across cluster "+this+"; WARs now "+getConfig(WARS_BY_CONTEXT));
-
-        Iterable<CanDeployAndUndeploy> targets = Iterables.filter(getChildren(), CanDeployAndUndeploy.class);
-        TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name("Deploy "+targetName+" to cluster (size "+Iterables.size(targets)+")");
-        for (Entity target: targets) {
-            tb.add(whenServiceUp(target, Effectors.invocation(target, DEPLOY, MutableMap.of("url", url, "targetName", targetName)),
-                "Deploy "+targetName+" to "+target+" when ready"));
-        }
-        DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked();
-
-        // Update attribute
-        // TODO support for atomic sensor update (should be part of standard tooling; NB there is some work towards this, according to @aledsage)
-        Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
-        deployedWars.add(targetName);
-        setAttribute(DEPLOYED_WARS, deployedWars);
-    }
-    
-    @Override
-    public void undeploy(String targetName) {
-        checkNotNull(targetName, "targetName");
-        targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName);
-        
-        // set it up so future nodes get the right wars
-        if (!removeFromWarsByContext(this, targetName)) {
-            DynamicTasks.submit(Tasks.warning("Context "+targetName+" not known at "+this+"; attempting to undeploy regardless", null), this);
-        }
-        
-        log.debug("Undeploying "+targetName+" across cluster "+this+"; WARs now "+getConfig(WARS_BY_CONTEXT));
-
-        Iterable<CanDeployAndUndeploy> targets = Iterables.filter(getChildren(), CanDeployAndUndeploy.class);
-        TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name("Undeploy "+targetName+" across cluster (size "+Iterables.size(targets)+")");
-        for (Entity target: targets) {
-            tb.add(whenServiceUp(target, Effectors.invocation(target, UNDEPLOY, MutableMap.of("targetName", targetName)),
-                "Undeploy "+targetName+" at "+target+" when ready"));
-        }
-        DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked();
-
-        // Update attribute
-        Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
-        deployedWars.remove( FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName) );
-        setAttribute(DEPLOYED_WARS, deployedWars);
-    }
-
-    static void addToWarsByContext(Entity entity, String url, String targetName) {
-        targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName);
-        // TODO a better way to do atomic updates, see comment above
-        synchronized (entity) {
-            Map<String,String> newWarsMap = MutableMap.copyOf(entity.getConfig(WARS_BY_CONTEXT));
-            newWarsMap.put(targetName, url);
-            ((EntityInternal)entity).setConfig(WARS_BY_CONTEXT, newWarsMap);
-        }
-    }
-
-    static boolean removeFromWarsByContext(Entity entity, String targetName) {
-        targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName);
-        // TODO a better way to do atomic updates, see comment above
-        synchronized (entity) {
-            Map<String,String> newWarsMap = MutableMap.copyOf(entity.getConfig(WARS_BY_CONTEXT));
-            String url = newWarsMap.remove(targetName);
-            if (url==null) {
-                return false;
-            }
-            ((EntityInternal)entity).setConfig(WARS_BY_CONTEXT, newWarsMap);
-            return true;
-        }
-    }
-    
-    @Override
-    public void redeployAll() {
-        Map<String, String> wars = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
-        String redeployPrefix = "Redeploy all WARs (count "+wars.size()+")";
-
-        log.debug("Redeplying all WARs across cluster "+this+": "+getConfig(WARS_BY_CONTEXT));
-        
-        Iterable<CanDeployAndUndeploy> targetEntities = Iterables.filter(getChildren(), CanDeployAndUndeploy.class);
-        TaskBuilder<Void> tb = Tasks.<Void>builder().parallel(true).name(redeployPrefix+" across cluster (size "+Iterables.size(targetEntities)+")");
-        for (Entity targetEntity: targetEntities) {
-            TaskBuilder<Void> redeployAllToTarget = Tasks.<Void>builder().name(redeployPrefix+" at "+targetEntity+" (after ready check)");
-            for (String warContextPath: wars.keySet()) {
-                redeployAllToTarget.add(Effectors.invocation(targetEntity, DEPLOY, MutableMap.of("url", wars.get(warContextPath), "targetName", warContextPath)));
-            }
-            tb.add(whenServiceUp(targetEntity, redeployAllToTarget.build(), redeployPrefix+" at "+targetEntity+" when ready"));
-        }
-        DynamicTasks.queueIfPossible(tb.build()).orSubmitAsync(this).asTask().getUnchecked();
-    }  
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabric.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabric.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabric.java
deleted file mode 100644
index ac60f86..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabric.java
+++ /dev/null
@@ -1,48 +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 brooklyn.entity.group.DynamicFabric;
-import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
-
-/**
- * DynamicWebAppFabric provide a fabric of clusters, aggregating the entity attributes.  Currently totals and averages:
- * <ul>
- *   <li>Entity request counts</li>
- *   <li>Entity error counts</li>
- *   <li>Requests per second</li>
- *   <li>Entity processing time</li>
- * </ul>
- */
-@ImplementedBy(DynamicWebAppFabricImpl.class)
-public interface DynamicWebAppFabric extends DynamicFabric, WebAppService {
-
-    public static final AttributeSensor<Double> REQUEST_COUNT_PER_NODE = new BasicAttributeSensor<Double>(
-            Double.class, "webapp.reqs.total.perNode", "Fabric entity request average");
-
-    public static final AttributeSensor<Integer> ERROR_COUNT_PER_NODE = new BasicAttributeSensor<Integer>(
-            Integer.class, "webapp.reqs.errors.perNode", "Fabric entity request error average");
-
-    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_LAST_PER_NODE = DynamicWebAppCluster.REQUESTS_PER_SECOND_LAST_PER_NODE;
-    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE = DynamicWebAppCluster.REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE;
-    public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME_PER_NODE = DynamicWebAppCluster.TOTAL_PROCESSING_TIME_PER_NODE;
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
deleted file mode 100644
index 3a8d0be..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
+++ /dev/null
@@ -1,83 +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 java.util.List;
-
-import javax.annotation.Nullable;
-
-import brooklyn.enricher.Enrichers;
-import brooklyn.entity.group.DynamicFabricImpl;
-import brooklyn.event.AttributeSensor;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-
-public class DynamicWebAppFabricImpl extends DynamicFabricImpl implements DynamicWebAppFabric {
-
-    @Override
-    public void onManagementBecomingMaster() {
-        // Enricher attribute setup.  A way of automatically discovering these (but avoiding
-        // averaging things like HTTP port and response codes) would be neat.
-        List<? extends List<? extends AttributeSensor<? extends Number>>> summingEnricherSetup = ImmutableList.of(
-                ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT),
-                ImmutableList.of(ERROR_COUNT, ERROR_COUNT),
-                ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST),
-                ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW),
-                ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME)
-        );
-        
-        List<? extends List<? extends AttributeSensor<? extends Number>>> averagingEnricherSetup = ImmutableList.of(
-                ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT_PER_NODE),
-                ImmutableList.of(ERROR_COUNT, ERROR_COUNT_PER_NODE),
-                ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST_PER_NODE),
-                ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE),
-                ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME_PER_NODE)
-        );
-        
-        for (List<? extends AttributeSensor<? extends Number>> es : summingEnricherSetup) {
-            AttributeSensor<? extends Number> t = es.get(0);
-            AttributeSensor<? extends Number> total = es.get(1);
-            addEnricher(Enrichers.builder()
-                    .aggregating(t)
-                    .publishing(total)
-                    .fromMembers()
-                    .computingSum()
-                    .build());
-        }
-        
-        for (List<? extends AttributeSensor<? extends Number>> es : averagingEnricherSetup) {
-            @SuppressWarnings("unchecked")
-            AttributeSensor<Number> t = (AttributeSensor<Number>) es.get(0);
-            @SuppressWarnings("unchecked")
-            AttributeSensor<Double> average = (AttributeSensor<Double>) es.get(1);
-            
-            // TODO This needs to respond to changes in FABRIC_SIZE as well, to recalculate
-            addEnricher(Enrichers.builder()
-                    .transforming(t)
-                    .publishing(average)
-                    .computing(new Function<Number, Double>() {
-                            @Override public Double apply(@Nullable Number input) {
-                                Integer size = getAttribute(DynamicWebAppFabric.FABRIC_SIZE);
-                                return (size != null && input != null) ? (input.doubleValue() / size) : null;
-                            }})
-                    .build());
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java
deleted file mode 100644
index 89a1311..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.webapp;
-
-import java.util.Map;
-
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.AbstractConfigurableEntityFactory;
-import brooklyn.entity.basic.ConfigurableEntityFactory;
-import brooklyn.entity.basic.EntityFactoryForLocation;
-import brooklyn.entity.proxying.EntitySpec;
-import brooklyn.entity.trait.Startable;
-import brooklyn.location.Location;
-import brooklyn.location.MachineProvisioningLocation;
-
-public interface ElasticJavaWebAppService extends JavaWebAppService, Startable {
-
-    public interface ElasticJavaWebAppServiceAwareLocation {
-        ConfigurableEntityFactory<ElasticJavaWebAppService> newWebClusterFactory();
-    }
-
-    /** @deprecated since 0.7.0 use {@link EntitySpec} */
-    @Deprecated
-    public static class Factory extends AbstractConfigurableEntityFactory<ElasticJavaWebAppService>
-    implements EntityFactoryForLocation<ElasticJavaWebAppService> {
-
-        private static final long serialVersionUID = 6654647949712073832L;
-
-        public ElasticJavaWebAppService newEntity2(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
-            return new ControlledDynamicWebAppClusterImpl(flags, parent);
-        }
-
-        public ConfigurableEntityFactory<ElasticJavaWebAppService> newFactoryForLocation(Location l) {
-            if (l instanceof ElasticJavaWebAppServiceAwareLocation) {
-                return ((ElasticJavaWebAppServiceAwareLocation)l).newWebClusterFactory().configure(config);
-            }
-            //optional, fail fast if location not supported
-            if (!(l instanceof MachineProvisioningLocation))
-                throw new UnsupportedOperationException("cannot create this entity in location "+l);
-            return this;
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/FilenameToWebContextMapper.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/FilenameToWebContextMapper.java b/software/webapp/src/main/java/brooklyn/entity/webapp/FilenameToWebContextMapper.java
deleted file mode 100644
index 9bc99b8..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/FilenameToWebContextMapper.java
+++ /dev/null
@@ -1,92 +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 java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/** utilities for translating consistently between a filename (http://acme.org/foo.war) and a web context path (/foo) */ 
-public class FilenameToWebContextMapper {
-
-    public static final Logger log = LoggerFactory.getLogger(FilenameToWebContextMapper.class);
-    
-    public String findArchiveNameFromUrl(String url, boolean verbose) {
-        String name = url.substring(url.lastIndexOf('/') + 1);
-        if (name.indexOf("?")>0) {
-            Pattern p = Pattern.compile("[A-Za-z0-9_\\-]+\\..(ar|AR)($|(?=[^A-Za-z0-9_\\-]))");
-            Matcher wars = p.matcher(name);
-            if (wars.find()) {
-                // take first such string
-                name = wars.group();
-                if (wars.find()) {
-                    if (verbose) log.warn("Not clear which archive to deploy for "+url+": using "+name);
-                } else {
-                    if (verbose) log.info("Inferred archive to deploy for "+url+": using "+name);
-                }
-            } else {
-                if (verbose) log.warn("Not clear which archive to deploy for "+url+": using "+name);
-            }
-        }
-        return name;
-    }
-
-    public String convertDeploymentTargetNameToFilename(String targetName) {
-        String result = targetName;
-        if (result.isEmpty()) return "";
-        if (targetName.startsWith("/")) {
-            // treat input as a context
-            result = result.substring(1);
-            if (result.length()==0) result="ROOT";
-            result += ".war";
-        } else {
-            // treat input as a file, unless it has no dots in it
-            if (result.indexOf('.')==-1) result += ".war";
-        }
-        return result;
-    }
-    
-    public String convertDeploymentTargetNameToContext(String targetName) {
-        String result = targetName;
-        if (result.isEmpty()) return "";
-        if (targetName.startsWith("/")) {
-            // treat input as a context - noop
-        } else {
-            // make it look like a context
-            result = "/"+result;
-            if (result.indexOf('.')==-1) {
-                // no dot means no more processing
-            } else {
-                // look at extension
-                String extension = result.substring(result.lastIndexOf('.')+1).toUpperCase();
-                if (extension.matches(".AR")) {
-                    // looks like it was a WAR/EAR/etc
-                    result = result.substring(0, result.length()-4);
-                    if (result.equalsIgnoreCase("/ROOT")) result = "/"; 
-                } else {
-                    // input didn't look like a war filename, no more processing
-                }
-            }
-        }
-        return result;        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/HttpsSslConfig.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/HttpsSslConfig.java b/software/webapp/src/main/java/brooklyn/entity/webapp/HttpsSslConfig.java
deleted file mode 100644
index cca69d0..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/HttpsSslConfig.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.webapp;
-
-import java.util.Map;
-
-import brooklyn.util.guava.Maybe;
-
-public class HttpsSslConfig {
-
-    private String keystoreUrl;
-    private String keystorePassword;
-    private String keyAlias;
-    
-    public HttpsSslConfig() {
-    }
-    
-    public HttpsSslConfig keystoreUrl(String val) {
-        keystoreUrl = val; return this;
-    }
-    
-    public HttpsSslConfig keystorePassword(String val) {
-        keystorePassword = val; return this;
-    }
-    
-    public HttpsSslConfig keyAlias(String val) {
-        keyAlias = val; return this;
-    }
-    
-    public String getKeystoreUrl() {
-        return keystoreUrl;
-    }
-    
-    public String getKeystorePassword() {
-        return keystorePassword;
-    }
-    
-    public String getKeyAlias() {
-        return keyAlias;
-    }
-
-    // method naming convention allows it to be used by TypeCoercions
-    public static HttpsSslConfig fromMap(Map<String,String> map) {
-        HttpsSslConfig result = new HttpsSslConfig();
-        result.keystoreUrl = first(map, "keystoreUrl", "url").orNull();
-        result.keystorePassword = first(map, "keystorePassword", "password").orNull();
-        result.keyAlias = first(map, "keyAlias", "alias", "key").orNull();
-        return result;
-    }
-
-    private static Maybe<String> first(Map<String,String> map, String ...keys) {
-        for (String key: keys) {
-            if (map.containsKey(key))
-                return Maybe.of(map.get(key));
-        }
-        return Maybe.<String>absent();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppDriver.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppDriver.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppDriver.java
deleted file mode 100644
index f355555..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppDriver.java
+++ /dev/null
@@ -1,54 +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 java.io.File;
-import java.util.Set;
-
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-
-public interface JavaWebAppDriver extends JavaSoftwareProcessDriver {
-
-    Set<String> getEnabledProtocols();
-
-    Integer getHttpPort();
-
-    Integer getHttpsPort();
-
-    HttpsSslConfig getHttpsSslConfig();
-    
-    void deploy(File file);
-
-    void deploy(File f, String targetName);
-
-    /**
-     * Deploys a URL as a webapp at the appserver.
-     * <p>
-     * See {@link JavaWebAppSoftwareProcess#deploy(String, String)} for details of how input filenames are handled.
-     *
-     * @return A token which can be used as an argument to undeploy.
-     *     Typically the web context with leading slash where the app can be reached (just "/" for ROOT)
-     */
-    String deploy(String url, String targetName);
-    
-    void undeploy(String targetName);
-    
-    FilenameToWebContextMapper getFilenameContextMapper();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
deleted file mode 100644
index 52b090d..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppService.java
+++ /dev/null
@@ -1,109 +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 java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.Entity;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.MethodEffector;
-import brooklyn.entity.java.UsesJava;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
-
-public interface JavaWebAppService extends WebAppService, UsesJava {
-
-    @SetFromFlag("war")
-    public static final ConfigKey<String> ROOT_WAR = new BasicConfigKey<String>(
-            String.class, "wars.root", "WAR file to deploy as the ROOT, as URL (supporting file: and classpath: prefixes)");
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @SetFromFlag("wars")
-    public static final ConfigKey<List<String>> NAMED_WARS = new BasicConfigKey(
-            List.class, "wars.named", "Archive files to deploy, as URL strings (supporting file: and classpath: prefixes); context (path in user-facing URL) will be inferred by name");
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @SetFromFlag("warsByContext")
-    public static final ConfigKey<Map<String,String>> WARS_BY_CONTEXT = new BasicConfigKey(
-            Map.class, "wars.by.context", "Map of context keys (path in user-facing URL, typically without slashes) to archives (e.g. WARs by URL) to deploy, supporting file: and classpath: prefixes)");
-    
-    /** Optional marker interface for entities which support 'deploy' and 'undeploy' */
-    public interface CanDeployAndUndeploy extends Entity {
-
-        @SuppressWarnings({ "unchecked", "rawtypes" })
-        public static final AttributeSensor<Set<String>> DEPLOYED_WARS = new BasicAttributeSensor(
-                Set.class, "webapp.deployedWars", "Names of archives/contexts that are currently deployed");
-
-        public static final MethodEffector<Void> DEPLOY = new MethodEffector<Void>(CanDeployAndUndeploy.class, "deploy");
-        public static final MethodEffector<Void> UNDEPLOY = new MethodEffector<Void>(CanDeployAndUndeploy.class, "undeploy");
-
-        /**
-         * Deploys the given artifact, from a source URL, to a given deployment filename/context.
-         * There is some variance in expected filename/context at various servers,
-         * so the following conventions are followed:
-         * <p>
-         *   either ROOT.WAR or /       denotes root context
-         * <p>
-         *   anything of form  FOO.?AR  (ending .?AR) is copied with that name (unless copying not necessary)
-         *                              and is expected to be served from /FOO
-         * <p>
-         *   anything of form  /FOO     (with leading slash) is expected to be served from /FOO
-         *                              (and is copied as FOO.WAR)
-         * <p>
-         *   anything of form  FOO      (without a dot) is expected to be served from /FOO
-         *                              (and is copied as FOO.WAR)
-         * <p>
-         *   otherwise <i>please note</i> behaviour may vary on different appservers;
-         *   e.g. FOO.FOO would probably be ignored on appservers which expect a file copied across (usually),
-         *   but served as /FOO.FOO on systems that take a deployment context.
-         * <p>
-         * See {@link FileNameToContextMappingTest} for definitive examples!
-         *
-         * @param url  where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)...
-         * @param targetName  where to tell the server to serve the WAR, see above
-         */
-        @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
-        public void deploy(
-                @EffectorParam(name="url", description="URL of WAR file") String url, 
-                @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName);
-
-        /** 
-         * For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy,
-         * e.g. the transformed name using 
-         */
-        @Effector(description="Undeploys the given context/artifact")
-        public void undeploy(
-                @EffectorParam(name="targetName") String targetName);
-    }
-
-    /** Optional marker interface for entities which support 'redeployAll' */
-    public interface CanRedeployAll {
-        public static final MethodEffector<Void> REDEPLOY_ALL = new MethodEffector<Void>(CanRedeployAll.class, "redeployAll");
-        
-        @Effector(description="Redeploys all web apps known here across the cluster (e.g. if it gets into an inconsistent state)")
-        public void redeployAll();
-    }
-        
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java
deleted file mode 100644
index bbeead2..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcess.java
+++ /dev/null
@@ -1,34 +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 brooklyn.entity.basic.SoftwareProcess;
-
-public interface JavaWebAppSoftwareProcess extends SoftwareProcess, JavaWebAppService, JavaWebAppService.CanDeployAndUndeploy {
-    
-    // exist on the interface for freemarker to pick it up
-    
-    public boolean isHttpEnabled();
-    public boolean isHttpsEnabled();
-    public Integer getHttpPort();
-    public Integer getHttpsPort();
-    public String getHttpsSslKeyAlias();
-    public String getHttpsSslKeystorePassword();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
deleted file mode 100644
index 209d3fe..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
+++ /dev/null
@@ -1,206 +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 static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.Entity;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.java.JavaAppUtils;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.Sets;
-
-public abstract class JavaWebAppSoftwareProcessImpl extends SoftwareProcessImpl implements JavaWebAppService, JavaWebAppSoftwareProcess {
-
-    private static final Logger LOG = LoggerFactory.getLogger(JavaWebAppSoftwareProcessImpl.class);
-
-    public JavaWebAppSoftwareProcessImpl(){
-        super();
-    }
-
-    @SuppressWarnings("rawtypes")
-    public JavaWebAppSoftwareProcessImpl(Entity parent){
-        this(new LinkedHashMap(),parent);
-    }
-
-    @SuppressWarnings("rawtypes")
-    public JavaWebAppSoftwareProcessImpl(Map flags){
-        this(flags, null);
-    }
-
-    @SuppressWarnings("rawtypes")
-    public JavaWebAppSoftwareProcessImpl(Map flags, Entity parent) {
-        super(flags, parent);
-    }
-
-    @Override
-    public void init() {
-        super.init();
-        
-        WebAppServiceMethods.connectWebAppServerPolicies(this);
-        JavaAppUtils.connectJavaAppServerPolicies(this);
-    }
-    
-    //just provide better typing
-    public JavaWebAppDriver getDriver() {
-        return (JavaWebAppDriver) super.getDriver();
-    }
-
-    // TODO thread-safety issues: if multiple concurrent calls, may break (e.g. deployment_wars being reset)
-    public void deployInitialWars() {
-        if (getAttribute(DEPLOYED_WARS) == null) setAttribute(DEPLOYED_WARS, Sets.<String>newLinkedHashSet());
-        
-        String rootWar = getConfig(ROOT_WAR);
-        if (rootWar!=null) deploy(rootWar, "ROOT.war");
-
-        List<String> namedWars = getConfig(NAMED_WARS, Collections.<String>emptyList());
-        for(String war: namedWars){
-            deploy(war, getDriver().getFilenameContextMapper().findArchiveNameFromUrl(war, true));
-        }
-        
-        Map<String,String> warsByContext = getConfig(WARS_BY_CONTEXT);
-        if (warsByContext!=null) {
-            for (String context: warsByContext.keySet()) {
-                deploy(warsByContext.get(context), context);
-            }
-        }
-    }
-
-    /**
-     * Deploys the given artifact, from a source URL, to a given deployment filename/context.
-     * There is some variance in expected filename/context at various servers,
-     * so the following conventions are followed:
-     * <p>
-     *   either ROOT.WAR or /       denotes root context
-     * <p>
-     *   anything of form  FOO.?AR  (ending .?AR) is copied with that name (unless copying not necessary)
-     *                              and is expected to be served from /FOO
-     * <p>
-     *   anything of form  /FOO     (with leading slash) is expected to be served from /FOO
-     *                              (and is copied as FOO.WAR)
-     * <p>
-     *   anything of form  FOO      (without a dot) is expected to be served from /FOO
-     *                              (and is copied as FOO.WAR)
-     * <p>                            
-     *   otherwise <i>please note</i> behaviour may vary on different appservers;
-     *   e.g. FOO.FOO would probably be ignored on appservers which expect a file copied across (usually),
-     *   but served as /FOO.FOO on systems that take a deployment context.
-     * <p>
-     * See {@link FileNameToContextMappingTest} for definitive examples!
-     * 
-     * @param url  where to get the war, as a URL, either classpath://xxx or file:///home/xxx or http(s)...
-     * @param targetName  where to tell the server to serve the WAR, see above
-     */
-    @Effector(description="Deploys the given artifact, from a source URL, to a given deployment filename/context")
-    public void deploy(
-            @EffectorParam(name="url", description="URL of WAR file") String url, 
-            @EffectorParam(name="targetName", description="context path where WAR should be deployed (/ for ROOT)") String targetName) {
-        try {
-            checkNotNull(url, "url");
-            checkNotNull(targetName, "targetName");
-            JavaWebAppDriver driver = getDriver();
-            String deployedName = driver.deploy(url, targetName);
-            
-            // Update attribute
-            Set<String> deployedWars = getAttribute(DEPLOYED_WARS);
-            if (deployedWars == null) {
-                deployedWars = Sets.newLinkedHashSet();
-            }
-            deployedWars.add(deployedName);
-            setAttribute(DEPLOYED_WARS, deployedWars);
-        } catch (RuntimeException e) {
-            // Log and propagate, so that log says which entity had problems...
-            LOG.warn("Error deploying '"+url+"' to "+targetName+" on "+toString()+"; rethrowing...", e);
-            throw Throwables.propagate(e);
-        }
-    }
-
-    /** For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy */
-    @Override
-    @Effector(description="Undeploys the given context/artifact")
-    public void undeploy(
-            @EffectorParam(name="targetName") String targetName) {
-        try {
-            JavaWebAppDriver driver = getDriver();
-            driver.undeploy(targetName);
-            
-            // Update attribute
-            Set<String> deployedWars = getAttribute(DEPLOYED_WARS);
-            if (deployedWars == null) {
-                deployedWars = Sets.newLinkedHashSet();
-            }
-            deployedWars.remove( driver.getFilenameContextMapper().convertDeploymentTargetNameToContext(targetName) );
-            setAttribute(DEPLOYED_WARS, deployedWars);
-        } catch (RuntimeException e) {
-            // Log and propagate, so that log says which entity had problems...
-            LOG.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", e);
-            throw Throwables.propagate(e);
-        }
-    }
-    
-    @Override
-    protected void postStop() {
-        super.postStop();
-        // zero our workrate derived workrates.
-        // TODO might not be enough, as policy may still be executing and have a record of historic vals; should remove policies
-        // (also not sure we want this; implies more generally a responsibility for sensors to announce things when disconnected,
-        // vs them just showing the last known value...)
-        setAttribute(REQUESTS_PER_SECOND_LAST, 0D);
-        setAttribute(REQUESTS_PER_SECOND_IN_WINDOW, 0D);
-    }
-
-    public boolean isHttpEnabled() {
-        return WebAppServiceMethods.isProtocolEnabled(this, "HTTP");
-    }
-
-    public boolean isHttpsEnabled() {
-        return WebAppServiceMethods.isProtocolEnabled(this, "HTTPS");
-    }
-
-    public Integer getHttpPort() {
-        return getAttribute(HTTP_PORT);
-    }
-
-    public Integer getHttpsPort() {
-        return getAttribute(HTTPS_PORT);
-    }
-
-    public String getHttpsSslKeyAlias() {
-        HttpsSslConfig config = getAttribute(HTTPS_SSL_CONFIG);
-        return (config == null) ? null : config.getKeyAlias();
-    }
-
-    public String getHttpsSslKeystorePassword() {
-        HttpsSslConfig config = getAttribute(HTTPS_SSL_CONFIG);
-        return (config == null) ? "" : config.getKeystorePassword();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSshDriver.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSshDriver.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSshDriver.java
deleted file mode 100644
index cd32b01..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSshDriver.java
+++ /dev/null
@@ -1,201 +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 static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
-import java.net.URI;
-import java.util.Set;
-
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.text.Strings;
-
-import com.google.common.collect.ImmutableList;
-
-public abstract class JavaWebAppSshDriver extends JavaSoftwareProcessSshDriver implements JavaWebAppDriver {
-
-    public JavaWebAppSshDriver(JavaWebAppSoftwareProcessImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    public JavaWebAppSoftwareProcessImpl getEntity() {
-        return (JavaWebAppSoftwareProcessImpl) super.getEntity();
-    }
-
-    protected boolean isProtocolEnabled(String protocol) {
-        Set<String> protocols = getEnabledProtocols();
-        for (String contender : protocols) {
-            if (protocol.equalsIgnoreCase(contender)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public Set<String> getEnabledProtocols() {
-        return entity.getAttribute(JavaWebAppSoftwareProcess.ENABLED_PROTOCOLS);
-    }
-    
-    @Override
-    public Integer getHttpPort() {
-        return entity.getAttribute(Attributes.HTTP_PORT);
-    }
-
-    @Override
-    public Integer getHttpsPort() {
-        return entity.getAttribute(Attributes.HTTPS_PORT);
-    }
-
-    @Override
-    public HttpsSslConfig getHttpsSslConfig() {
-        return entity.getAttribute(WebAppServiceConstants.HTTPS_SSL_CONFIG);
-    }
-
-    protected String getSslKeystoreUrl() {
-        HttpsSslConfig ssl = getHttpsSslConfig();
-        return (ssl == null) ? null : ssl.getKeystoreUrl();
-    }
-    
-    protected String getSslKeystorePassword() {
-        HttpsSslConfig ssl = getHttpsSslConfig();
-        return (ssl == null) ? null : ssl.getKeystorePassword();
-    }
-    
-    protected String getSslKeyAlias() {
-        HttpsSslConfig ssl = getHttpsSslConfig();
-        return (ssl == null) ? null : ssl.getKeyAlias();
-    }
-
-    protected String inferRootUrl() {
-        if (isProtocolEnabled("https")) {
-            Integer port = getHttpsPort();
-            checkNotNull(port, "HTTPS_PORT sensors not set; is an acceptable port available?");
-            return String.format("https://%s:%s/", getSubnetHostname(), port);
-        } else if (isProtocolEnabled("http")) {
-            Integer port = getHttpPort();
-            checkNotNull(port, "HTTP_PORT sensors not set; is an acceptable port available?");
-            return String.format("http://%s:%s/", getSubnetHostname(), port);
-        } else {
-            throw new IllegalStateException("HTTP and HTTPS protocols not enabled for "+entity+"; enabled protocols are "+getEnabledProtocols());
-        }
-    }
-    
-    @Override
-    public void postLaunch() {
-        String rootUrl = inferRootUrl();
-        entity.setAttribute(Attributes.MAIN_URI, URI.create(rootUrl));
-        entity.setAttribute(WebAppService.ROOT_URL, rootUrl);
-    }
-
-    /** 
-     * if files should be placed on the server for deployment,
-     * override this to be the sub-directory of the runDir where they should be stored
-     * (or override getDeployDir() if they should be copied somewhere else,
-     * and set this null);
-     * if files are not copied to the server, but injected (e.g. JMX or uploaded)
-     * then override {@link #deploy(String, String)} as appropriate,
-     * using getContextFromDeploymentTargetName(targetName)
-     * and override this to return null
-     */
-    protected abstract String getDeploySubdir();
-    
-    protected String getDeployDir() {
-        if (getDeploySubdir()==null)
-            throw new IllegalStateException("no deployment directory available for "+this);
-        return getRunDir() + "/" + getDeploySubdir();
-    }
-
-    @Override
-    public void deploy(File file) {
-        deploy(file, null);
-    }
-
-    @Override
-    public void deploy(File f, String targetName) {
-        if (targetName == null) {
-            targetName = f.getName();
-        }
-        deploy(f.toURI().toASCIIString(), targetName);
-    }
-
-    /**
-     * Deploys a URL as a webapp at the appserver.
-     *
-     * Returns a token which can be used as an argument to undeploy,
-     * typically the web context with leading slash where the app can be reached (just "/" for ROOT)
-     *
-     * @see JavaWebAppSoftwareProcess#deploy(String, String) for details of how input filenames are handled
-     */
-    @Override
-    public String deploy(final String url, final String targetName) {
-        final String canonicalTargetName = getFilenameContextMapper().convertDeploymentTargetNameToFilename(targetName);
-        final String dest = getDeployDir() + "/" + canonicalTargetName;
-        //write to a .tmp so autodeploy is not triggered during upload
-        final String tmpDest = dest + "." + Strings.makeRandomId(8) + ".tmp";
-        final String msg = String.format("deploying %s to %s:%s", new Object[]{url, getHostname(), dest});
-        log.info(entity + " " + msg);
-        Tasks.setBlockingDetails(msg);
-        try {
-            final String copyTaskMsg = String.format("copying %s to %s:%s", new Object[]{url, getHostname(), tmpDest});
-            DynamicTasks.queue(copyTaskMsg, new Runnable() {
-                @Override
-                public void run() {
-                    int result = copyResource(url, tmpDest);
-                    if (result != 0) {
-                        throw new IllegalStateException("Invalud result " + result + " while " + copyTaskMsg);
-                    }
-                }
-            });
-
-            // create a backup
-            DynamicTasks.queue(SshTasks.newSshExecTaskFactory(getMachine(), String.format("mv -f %s %s.bak", dest, dest))
-                    .allowingNonZeroExitCode());
-
-            //rename temporary upload file to .war to be picked up for deployment
-            DynamicTasks.queue(SshTasks.newSshExecTaskFactory(getMachine(), String.format("mv -f %s %s", tmpDest, dest))
-                    .requiringExitCodeZero());
-            log.debug("{} deployed {} to {}:{}", new Object[]{entity, url, getHostname(), dest});
-
-            DynamicTasks.waitForLast();
-        } finally {
-            Tasks.resetBlockingDetails();
-        }
-        return getFilenameContextMapper().convertDeploymentTargetNameToContext(canonicalTargetName);
-    }
-    
-    @Override
-    public void undeploy(String targetName) {
-        String dest = getDeployDir() + "/" + getFilenameContextMapper().convertDeploymentTargetNameToFilename(targetName);
-        log.info("{} undeploying {}:{}", new Object[]{entity, getHostname(), dest});
-        int result = getMachine().execCommands("removing war on undeploy", ImmutableList.of(String.format("rm -f %s", dest)));
-        log.debug("{} undeployed {}:{}: result {}", new Object[]{entity, getHostname(), dest, result});
-    }
-    
-    @Override
-    public FilenameToWebContextMapper getFilenameContextMapper() {
-        return new FilenameToWebContextMapper();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppService.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppService.java
deleted file mode 100644
index 8aeaec6..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppService.java
+++ /dev/null
@@ -1,24 +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 brooklyn.entity.Entity;
-
-public interface WebAppService extends WebAppServiceConstants, Entity {
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java
deleted file mode 100644
index 68ba9ae..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java
+++ /dev/null
@@ -1,61 +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 java.util.Set;
-
-import com.google.common.collect.ImmutableSet;
-
-import brooklyn.config.render.RendererHints;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
-
-public interface WebAppServiceConstants extends WebAppServiceMetrics {
-
-    @SetFromFlag("httpPort")
-    public static final PortAttributeSensorAndConfigKey HTTP_PORT = Attributes.HTTP_PORT;
-
-    @SetFromFlag("httpsPort")
-    public static final PortAttributeSensorAndConfigKey HTTPS_PORT = Attributes.HTTPS_PORT;
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @SetFromFlag("enabledProtocols")
-    public static final BasicAttributeSensorAndConfigKey<Set<String>> ENABLED_PROTOCOLS = new BasicAttributeSensorAndConfigKey(
-            Set.class, "webapp.enabledProtocols", "List of enabled protocols (e.g. http, https)", ImmutableSet.of("http"));
-
-    @SetFromFlag("httpsSsl")
-    public static final BasicAttributeSensorAndConfigKey<HttpsSslConfig> HTTPS_SSL_CONFIG = new BasicAttributeSensorAndConfigKey<HttpsSslConfig>(
-            HttpsSslConfig.class, "webapp.https.ssl", "SSL Configuration for HTTPS", null);
-    
-    public static final AttributeSensor<String> ROOT_URL = RootUrl.ROOT_URL;
-
-}
-
-// this class is added because the ROOT_URL relies on a static initialization which unfortunately can't be added to an interface.
-class RootUrl {
-    public static final AttributeSensor<String> ROOT_URL = Sensors.newStringSensor("webapp.url", "URL");
-
-    static {
-        RendererHints.register(ROOT_URL, RendererHints.namedActionWithUrl());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/77dff880/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java
deleted file mode 100644
index c6fbe29..0000000
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMethods.java
+++ /dev/null
@@ -1,89 +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 static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import brooklyn.enricher.RollingTimeWindowMeanEnricher;
-import brooklyn.enricher.TimeFractionDeltaEnricher;
-import brooklyn.enricher.TimeWeightedDeltaEnricher;
-import brooklyn.entity.Entity;
-import brooklyn.entity.basic.EntityLocal;
-import brooklyn.location.access.BrooklynAccessUtils;
-import brooklyn.util.time.Duration;
-
-import com.google.common.net.HostAndPort;
-
-public class WebAppServiceMethods implements WebAppServiceConstants {
-
-    public static final Duration DEFAULT_WINDOW_DURATION = Duration.TEN_SECONDS;
-
-    public static void connectWebAppServerPolicies(EntityLocal entity) {
-        connectWebAppServerPolicies(entity, DEFAULT_WINDOW_DURATION);
-    }
-
-    public static void connectWebAppServerPolicies(EntityLocal entity, Duration windowPeriod) {
-        entity.addEnricher(TimeWeightedDeltaEnricher.<Integer>getPerSecondDeltaEnricher(entity, REQUEST_COUNT, REQUESTS_PER_SECOND_LAST));
-
-        if (windowPeriod!=null) {
-            entity.addEnricher(new RollingTimeWindowMeanEnricher<Double>(entity, REQUESTS_PER_SECOND_LAST,
-                    REQUESTS_PER_SECOND_IN_WINDOW, windowPeriod));
-        }
-
-        entity.addEnricher(new TimeFractionDeltaEnricher<Integer>(entity, TOTAL_PROCESSING_TIME, PROCESSING_TIME_FRACTION_LAST, TimeUnit.MILLISECONDS));
-
-        if (windowPeriod!=null) {
-            entity.addEnricher(new RollingTimeWindowMeanEnricher<Double>(entity, PROCESSING_TIME_FRACTION_LAST,
-                    PROCESSING_TIME_FRACTION_IN_WINDOW, windowPeriod));
-        }
-
-    }
-
-    public static Set<String> getEnabledProtocols(Entity entity) {
-        return entity.getAttribute(WebAppService.ENABLED_PROTOCOLS);
-    }
-
-    public static boolean isProtocolEnabled(Entity entity, String protocol) {
-        for (String contender : getEnabledProtocols(entity)) {
-            if (protocol.equalsIgnoreCase(contender)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static String inferBrooklynAccessibleRootUrl(Entity entity) {
-        if (isProtocolEnabled(entity, "https")) {
-            Integer rawPort = entity.getAttribute(HTTPS_PORT);
-            checkNotNull(rawPort, "HTTPS_PORT sensors not set for %s; is an acceptable port available?", entity);
-            HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, rawPort);
-            return String.format("https://%s:%s/", hp.getHostText(), hp.getPort());
-        } else if (isProtocolEnabled(entity, "http")) {
-            Integer rawPort = entity.getAttribute(HTTP_PORT);
-            checkNotNull(rawPort, "HTTP_PORT sensors not set for %s; is an acceptable port available?", entity);
-            HostAndPort hp = BrooklynAccessUtils.getBrooklynAccessibleAddress(entity, rawPort);
-            return String.format("http://%s:%s/", hp.getHostText(), hp.getPort());
-        } else {
-            throw new IllegalStateException("HTTP and HTTPS protocols not enabled for "+entity+"; enabled protocols are "+getEnabledProtocols(entity));
-        }
-    }
-}