You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/07/29 21:31:57 UTC

[02/31] git commit: move deploy and redeploy bodies to DynamicWebAppCluster, with ControlledDWAC calling to that, and with new interfaces for the shared items (deploy effectors etc) so that ControlledDWAC is not a JavaWebAppSoftwareProcess

move deploy and redeploy bodies to DynamicWebAppCluster, with ControlledDWAC calling to that,
and with new interfaces for the shared items (deploy effectors etc) so that ControlledDWAC is not a JavaWebAppSoftwareProcess


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

Branch: refs/heads/master
Commit: 8a3188d3bbed97b905857c5187f722d67f0f178a
Parents: dbf26e3
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jul 18 15:58:16 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Jul 29 10:41:10 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/basic/AbstractEntity.java   |   2 +-
 .../entity/basic/AbstractGroupImpl.java         |   2 +-
 .../brooklyn/entity/basic/DynamicGroupImpl.java |   2 +-
 .../ControlledDynamicWebAppClusterImpl.java     | 113 +++----------------
 .../entity/webapp/DynamicWebAppCluster.java     |   2 +-
 .../entity/webapp/DynamicWebAppClusterImpl.java | 110 ++++++++++++++++++
 .../entity/webapp/DynamicWebAppFabricImpl.java  |   2 +
 .../entity/webapp/ElasticJavaWebAppService.java |   7 +-
 .../webapp/JavaWebAppSoftwareProcessImpl.java   |   3 +
 .../entity/webapp/WebAppServiceConstants.java   |  42 +------
 .../entity/webapp/WebAppServiceMetrics.java     |  73 ++++++++++++
 .../entity/webapp/jboss/JBoss6Server.java       |   3 +-
 .../entity/webapp/jboss/JBoss7Server.java       |   3 +-
 13 files changed, 215 insertions(+), 149 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index 0f291bf..438f407 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -243,7 +243,7 @@ public abstract class AbstractEntity implements EntityLocal, EntityInternal {
      * @deprecated since 0.5; instead use no-arg constructor with EntityManager().createEntity(spec)
      */
     @Deprecated
-    public AbstractEntity(Map flags, Entity parent) {
+    public AbstractEntity(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
         if (flags==null) {
             throw new IllegalArgumentException("Flags passed to entity "+this+" must not be null (try no-arguments or empty map)");
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java b/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java
index 8542e3a..4aeb931 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractGroupImpl.java
@@ -61,7 +61,7 @@ public abstract class AbstractGroupImpl extends AbstractEntity implements Abstra
     }
 
     @Deprecated
-    public AbstractGroupImpl(Map flags, Entity parent) {
+    public AbstractGroupImpl(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
         super(flags, parent);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
index 67a5d26..11544eb 100644
--- a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
+++ b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
@@ -50,7 +50,7 @@ public class DynamicGroupImpl extends AbstractGroupImpl implements DynamicGroup
     public DynamicGroupImpl() { }
 
     @Deprecated
-    public DynamicGroupImpl(Map flags, Entity parent) {
+    public DynamicGroupImpl(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
         super(flags, parent);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/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
index ac70f3a..3f9c026 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ControlledDynamicWebAppClusterImpl.java
@@ -18,13 +18,10 @@
  */
 package brooklyn.entity.webapp;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
 import org.slf4j.Logger;
@@ -32,8 +29,6 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Entity;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigurableEntityFactory;
 import brooklyn.entity.basic.DynamicGroupImpl;
@@ -52,25 +47,20 @@ import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.location.Location;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
 public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl implements ControlledDynamicWebAppCluster {
 
     public static final Logger log = LoggerFactory.getLogger(ControlledDynamicWebAppClusterImpl.class);
-    private FilenameToWebContextMapper filenameToWebContextMapper = new FilenameToWebContextMapper();
 
     public ControlledDynamicWebAppClusterImpl() {
         this(MutableMap.of(), null);
     }
     
-    public ControlledDynamicWebAppClusterImpl(Map flags) {
+    public ControlledDynamicWebAppClusterImpl(Map<?,?> flags) {
         this(flags, null);
     }
     
@@ -78,7 +68,8 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
         this(MutableMap.of(), parent);
     }
     
-    public ControlledDynamicWebAppClusterImpl(Map flags, Entity parent) {
+    @Deprecated
+    public ControlledDynamicWebAppClusterImpl(Map<?,?> flags, Entity parent) {
         super(flags, parent);
         setAttribute(SERVICE_UP, false);
     }
@@ -115,6 +106,7 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
             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);
@@ -168,6 +160,7 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
         return getAttribute(CONTROLLER);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public synchronized ConfigurableEntityFactory<WebAppService> getFactory() {
         return (ConfigurableEntityFactory<WebAppService>) getAttribute(FACTORY);
@@ -316,99 +309,19 @@ public class ControlledDynamicWebAppClusterImpl extends DynamicGroupImpl impleme
         return getCluster().getCurrentSize();
     }
 
-    private Entity findChildOrNull(Predicate<? super Entity> predicate) {
-        for (Entity contender : getChildren()) {
-            if (predicate.apply(contender)) return contender;
-        }
-        return null;
-    }
-    /**
-     * Deploys the given artifact, from a source URL, to all members of the cluster
-     * 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");
-            
-            // set it up so future nodes get the right wars
-            synchronized (this) {
-                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
-                newWarsMap.put(targetName, url);
-                setConfig(WARS_BY_CONTEXT, newWarsMap);
-            }
-            
-            // now actually deploy
-            List <Entity> clusterMembers = MutableList.copyOf(
-                Iterables.filter(getCluster().getChildren(), Predicates.and(
-                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
-                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
-            )));
-            Entities.invokeEffectorListWithArgs(this, clusterMembers, DEPLOY, url, targetName).get();            
-            
-            // Update attribute
-            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
-            deployedWars.add(targetName);
-            setAttribute(DEPLOYED_WARS, deployedWars);
-            
-        } catch (Exception e) {
-            // Log and propagate, so that log says which entity had problems...
-            log.warn("Error deploying '"+url+"' to "+targetName+" on "+toString()+"; rethrowing...", e);
-            throw Exceptions.propagate(e);
-        }
+    @Override
+    public void deploy(String url, String targetName) {
+        getCluster().deploy(url, targetName);
     }
-    
-    /*
-     * TODO
-     * 
-     * - deploy to all, not just running, with a wait-for-running-or-bail-out logic
-     * - thread pool
-     * - redeploy to all (simple way, with notes)
-     * - check-in, then move down with echo here
-     */
-    
-    /** For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy */
-    @Effector(description="Undeploys the given context/artifact")
-    public void undeploy(@EffectorParam(name="targetName") String targetName) {
-    	
-        try {
-            checkNotNull(targetName, "targetName");
-            
-            // set it up so future nodes get the right wars
-            synchronized (this) {
-                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
-                newWarsMap.remove(targetName);
-                setConfig(WARS_BY_CONTEXT, newWarsMap);
-            }
 
-            List <Entity> clusterMembers = MutableList.copyOf(
-                Iterables.filter(getCluster().getChildren(), Predicates.and(
-                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
-                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
-            )));
-            Entities.invokeEffectorListWithArgs(this, clusterMembers, UNDEPLOY, targetName).get(); 
-            
-            // Update attribute
-            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
-            deployedWars.remove( filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName) );
-            setAttribute(DEPLOYED_WARS, deployedWars);
-            
-        } catch (Exception e) {
-            // Log and propagate, so that log says which entity had problems...
-            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", e);
-            throw Exceptions.propagate(e);
-        }
+    @Override
+    public void undeploy(String targetName) {
+        getCluster().undeploy(targetName);
     }
 
     @Override
     public void redeployAll() {
-        throw new UnsupportedOperationException("TODO - support redeploying all WARs (if any of the deploy/undeploys fail)");
-    }  
+        getCluster().redeployAll();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/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
index e561c56..04ec69e 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppCluster.java
@@ -35,7 +35,7 @@ import brooklyn.util.time.Duration;
  * </ul>
  */
 @ImplementedBy(DynamicWebAppClusterImpl.class)
-public interface DynamicWebAppCluster extends DynamicCluster, WebAppService {
+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");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/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
index ec942ee..36a62de 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -18,17 +18,35 @@
  */
 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import brooklyn.enricher.Enrichers;
 import brooklyn.entity.Entity;
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityPredicates;
+import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.group.DynamicClusterImpl;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.exceptions.Exceptions;
 
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
 
 /**
  * DynamicWebAppClusters provide cluster-wide aggregates of entity attributes.  Currently totals and averages:
@@ -41,6 +59,9 @@ import com.google.common.collect.ImmutableList;
  */
 public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements DynamicWebAppCluster {
 
+    private static final Logger log = LoggerFactory.getLogger(DynamicWebAppClusterImpl.class);
+    private FilenameToWebContextMapper filenameToWebContextMapper = new FilenameToWebContextMapper();
+    
     /**
      * Instantiate a new DynamicWebAppCluster.  Parameters as per {@link DynamicCluster#DynamicCluster()}
      */
@@ -129,4 +150,93 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
         }
         return up;
     }
+    
+    /**
+     * Deploys the given artifact, from a source URL, to all members of the cluster
+     * 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");
+            
+            // set it up so future nodes get the right wars
+            synchronized (this) {
+                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
+                newWarsMap.put(targetName, url);
+                setConfig(WARS_BY_CONTEXT, newWarsMap);
+            }
+            
+            // now actually deploy
+            List <Entity> clusterMembers = MutableList.copyOf(
+                Iterables.filter(getChildren(), Predicates.and(
+                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
+                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
+            )));
+            Entities.invokeEffectorListWithArgs(this, clusterMembers, DEPLOY, url, targetName).get();            
+            
+            // Update attribute
+            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
+            deployedWars.add(targetName);
+            setAttribute(DEPLOYED_WARS, deployedWars);
+            
+        } catch (Exception e) {
+            // Log and propagate, so that log says which entity had problems...
+            log.warn("Error deploying '"+url+"' to "+targetName+" on "+toString()+"; rethrowing...", e);
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    /*
+     * TODO
+     * 
+     * - deploy to all, not just running, with a wait-for-running-or-bail-out logic
+     * - thread pool
+     * - redeploy to all (simple way, with notes)
+     */
+    
+    /** For the DEPLOYED_WARS to be updated, the input must match the result of the call to deploy */
+    @Effector(description="Undeploys the given context/artifact")
+    public void undeploy(@EffectorParam(name="targetName") String targetName) {
+        
+        try {
+            checkNotNull(targetName, "targetName");
+            
+            // set it up so future nodes get the right wars
+            synchronized (this) {
+                Map<String,String> newWarsMap = MutableMap.copyOf(getConfig(WARS_BY_CONTEXT));
+                newWarsMap.remove(targetName);
+                setConfig(WARS_BY_CONTEXT, newWarsMap);
+            }
+
+            List <Entity> clusterMembers = MutableList.copyOf(
+                Iterables.filter(getChildren(), Predicates.and(
+                     Predicates.instanceOf(JavaWebAppSoftwareProcess.class),
+                     EntityPredicates.attributeEqualTo(SERVICE_STATE, Lifecycle.RUNNING)
+            )));
+            Entities.invokeEffectorListWithArgs(this, clusterMembers, UNDEPLOY, targetName).get(); 
+            
+            // Update attribute
+            Set<String> deployedWars = MutableSet.copyOf(getAttribute(DEPLOYED_WARS));
+            deployedWars.remove( filenameToWebContextMapper.convertDeploymentTargetNameToContext(targetName) );
+            setAttribute(DEPLOYED_WARS, deployedWars);
+            
+        } catch (Exception e) {
+            // Log and propagate, so that log says which entity had problems...
+            log.warn("Error undeploying '"+targetName+"' on "+toString()+"; rethrowing...", e);
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    @Override
+    public void redeployAll() {
+        throw new UnsupportedOperationException("TODO - support redeploying all WARs (if any of the deploy/undeploys fail)");
+    }  
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/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
index 3af6817..4023748 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppFabricImpl.java
@@ -63,7 +63,9 @@ public class DynamicWebAppFabricImpl extends DynamicFabricImpl implements Dynami
         }
         
         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

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/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
index 26e9e96..89a1311 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/ElasticJavaWebAppService.java
@@ -24,6 +24,7 @@ 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;
@@ -34,10 +35,14 @@ public interface ElasticJavaWebAppService extends JavaWebAppService, Startable {
         ConfigurableEntityFactory<ElasticJavaWebAppService> newWebClusterFactory();
     }
 
+    /** @deprecated since 0.7.0 use {@link EntitySpec} */
+    @Deprecated
     public static class Factory extends AbstractConfigurableEntityFactory<ElasticJavaWebAppService>
     implements EntityFactoryForLocation<ElasticJavaWebAppService> {
 
-        public ElasticJavaWebAppService newEntity2(Map flags, Entity parent) {
+        private static final long serialVersionUID = 6654647949712073832L;
+
+        public ElasticJavaWebAppService newEntity2(@SuppressWarnings("rawtypes") Map flags, Entity parent) {
             return new ControlledDynamicWebAppClusterImpl(flags, parent);
         }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/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
index c67ad2b..2b6ab29 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
@@ -48,14 +48,17 @@ public abstract class JavaWebAppSoftwareProcessImpl extends SoftwareProcessImpl
         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);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/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
index b76ea2e..4a9903e 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceConstants.java
@@ -23,17 +23,14 @@ import java.util.Set;
 import brooklyn.config.render.RendererHints;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
 import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.text.ByteSizeStrings;
-import brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;
 
-public interface WebAppServiceConstants {
+public interface WebAppServiceConstants extends WebAppServiceMetrics {
 
     @SetFromFlag("httpPort")
     public static final PortAttributeSensorAndConfigKey HTTP_PORT = Attributes.HTTP_PORT;
@@ -50,50 +47,15 @@ public interface WebAppServiceConstants {
     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<Integer> REQUEST_COUNT =
-            Sensors.newIntegerSensor("webapp.reqs.total", "Request count");
-    public static final brooklyn.event.basic.BasicAttributeSensor<Integer> ERROR_COUNT =
-            new brooklyn.event.basic.BasicAttributeSensor<Integer>(Integer.class, "webapp.reqs.errors", "Request errors");
-    public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME = Sensors.newIntegerSensor(
-            "webapp.reqs.processingTime.total", "Total processing time, reported by webserver (millis)");
-    public static final AttributeSensor<Integer> MAX_PROCESSING_TIME =
-            Sensors.newIntegerSensor("webapp.reqs.processingTime.max", "Max processing time for any single request, reported by webserver (millis)");
-
-    /** the fraction of time represented by the most recent delta to TOTAL_PROCESSING_TIME, ie 0.4 if 800 millis were accumulated in last 2s;
-     * easily configured with {@link WebAppServiceMethods#connectWebAppServerPolicies(brooklyn.entity.basic.EntityLocal, brooklyn.util.time.Duration)} */
-    public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_LAST =
-            Sensors.newDoubleSensor("webapp.reqs.processingTime.fraction.last", "Fraction of time spent processing, reported by webserver (percentage, last datapoint)");
-    public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_IN_WINDOW =
-            Sensors.newDoubleSensor("webapp.reqs.processingTime.fraction.windowed", "Fraction of time spent processing, reported by webserver (percentage, over time window)");
-
-    public static final AttributeSensor<Long> BYTES_RECEIVED =
-            new BasicAttributeSensor<Long>(Long.class, "webapp.reqs.bytes.received", "Total bytes received by the webserver");
-    public static final AttributeSensor<Long> BYTES_SENT =
-            new BasicAttributeSensor<Long>(Long.class, "webapp.reqs.bytes.sent", "Total bytes sent by the webserver");
-
-    /** req/second computed from the delta of the last request count and an associated timestamp */
-    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_LAST =
-            Sensors.newDoubleSensor("webapp.reqs.perSec.last", "Reqs/sec (last datapoint)");
-
-    /** rolled-up req/second for a window, 
-     * easily configured with {@link WebAppServiceMethods#connectWebAppServerPolicies(brooklyn.entity.basic.EntityLocal, brooklyn.util.time.Duration)} */
-    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW =
-            Sensors.newDoubleSensor("webapp.reqs.perSec.windowed", "Reqs/sec (over time window)");
-
     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.
+// 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, new RendererHints.NamedActionWithUrl("Open"));
-        RendererHints.register(WebAppServiceConstants.TOTAL_PROCESSING_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
-        RendererHints.register(WebAppServiceConstants.MAX_PROCESSING_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
-        RendererHints.register(WebAppServiceConstants.BYTES_RECEIVED, RendererHints.displayValue(ByteSizeStrings.metric()));
-        RendererHints.register(WebAppServiceConstants.BYTES_SENT, RendererHints.displayValue(ByteSizeStrings.metric()));
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMetrics.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMetrics.java b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMetrics.java
new file mode 100644
index 0000000..710e344
--- /dev/null
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/WebAppServiceMetrics.java
@@ -0,0 +1,73 @@
+/*
+ * 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.config.render.RendererHints;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.BasicAttributeSensor;
+import brooklyn.event.basic.Sensors;
+import brooklyn.util.text.ByteSizeStrings;
+import brooklyn.util.time.Duration;
+
+public interface WebAppServiceMetrics {
+    
+    public static final AttributeSensor<Integer> REQUEST_COUNT = Initializer.REQUEST_COUNT;
+        
+    public static final brooklyn.event.basic.BasicAttributeSensor<Integer> ERROR_COUNT =
+            new brooklyn.event.basic.BasicAttributeSensor<Integer>(Integer.class, "webapp.reqs.errors", "Request errors");
+    public static final AttributeSensor<Integer> TOTAL_PROCESSING_TIME = Sensors.newIntegerSensor(
+            "webapp.reqs.processingTime.total", "Total processing time, reported by webserver (millis)");
+    public static final AttributeSensor<Integer> MAX_PROCESSING_TIME =
+            Sensors.newIntegerSensor("webapp.reqs.processingTime.max", "Max processing time for any single request, reported by webserver (millis)");
+
+    /** the fraction of time represented by the most recent delta to TOTAL_PROCESSING_TIME, ie 0.4 if 800 millis were accumulated in last 2s;
+     * easily configured with {@link WebAppServiceMethods#connectWebAppServerPolicies(brooklyn.entity.basic.EntityLocal, brooklyn.util.time.Duration)} */
+    public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_LAST =
+            Sensors.newDoubleSensor("webapp.reqs.processingTime.fraction.last", "Fraction of time spent processing, reported by webserver (percentage, last datapoint)");
+    public static final AttributeSensor<Double> PROCESSING_TIME_FRACTION_IN_WINDOW =
+            Sensors.newDoubleSensor("webapp.reqs.processingTime.fraction.windowed", "Fraction of time spent processing, reported by webserver (percentage, over time window)");
+
+    public static final AttributeSensor<Long> BYTES_RECEIVED =
+            new BasicAttributeSensor<Long>(Long.class, "webapp.reqs.bytes.received", "Total bytes received by the webserver");
+    public static final AttributeSensor<Long> BYTES_SENT =
+            new BasicAttributeSensor<Long>(Long.class, "webapp.reqs.bytes.sent", "Total bytes sent by the webserver");
+
+    /** req/second computed from the delta of the last request count and an associated timestamp */
+    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_LAST =
+            Sensors.newDoubleSensor("webapp.reqs.perSec.last", "Reqs/sec (last datapoint)");
+
+    /** rolled-up req/second for a window, 
+     * easily configured with {@link WebAppServiceMethods#connectWebAppServerPolicies(brooklyn.entity.basic.EntityLocal, brooklyn.util.time.Duration)} */
+    public static final AttributeSensor<Double> REQUESTS_PER_SECOND_IN_WINDOW =
+            Sensors.newDoubleSensor("webapp.reqs.perSec.windowed", "Reqs/sec (over time window)");
+
+    // this class is added because the above need static initialization which unfortunately can't be added to an interface.
+    static class Initializer {
+        public static final AttributeSensor<Integer> REQUEST_COUNT =
+            Sensors.newIntegerSensor("webapp.reqs.total", "Request count");
+
+        static {
+            RendererHints.register(WebAppServiceConstants.TOTAL_PROCESSING_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
+            RendererHints.register(WebAppServiceConstants.MAX_PROCESSING_TIME, RendererHints.displayValue(Duration.millisToStringRounded()));
+            RendererHints.register(WebAppServiceConstants.BYTES_RECEIVED, RendererHints.displayValue(ByteSizeStrings.metric()));
+            RendererHints.register(WebAppServiceConstants.BYTES_SENT, RendererHints.displayValue(ByteSizeStrings.metric()));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java
index d3a6041..f2cc135 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss6Server.java
@@ -24,14 +24,13 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.java.UsesJmx;
 import brooklyn.entity.proxying.ImplementedBy;
-import brooklyn.entity.webapp.JavaWebAppService;
 import brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.util.flags.SetFromFlag;
 
 @Catalog(name="JBoss Application Server 6", description="AS6: an open source Java application server from JBoss", iconUrl="classpath:///jboss-logo.png")
 @ImplementedBy(JBoss6ServerImpl.class)
-public interface JBoss6Server extends JavaWebAppSoftwareProcess, JavaWebAppService, UsesJmx {
+public interface JBoss6Server extends JavaWebAppSoftwareProcess, UsesJmx {
 
     // TODO Instead of using portIncrement, would prefer to use http_port as "8080+" etc.
     // On localhost, if an existing jboss6 is running and consuming the required port(s), 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8a3188d3/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java
index 620294c..70b5131 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/jboss/JBoss7Server.java
@@ -24,7 +24,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.proxying.ImplementedBy;
 import brooklyn.entity.trait.HasShortName;
-import brooklyn.entity.webapp.JavaWebAppService;
 import brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
@@ -36,7 +35,7 @@ import brooklyn.util.javalang.JavaClassNames;
 
 @Catalog(name="JBoss Application Server 7", description="AS7: an open source Java application server from JBoss", iconUrl="classpath:///jboss-logo.png")
 @ImplementedBy(JBoss7ServerImpl.class)
-public interface JBoss7Server extends JavaWebAppSoftwareProcess, JavaWebAppService, HasShortName {
+public interface JBoss7Server extends JavaWebAppSoftwareProcess, HasShortName {
 
     @SetFromFlag("version")
     ConfigKey<String> SUGGESTED_VERSION =