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/10/25 23:48:23 UTC

[1/7] incubator-brooklyn git commit: Convert groovy tests to java

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 9a80ebe3b -> 9a441be8f


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/CarrenzaLocationLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/CarrenzaLocationLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/CarrenzaLocationLiveTest.java
new file mode 100644
index 0000000..235c725
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/CarrenzaLocationLiveTest.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds.provider;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsSshMachineLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Tests vcloud, with Carrenza. Uses the cloudsoft test account (hard-coding its NAT Mapping, 
+ * and one of its private vApp templates). Note that the template is for a Windows 2008 
+ * machine with winsshd installed.
+ * 
+ * TODO Will only work with >= jclouds 1.5, due to jclouds issues 994 and 995. Therefore it 
+ * will not work in brooklyn 0.4.0-M2 etc.
+ */
+class CarrenzaLocationLiveTest {
+    private static final Logger LOG = LoggerFactory.getLogger(CarrenzaLocationLiveTest.class);
+    
+    private static final String PROVIDER = "vcloud";
+    private static final String ENDPOINT = "https://myvdc.carrenza.net/api";
+    private static final String LOCATION_ID = "jclouds:"+PROVIDER+":"+ENDPOINT;
+    private static final String WINDOWS_IMAGE_ID = "https://myvdc.carrenza.net/api/v1.0/vAppTemplate/vappTemplate-2bd5b0ff-ecd9-405e-8306-2f4f6c092a1b";
+    
+    private BrooklynProperties brooklynProperties;
+    private LocalManagementContext managementContext;
+    private JcloudsLocation loc;
+    private Collection<SshMachineLocation> machines = new ArrayList<>();
+    
+    // TODO Has not been tested since updating ot remove use of deleted LocationRegistry!
+    @BeforeMethod(groups = "Live")
+    public void setUp() {
+        System.out.println("classpath="+System.getProperty("java.class.path"));
+        
+        brooklynProperties = BrooklynProperties.Factory.newDefault();
+        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".image-description-regex");
+        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".image-name-regex");
+        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".image-id");
+        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".inboundPorts");
+        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".hardware-id");
+
+        // Also removes scriptHeader (e.g. if doing `. ~/.bashrc` and `. ~/.profile`, then that can cause "stdin: is not a tty")
+        brooklynProperties.remove("brooklyn.ssh.config.scriptHeader");
+        
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".jclouds.endpoint", ENDPOINT);
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".imageId", WINDOWS_IMAGE_ID);
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".noDefaultSshKeys", true);
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".userName", "Administrator");
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".dontCreateUser", true);
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".overrideLoginUser", "Administrator");
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".waitForSshable", false);
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".runAsRoot", false);
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".inboundPorts", ImmutableList.of(22, 3389));
+        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".natMapping", ImmutableMap.of("192.168.0.100", "195.3.186.200", "192.168.0.101", "195.3.186.42"));
+
+        managementContext = new LocalManagementContext(brooklynProperties);
+        loc = (JcloudsLocation) managementContext.getLocationRegistry().resolve(LOCATION_ID);
+    }
+    
+    @AfterMethod(groups = "Live")
+    public void tearDown() throws Exception {
+        List<Exception> exceptions = new ArrayList<>();
+        for (SshMachineLocation machine : machines) {
+            try {
+                loc.release(machine);
+            } catch (Exception e) {
+                LOG.warn("Error releasing machine $it; continuing...", e);
+                exceptions.add(e);
+            }
+        }
+        if (!exceptions.isEmpty()) {
+            throw exceptions.get(0);
+        }
+        machines.clear();
+    }
+    
+    // FIXME Disabled because of jclouds issues #994 and #995 (fixed in jclouds 1.5, so not in brooklyn 0.4.0-M2 etc)
+    // Note the careful settings in setUp (e.g. so don't try to install ssh-keys etc
+    // Also, the windows image used has winsshd installed
+    @Test(enabled=false, groups = "Live")
+    public void testProvisionWindowsVm() throws NoMachinesAvailableException {
+        JcloudsSshMachineLocation machine = (JcloudsSshMachineLocation) obtainMachine(MutableMap.of(
+                "imageId", WINDOWS_IMAGE_ID));
+        
+        LOG.info("Provisioned Windows VM {}; checking if has password", machine);
+        String password = machine.waitForPassword();
+        assertNotNull(password);
+        
+        LOG.info("Checking can ssh to windows machine {} using password {}", machine, password);
+        assertEquals(machine.execCommands(MutableMap.of("password", password), "check-reachable", ImmutableList.of("hostname")), 0);
+    }
+    
+    // Use this utility method to ensure machines are released on tearDown
+    protected SshMachineLocation obtainMachine(Map<?, ?> flags) throws NoMachinesAvailableException {
+        SshMachineLocation result = (SshMachineLocation) loc.obtain(flags);
+        machines.add(result);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/GoGridLocationLiveTest.groovy
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/GoGridLocationLiveTest.groovy b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/GoGridLocationLiveTest.groovy
deleted file mode 100644
index 5276302..0000000
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/GoGridLocationLiveTest.groovy
+++ /dev/null
@@ -1,52 +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 org.apache.brooklyn.location.jclouds.provider
-
-import org.testng.annotations.DataProvider
-
-public class GoGridLocationLiveTest extends AbstractJcloudsLocationTest {
-    
-    private static final String PROVIDER = "gogrid"
-    private static final String USWEST_REGION_NAME = "1"//"us-west-1"
-    private static final String USWEST_IMAGE_ID = "1532"
-    private static final String IMAGE_NAME_PATTERN = "CentOS 5.3 (64-bit) w/ None"
-    private static final String IMAGE_OWNER = null
-    
-    public GoGridLocationLiveTest() {
-        super(PROVIDER)
-    }
-    
-    @Override
-    @DataProvider(name = "fromImageId")
-    public Object[][] cloudAndImageIds() {
-        return [ [USWEST_REGION_NAME, USWEST_IMAGE_ID, IMAGE_OWNER] ]
-    }
-
-    @Override
-    @DataProvider(name = "fromImageNamePattern")
-    public Object[][] cloudAndImageNamePatterns() {
-        return [ [USWEST_REGION_NAME, IMAGE_NAME_PATTERN, IMAGE_OWNER] ]
-    }
-    
-    @Override
-    @DataProvider(name = "fromImageDescriptionPattern")
-    public Object[][] cloudAndImageDescriptionPatterns() {
-        return []
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/GoGridLocationLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/GoGridLocationLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/GoGridLocationLiveTest.java
new file mode 100644
index 0000000..c8ab1fe
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/GoGridLocationLiveTest.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds.provider;
+
+import org.testng.annotations.DataProvider;
+
+public class GoGridLocationLiveTest extends AbstractJcloudsLocationTest {
+    
+    private static final String PROVIDER = "gogrid";
+    private static final String USWEST_REGION_NAME = "1";//"us-west-1"
+    private static final String USWEST_IMAGE_ID = "1532";
+    private static final String IMAGE_NAME_PATTERN = "CentOS 5.3 (64-bit) w/ None";
+    private static final String IMAGE_OWNER = null;
+    
+    public GoGridLocationLiveTest() {
+        super(PROVIDER);
+    }
+    
+    @Override
+    @DataProvider(name = "fromImageId")
+    public Object[][] cloudAndImageIds() {
+        return new Object[][] {{USWEST_REGION_NAME, USWEST_IMAGE_ID, IMAGE_OWNER}};
+    }
+
+    @Override
+    @DataProvider(name = "fromImageNamePattern")
+    public Object[][] cloudAndImageNamePatterns() {
+        return new Object[][] {{USWEST_REGION_NAME, IMAGE_NAME_PATTERN, IMAGE_OWNER}};
+    }
+    
+    @Override
+    @DataProvider(name = "fromImageDescriptionPattern")
+    public Object[][] cloudAndImageDescriptionPatterns() {
+        return new Object[][] {};
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/policy/pom.xml
----------------------------------------------------------------------
diff --git a/policy/pom.xml b/policy/pom.xml
index 0843753..c28e39f 100644
--- a/policy/pom.xml
+++ b/policy/pom.xml
@@ -23,8 +23,8 @@
     <packaging>jar</packaging>
     <name>Brooklyn Policies</name>
     <description>
-		General policies and enrichers for managing entities
-	</description>
+        General policies and enrichers for managing entities
+    </description>
 
     <parent>
         <groupId>org.apache.brooklyn</groupId>
@@ -44,10 +44,6 @@
             <artifactId>guava</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.apache.brooklyn</groupId>
             <artifactId>brooklyn-utils-common</artifactId>
             <version>${project.version}</version>
@@ -96,21 +92,4 @@
             <scope>test</scope>
         </dependency>
     </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <inherited>true</inherited>
-                <executions>
-                    <execution>
-                        <id>default-testCompile</id>
-                        <configuration>
-                            <compilerId>groovy-eclipse-compiler</compilerId>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.groovy
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.groovy b/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.groovy
deleted file mode 100644
index 3c5f192..0000000
--- a/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.groovy
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.policy.enricher
-
-import static org.testng.Assert.assertEquals
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.SubscriptionContext
-import org.apache.brooklyn.api.sensor.Sensor
-import org.apache.brooklyn.core.entity.AbstractApplication
-import org.apache.brooklyn.core.entity.AbstractEntity
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-class DeltaEnrichersTests {
-    
-    AbstractApplication app
-    
-    EntityLocal producer
-
-    Sensor<Integer> intSensor, deltaSensor
-    Sensor<Double> avgSensor
-    SubscriptionContext subscription
-    
-    @BeforeMethod
-    public void before() {
-        app = new AbstractApplication() {}
-        producer = new AbstractEntity(app) {}
-        Entities.startManagement(app);
-
-        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor")
-        deltaSensor = new BasicAttributeSensor<Double>(Double.class, "delta sensor")
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    @Test
-    public void testDeltaEnricher() {
-        DeltaEnricher delta = new DeltaEnricher<Integer>(producer, intSensor, deltaSensor)
-        producer.enrichers().add(delta)
-        
-        delta.onEvent(intSensor.newEvent(producer, 0))
-        delta.onEvent(intSensor.newEvent(producer, 0))
-        assertEquals(producer.getAttribute(deltaSensor), 0d)
-        delta.onEvent(intSensor.newEvent(producer, 1))
-        assertEquals(producer.getAttribute(deltaSensor), 1d)
-        delta.onEvent(intSensor.newEvent(producer, 3))
-        assertEquals(producer.getAttribute(deltaSensor), 2d)
-        delta.onEvent(intSensor.newEvent(producer, 8))
-        assertEquals(producer.getAttribute(deltaSensor), 5d)
-    }
-    
-    @Test
-    public void testMonospaceTimeWeightedDeltaEnricher() {
-        TimeWeightedDeltaEnricher delta = 
-            TimeWeightedDeltaEnricher.<Integer>getPerSecondDeltaEnricher(producer, intSensor, deltaSensor)
-        producer.enrichers().add(delta)
-        
-        delta.onEvent(intSensor.newEvent(producer, 0), 0)
-        assertEquals(producer.getAttribute(deltaSensor), null)
-        delta.onEvent(intSensor.newEvent(producer, 0), 1000)
-        assertEquals(producer.getAttribute(deltaSensor), 0d)
-        delta.onEvent(intSensor.newEvent(producer, 1), 2000)
-        assertEquals(producer.getAttribute(deltaSensor), 1d)
-        delta.onEvent(intSensor.newEvent(producer, 3), 3000)
-        assertEquals(producer.getAttribute(deltaSensor), 2d)
-        delta.onEvent(intSensor.newEvent(producer, 8), 4000)
-        assertEquals(producer.getAttribute(deltaSensor), 5d)
-    }
-    
-    @Test
-    public void testVariableTimeWeightedDeltaEnricher() {
-        TimeWeightedDeltaEnricher delta = 
-            TimeWeightedDeltaEnricher.<Integer>getPerSecondDeltaEnricher(producer, intSensor, deltaSensor)
-        producer.enrichers().add(delta)
-        
-        delta.onEvent(intSensor.newEvent(producer, 0), 0)
-        delta.onEvent(intSensor.newEvent(producer, 0), 2000)
-        assertEquals(producer.getAttribute(deltaSensor), 0d)
-        delta.onEvent(intSensor.newEvent(producer, 3), 5000)
-        assertEquals(producer.getAttribute(deltaSensor), 1d)
-        delta.onEvent(intSensor.newEvent(producer, 7), 7000)
-        assertEquals(producer.getAttribute(deltaSensor), 2d)
-        delta.onEvent(intSensor.newEvent(producer, 12), 7500)
-        assertEquals(producer.getAttribute(deltaSensor), 10d)
-        delta.onEvent(intSensor.newEvent(producer, 15), 9500)
-        assertEquals(producer.getAttribute(deltaSensor), 1.5d)
-    }
-
-    @Test
-    public void testPostProcessorCalledForDeltaEnricher() {
-        TimeWeightedDeltaEnricher delta = new TimeWeightedDeltaEnricher(producer, intSensor, deltaSensor, 1000, {it+123})
-        producer.enrichers().add(delta)
-        
-        delta.onEvent(intSensor.newEvent(producer, 0), 0)
-        delta.onEvent(intSensor.newEvent(producer, 0), 1000)
-        assertEquals(producer.getAttribute(deltaSensor), 123+0d)
-        delta.onEvent(intSensor.newEvent(producer, 1), 2000)
-        assertEquals(producer.getAttribute(deltaSensor), 123+1d)
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.java b/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.java
new file mode 100644
index 0000000..3722bcd
--- /dev/null
+++ b/policy/src/test/java/org/apache/brooklyn/policy/enricher/DeltaEnrichersTests.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.policy.enricher;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.SubscriptionContext;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.core.entity.AbstractApplication;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+
+public class DeltaEnrichersTests {
+    
+    AbstractApplication app;
+    
+    EntityLocal producer;
+
+    Sensor<Integer> intSensor;
+    Sensor<Double> avgSensor;
+    SubscriptionContext subscription;
+    
+    @BeforeMethod
+    public void before() {
+        app = new AbstractApplication() {};
+        producer = new AbstractEntity(app) {};
+        producer.setParent(app);
+        Entities.startManagement(app);
+
+        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testDeltaEnricher() {
+        AttributeSensor<Integer> deltaSensor = new BasicAttributeSensor<Integer>(Integer.class, "delta sensor");
+        DeltaEnricher<Integer> delta = new DeltaEnricher<Integer>(producer, intSensor, deltaSensor);
+        producer.enrichers().add(delta);
+        
+        delta.onEvent(intSensor.newEvent(producer, 0));
+        delta.onEvent(intSensor.newEvent(producer, 0));
+        assertEquals(producer.getAttribute(deltaSensor), (Integer)0);
+        delta.onEvent(intSensor.newEvent(producer, 1));
+        assertEquals(producer.getAttribute(deltaSensor), (Integer)1);
+        delta.onEvent(intSensor.newEvent(producer, 3));
+        assertEquals(producer.getAttribute(deltaSensor), (Integer)2);
+        delta.onEvent(intSensor.newEvent(producer, 8));
+        assertEquals(producer.getAttribute(deltaSensor), (Integer)5);
+    }
+    
+    @Test
+    public void testMonospaceTimeWeightedDeltaEnricher() {
+        AttributeSensor<Double> deltaSensor = new BasicAttributeSensor<Double>(Double.class, "per second delta delta sensor");
+        TimeWeightedDeltaEnricher<Integer> delta =
+            TimeWeightedDeltaEnricher.<Integer>getPerSecondDeltaEnricher(producer, intSensor, deltaSensor);
+        producer.enrichers().add(delta);
+        
+        delta.onEvent(intSensor.newEvent(producer, 0), 0);
+        assertEquals(producer.getAttribute(deltaSensor), null);
+        delta.onEvent(intSensor.newEvent(producer, 0), 1000);
+        assertEquals(producer.getAttribute(deltaSensor), 0d);
+        delta.onEvent(intSensor.newEvent(producer, 1), 2000);
+        assertEquals(producer.getAttribute(deltaSensor), 1d);
+        delta.onEvent(intSensor.newEvent(producer, 3), 3000);
+        assertEquals(producer.getAttribute(deltaSensor), 2d);
+        delta.onEvent(intSensor.newEvent(producer, 8), 4000);
+        assertEquals(producer.getAttribute(deltaSensor), 5d);
+    }
+    
+    @Test
+    public void testVariableTimeWeightedDeltaEnricher() {
+        AttributeSensor<Double> deltaSensor = new BasicAttributeSensor<Double>(Double.class, "per second delta delta sensor");
+        TimeWeightedDeltaEnricher<Integer> delta =
+            TimeWeightedDeltaEnricher.<Integer>getPerSecondDeltaEnricher(producer, intSensor, deltaSensor);
+        producer.enrichers().add(delta);
+        
+        delta.onEvent(intSensor.newEvent(producer, 0), 0);
+        delta.onEvent(intSensor.newEvent(producer, 0), 2000);
+        assertEquals(producer.getAttribute(deltaSensor), 0d);
+        delta.onEvent(intSensor.newEvent(producer, 3), 5000);
+        assertEquals(producer.getAttribute(deltaSensor), 1d);
+        delta.onEvent(intSensor.newEvent(producer, 7), 7000);
+        assertEquals(producer.getAttribute(deltaSensor), 2d);
+        delta.onEvent(intSensor.newEvent(producer, 12), 7500);
+        assertEquals(producer.getAttribute(deltaSensor), 10d);
+        delta.onEvent(intSensor.newEvent(producer, 15), 9500);
+        assertEquals(producer.getAttribute(deltaSensor), 1.5d);
+    }
+
+    @Test
+    public void testPostProcessorCalledForDeltaEnricher() {
+        AttributeSensor<Double> deltaSensor = new BasicAttributeSensor<Double>(Double.class, "per second delta delta sensor");
+        TimeWeightedDeltaEnricher<Integer> delta = new TimeWeightedDeltaEnricher<Integer>(producer, intSensor, deltaSensor, 1000, new AddConstant(123d));
+        producer.enrichers().add(delta);
+        
+        delta.onEvent(intSensor.newEvent(producer, 0), 0);
+        delta.onEvent(intSensor.newEvent(producer, 0), 1000);
+        assertEquals(producer.getAttribute(deltaSensor), 123+0d);
+        delta.onEvent(intSensor.newEvent(producer, 1), 2000);
+        assertEquals(producer.getAttribute(deltaSensor), 123+1d);
+    }
+
+    private static class AddConstant implements Function<Double, Double> {
+        private Double constant;
+
+        public AddConstant(Double constant) {
+            super();
+            this.constant = constant;
+        }
+
+        @Override
+        public Double apply(Double input) {
+            return input + constant;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.groovy
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.groovy b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.groovy
deleted file mode 100644
index bb7d2b7..0000000
--- a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.groovy
+++ /dev/null
@@ -1,105 +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 org.apache.brooklyn.policy.enricher
-
-import static org.testng.Assert.assertEquals;
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.SubscriptionContext
-import org.apache.brooklyn.api.sensor.Sensor
-import org.apache.brooklyn.core.entity.AbstractApplication
-import org.apache.brooklyn.core.entity.AbstractEntity
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-class RollingMeanEnricherTest {
-    
-    AbstractApplication app
-    
-    EntityLocal producer
-
-    Sensor<Integer> intSensor, deltaSensor
-    Sensor<Double> avgSensor
-    SubscriptionContext subscription
-    
-    RollingMeanEnricher<Integer> averager
-
-    @BeforeMethod(alwaysRun=true)
-    public void before() {
-        app = new AbstractApplication() {}
-        producer = new AbstractEntity(app) {}
-        Entities.startManagement(app);
-
-        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor")
-        deltaSensor = new BasicAttributeSensor<Integer>(Integer.class, "delta sensor")
-        avgSensor = new BasicAttributeSensor<Double>(Integer.class, "avg sensor")
-        
-        producer.enrichers().add(new DeltaEnricher<Integer>(producer, intSensor, deltaSensor))
-        averager = new RollingMeanEnricher<Integer>(producer, deltaSensor, avgSensor, 4)
-        producer.enrichers().add(averager)
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    @Test
-    public void testDefaultAverage() {
-        assertEquals(averager.getAverage(), null)
-    }
-    
-    @Test
-    public void testZeroWindowSize() {
-        averager = new RollingMeanEnricher<Integer>(producer, deltaSensor, avgSensor, 0)
-        producer.enrichers().add(averager)
-        
-        averager.onEvent(intSensor.newEvent(producer, 10))
-        assertEquals(averager.getAverage(), null)
-    }
-    
-    @Test
-    public void testSingleValueAverage() {
-        averager.onEvent(intSensor.newEvent(producer, 10))
-        assertEquals(averager.getAverage(), 10d)
-    }
-    
-    @Test
-    public void testMultipleValueAverage() {
-        averager.onEvent(intSensor.newEvent(producer, 10))
-        averager.onEvent(intSensor.newEvent(producer, 20))
-        averager.onEvent(intSensor.newEvent(producer, 30))
-        averager.onEvent(intSensor.newEvent(producer, 40))
-        assertEquals(averager.getAverage(), (10+20+30+40)/4d)
-    }
-    
-    @Test
-    public void testWindowSizeCulling() {
-        averager.onEvent(intSensor.newEvent(producer, 10))
-        averager.onEvent(intSensor.newEvent(producer, 20))
-        averager.onEvent(intSensor.newEvent(producer, 30))
-        averager.onEvent(intSensor.newEvent(producer, 40))
-        averager.onEvent(intSensor.newEvent(producer, 50))
-        averager.onEvent(intSensor.newEvent(producer, 60))
-        assertEquals(averager.getAverage(), (30+40+50+60)/4d)
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.java b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.java
new file mode 100644
index 0000000..071b5c3
--- /dev/null
+++ b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricherTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.policy.enricher;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.mgmt.SubscriptionContext;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.core.entity.AbstractApplication;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class RollingMeanEnricherTest {
+    
+    AbstractApplication app;
+    
+    EntityLocal producer;
+
+    Sensor<Integer> intSensor;
+    AttributeSensor<Integer> deltaSensor;
+    AttributeSensor<Double> avgSensor;
+    RollingMeanEnricher<Integer> averager;
+
+    @BeforeMethod(alwaysRun=true)
+    public void before() {
+        app = new AbstractApplication() {};
+        producer = new AbstractEntity(app) {};
+        producer.setParent(app);
+        Entities.startManagement(app);
+
+        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
+        deltaSensor = new BasicAttributeSensor<Integer>(Integer.class, "delta sensor");
+        avgSensor = new BasicAttributeSensor<Double>(Double.class, "avg sensor");
+        
+        producer.enrichers().add(new DeltaEnricher<Integer>(producer, intSensor, deltaSensor));
+        averager = new RollingMeanEnricher<Integer>(producer, deltaSensor, avgSensor, 4);
+        producer.enrichers().add(averager);
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testDefaultAverage() {
+        assertEquals(averager.getAverage(), null);
+    }
+    
+    @Test
+    public void testZeroWindowSize() {
+        averager = new RollingMeanEnricher<Integer>(producer, deltaSensor, avgSensor, 0);
+        producer.enrichers().add(averager);
+        
+        averager.onEvent(intSensor.newEvent(producer, 10));
+        assertEquals(averager.getAverage(), null);
+    }
+    
+    @Test
+    public void testSingleValueAverage() {
+        averager.onEvent(intSensor.newEvent(producer, 10));
+        assertEquals(averager.getAverage(), 10d);
+    }
+    
+    @Test
+    public void testMultipleValueAverage() {
+        averager.onEvent(intSensor.newEvent(producer, 10));
+        averager.onEvent(intSensor.newEvent(producer, 20));
+        averager.onEvent(intSensor.newEvent(producer, 30));
+        averager.onEvent(intSensor.newEvent(producer, 40));
+        assertEquals(averager.getAverage(), (10+20+30+40)/4d);
+    }
+    
+    @Test
+    public void testWindowSizeCulling() {
+        averager.onEvent(intSensor.newEvent(producer, 10));
+        averager.onEvent(intSensor.newEvent(producer, 20));
+        averager.onEvent(intSensor.newEvent(producer, 30));
+        averager.onEvent(intSensor.newEvent(producer, 40));
+        averager.onEvent(intSensor.newEvent(producer, 50));
+        averager.onEvent(intSensor.newEvent(producer, 60));
+        assertEquals(averager.getAverage(), (30+40+50+60)/4d);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.groovy
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.groovy b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.groovy
deleted file mode 100644
index 492d672..0000000
--- a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.groovy
+++ /dev/null
@@ -1,155 +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 org.apache.brooklyn.policy.enricher
-
-import static org.testng.Assert.assertEquals
-
-import org.apache.brooklyn.api.entity.EntityLocal;
-import org.apache.brooklyn.api.mgmt.SubscriptionContext
-import org.apache.brooklyn.api.sensor.Sensor
-import org.apache.brooklyn.core.entity.AbstractApplication
-import org.apache.brooklyn.core.entity.AbstractEntity
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor
-import org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher.ConfidenceQualifiedNumber
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-class RollingTimeWindowMeanEnricherTest {
-    
-    AbstractApplication app
-    
-    EntityLocal producer
-
-    Sensor<Integer> intSensor, deltaSensor
-    Sensor<Double> avgSensor
-    SubscriptionContext subscription
-    
-    RollingTimeWindowMeanEnricher<Integer> averager
-    ConfidenceQualifiedNumber average
-
-    private final long timePeriod = 1000
-    
-    @BeforeMethod
-    public void before() {
-        app = new AbstractApplication() {}
-        producer = new AbstractEntity(app) {}
-        Entities.startManagement(app);
-
-        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor")
-        deltaSensor = new BasicAttributeSensor<Integer>(Integer.class, "delta sensor")
-        avgSensor = new BasicAttributeSensor<Double>(Integer.class, "avg sensor")
-        
-        producer.enrichers().add(new DeltaEnricher<Integer>(producer, intSensor, deltaSensor))
-        averager = new RollingTimeWindowMeanEnricher<Integer>(producer, deltaSensor, avgSensor, timePeriod)
-        producer.enrichers().add(averager)
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    @Test
-    public void testDefaultAverageWhenEmpty() {
-        average = averager.getAverage(0)
-        assertEquals(average.value, 0d)
-        assertEquals(average.confidence, 0.0d)
-    }
-    
-    @Test
-    public void testNoRecentValuesAverage() {
-        averager.onEvent(intSensor.newEvent(producer, 10), 0L)
-        average = averager.getAverage(timePeriod+1000)
-        assertEquals(average.value, 10d)
-        assertEquals(average.confidence, 0d)
-    }
-    
-    @Test
-    public void testNoRecentValuesUsesLastForAverage() {
-        averager.onEvent(intSensor.newEvent(producer, 10), 0L)
-        averager.onEvent(intSensor.newEvent(producer, 20), 10L)
-        average = averager.getAverage(timePeriod+1000)
-        assertEquals(average.value, 20d)
-        assertEquals(average.confidence, 0d)
-    }
-    
-    @Test
-    public void testSingleValueTimeAverage() {
-        averager.onEvent(intSensor.newEvent(producer, 10), 1000)
-        average = averager.getAverage(1000)
-        assertEquals(average.confidence, 0d)
-    }
-    
-    @Test
-    public void testTwoValueAverageForPeriod() {
-        averager.onEvent(intSensor.newEvent(producer, 10), 1000)
-        averager.onEvent(intSensor.newEvent(producer, 10), 2000)
-        average = averager.getAverage(2000)
-        assertEquals(average.value, 10 /1d)
-        assertEquals(average.confidence, 1d)
-    }
-    
-    @Test
-    public void testMonospacedAverage() {
-        averager.onEvent(intSensor.newEvent(producer, 10), 1000)
-        averager.onEvent(intSensor.newEvent(producer, 20), 1250)
-        averager.onEvent(intSensor.newEvent(producer, 30), 1500)
-        averager.onEvent(intSensor.newEvent(producer, 40), 1750)
-        averager.onEvent(intSensor.newEvent(producer, 50), 2000)
-        average = averager.getAverage(2000)
-        assertEquals(average.value, (20+30+40+50)/4d)
-        assertEquals(average.confidence, 1d)
-    }
-    
-    @Test
-    public void testWeightedAverage() {
-        averager.onEvent(intSensor.newEvent(producer, 10), 1000)
-        averager.onEvent(intSensor.newEvent(producer, 20), 1100)
-        averager.onEvent(intSensor.newEvent(producer, 30), 1300)
-        averager.onEvent(intSensor.newEvent(producer, 40), 1600)
-        averager.onEvent(intSensor.newEvent(producer, 50), 2000)
-        average = averager.getAverage(2000)
-        assertEquals(average.value, (20*0.1d)+(30*0.2d)+(40*0.3d)+(50*0.4d))
-        assertEquals(average.confidence, 1d)
-    }
-    
-    @Test
-    public void testConfidenceDecay() {
-        averager.onEvent(intSensor.newEvent(producer, 10), 1000)
-        averager.onEvent(intSensor.newEvent(producer, 20), 1250)
-        averager.onEvent(intSensor.newEvent(producer, 30), 1500)
-        averager.onEvent(intSensor.newEvent(producer, 40), 1750)
-        averager.onEvent(intSensor.newEvent(producer, 50), 2000)
-        
-        average = averager.getAverage(2250)
-        assertEquals(average.value, (30+40+50)/3d)
-        assertEquals(average.confidence, 0.75d)
-        average = averager.getAverage(2500)
-        assertEquals(average.value, (40+50)/2d)
-        assertEquals(average.confidence, 0.5d)
-        average = averager.getAverage(2750)
-        assertEquals(average.value, 50d)
-        assertEquals(average.confidence, 0.25d)
-        average = averager.getAverage(3000)
-        assertEquals(average.value, 50d)
-        assertEquals(average.confidence, 0d)
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.java b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.java
new file mode 100644
index 0000000..162833d
--- /dev/null
+++ b/policy/src/test/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricherTest.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.policy.enricher;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.core.entity.AbstractApplication;
+import org.apache.brooklyn.core.entity.AbstractEntity;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher.ConfidenceQualifiedNumber;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+@SuppressWarnings("deprecation")
+public class RollingTimeWindowMeanEnricherTest {
+    
+    AbstractApplication app;
+    
+    EntityLocal producer;
+
+    Sensor<Integer> intSensor;
+    AttributeSensor<Integer> deltaSensor;
+    AttributeSensor<Double> avgSensor;
+
+    RollingTimeWindowMeanEnricher<Integer> averager;
+    ConfidenceQualifiedNumber average;
+
+    private final long timePeriod = 1000;
+    
+    @BeforeMethod
+    public void before() {
+        app = new AbstractApplication() {};
+        producer = new AbstractEntity(app) {};
+        Entities.startManagement(app);
+
+        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
+        deltaSensor = new BasicAttributeSensor<Integer>(Integer.class, "delta sensor");
+        avgSensor = new BasicAttributeSensor<Double>(Double.class, "avg sensor");
+        
+        producer.enrichers().add(new DeltaEnricher<Integer>(producer, intSensor, deltaSensor));
+        averager = new RollingTimeWindowMeanEnricher<Integer>(producer, deltaSensor, avgSensor, timePeriod);
+        producer.enrichers().add(averager);
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test
+    public void testDefaultAverageWhenEmpty() {
+        average = averager.getAverage(0);
+        assertEquals(average.value, 0d);
+        assertEquals(average.confidence, 0.0d);
+    }
+    
+    @Test
+    public void testNoRecentValuesAverage() {
+        averager.onEvent(intSensor.newEvent(producer, 10), 0L);
+        average = averager.getAverage(timePeriod+1000);
+        assertEquals(average.value, 10d);
+        assertEquals(average.confidence, 0d);
+    }
+    
+    @Test
+    public void testNoRecentValuesUsesLastForAverage() {
+        averager.onEvent(intSensor.newEvent(producer, 10), 0L);
+        averager.onEvent(intSensor.newEvent(producer, 20), 10L);
+        average = averager.getAverage(timePeriod+1000);
+        assertEquals(average.value, 20d);
+        assertEquals(average.confidence, 0d);
+    }
+    
+    @Test
+    public void testSingleValueTimeAverage() {
+        averager.onEvent(intSensor.newEvent(producer, 10), 1000);
+        average = averager.getAverage(1000);
+        assertEquals(average.confidence, 0d);
+    }
+    
+    @Test
+    public void testTwoValueAverageForPeriod() {
+        averager.onEvent(intSensor.newEvent(producer, 10), 1000);
+        averager.onEvent(intSensor.newEvent(producer, 10), 2000);
+        average = averager.getAverage(2000);
+        assertEquals(average.value, 10 /1d);
+        assertEquals(average.confidence, 1d);
+    }
+    
+    @Test
+    public void testMonospacedAverage() {
+        averager.onEvent(intSensor.newEvent(producer, 10), 1000);
+        averager.onEvent(intSensor.newEvent(producer, 20), 1250);
+        averager.onEvent(intSensor.newEvent(producer, 30), 1500);
+        averager.onEvent(intSensor.newEvent(producer, 40), 1750);
+        averager.onEvent(intSensor.newEvent(producer, 50), 2000);
+        average = averager.getAverage(2000);
+        assertEquals(average.value, (20+30+40+50)/4d);
+        assertEquals(average.confidence, 1d);
+    }
+    
+    @Test
+    public void testWeightedAverage() {
+        averager.onEvent(intSensor.newEvent(producer, 10), 1000);
+        averager.onEvent(intSensor.newEvent(producer, 20), 1100);
+        averager.onEvent(intSensor.newEvent(producer, 30), 1300);
+        averager.onEvent(intSensor.newEvent(producer, 40), 1600);
+        averager.onEvent(intSensor.newEvent(producer, 50), 2000);
+        average = averager.getAverage(2000);
+        assertEquals(average.value, (20*0.1d)+(30*0.2d)+(40*0.3d)+(50*0.4d));
+        assertEquals(average.confidence, 1d);
+    }
+    
+    @Test
+    public void testConfidenceDecay() {
+        averager.onEvent(intSensor.newEvent(producer, 10), 1000);
+        averager.onEvent(intSensor.newEvent(producer, 20), 1250);
+        averager.onEvent(intSensor.newEvent(producer, 30), 1500);
+        averager.onEvent(intSensor.newEvent(producer, 40), 1750);
+        averager.onEvent(intSensor.newEvent(producer, 50), 2000);
+        
+        average = averager.getAverage(2250);
+        assertEquals(average.value, (30+40+50)/3d);
+        assertEquals(average.confidence, 0.75d);
+        average = averager.getAverage(2500);
+        assertEquals(average.value, (40+50)/2d);
+        assertEquals(average.confidence, 0.5d);
+        average = averager.getAverage(2750);
+        assertEquals(average.value, 50d);
+        assertEquals(average.confidence, 0.25d);
+        average = averager.getAverage(3000);
+        assertEquals(average.value, 50d);
+        assertEquals(average.confidence, 0d);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Database.groovy
----------------------------------------------------------------------
diff --git a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Database.groovy b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Database.groovy
deleted file mode 100644
index 4e0ce53..0000000
--- a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Database.groovy
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.brooklyn.entity.database
-
-import org.apache.brooklyn.core.config.BasicConfigKey
-
-/**
- * Intended to represent a SQL relational database service.
- *
- * TODO work in progress
- */
-public interface Database {
-    BasicConfigKey<String> SQL_VERSION = [ String, "database.sql.version", "SQL version" ]
-
-    Collection<Schema> getSchemas();
-
-    void createSchema(String name, Map properties);
-
-    void addSchema(Schema schema);
-
-    void removeSchema(String schemaName);
-}
-
-/**
- * Intended to represent a SQL database schema.
- *
- * TODO work in progress
- */
-public interface Schema {
-    BasicConfigKey<String> SCHEMA_NAME = [ String, "database.schema", "Database schema name" ]
-
-    void create();
-    
-    void remove();
-    
-    String getName();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Database.java
----------------------------------------------------------------------
diff --git a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Database.java b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Database.java
new file mode 100644
index 0000000..fccb760
--- /dev/null
+++ b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Database.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.database;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+
+/**
+ * Intended to represent a SQL relational database service.
+ *
+ * TODO work in progress
+ */
+public interface Database {
+    ConfigKey<String> SQL_VERSION = ConfigKeys.newStringConfigKey("database.sql.version", "SQL version");
+
+    Collection<Schema> getSchemas();
+
+    void createSchema(String name, Map properties);
+
+    void addSchema(Schema schema);
+
+    void removeSchema(String schemaName);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Schema.java
----------------------------------------------------------------------
diff --git a/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Schema.java b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Schema.java
new file mode 100644
index 0000000..a032adc
--- /dev/null
+++ b/sandbox/database/src/main/java/org/apache/brooklyn/entity/database/Schema.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.database;
+
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+
+/**
+ * Intended to represent a SQL database schema.
+ *
+ * TODO work in progress
+ */
+public interface Schema {
+    ConfigKey<String> SCHEMA_NAME = ConfigKeys.newStringConfigKey("database.schema", "Database schema name");
+
+    void create();
+
+    void remove();
+
+    String getName();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy
deleted file mode 100644
index 70d8f06..0000000
--- a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.groovy
+++ /dev/null
@@ -1,103 +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 org.apache.brooklyn.entity.nosql.infinispan
-
-import static org.apache.brooklyn.test.TestUtils.*
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import java.util.concurrent.TimeUnit
-
-import org.apache.brooklyn.entity.nosql.infinispan.Infinispan5Server;
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import org.apache.brooklyn.api.entity.Application
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation
-import org.apache.brooklyn.core.test.entity.TestApplicationImpl
-import org.apache.brooklyn.util.groovy.TimeExtras;
-import org.apache.brooklyn.util.net.Networking
-import org.apache.brooklyn.util.repeat.Repeater
-
-class Infinispan5ServerIntegrationTest {
-    private static final Logger logger = LoggerFactory.getLogger(Infinispan5ServerIntegrationTest.class)
-    
-    static String DEFAULT_PROTOCOL = "memcached"
-    static int DEFAULT_PORT = 11219
-
-    static boolean portLeftOpen = false;
-    
-    static { TimeExtras.init() }
-
-    @BeforeMethod(groups = [ "Integration" ])
-    public void failIfPortInUse() {
-        if (isPortInUse(DEFAULT_PORT, 5000L)) {
-            portLeftOpen = true;
-            fail "someone is already listening on port $DEFAULT_PORT; tests assume that port $DEFAULT_PORT is free on localhost"
-        }
-    }
- 
-    @AfterMethod(groups = [ "Integration" ])
-    public void ensureIsShutDown() {
-        Socket shutdownSocket = null;
-        SocketException gotException = null;
-
-        boolean socketClosed = new Repeater("Checking Infinispan has shut down")
-            .repeat {
-                    if (shutdownSocket) shutdownSocket.close();
-                    try { shutdownSocket = new Socket(Networking.localHost, DEFAULT_PORT); }
-                    catch (SocketException e) { gotException = e; return; }
-                    gotException = null
-                }
-            .every(100 * MILLISECONDS)
-            .until { gotException }
-            .limitIterationsTo(25)
-            .run();
-
-        if (socketClosed == false) {
-            logger.error "Infinispan did not shut down";
-            throw new Exception("Infinispan did not shut down")
-        }
-    }
-
-    public void ensureIsUp() {
-        Socket socket = new Socket(Networking.localHost, DEFAULT_PORT);
-        socket.close();
-    }
-
-    @Test(groups = [ "Integration", "WIP" ])
-    public void testInfinispanStartsAndStops() {
-        Application app = new TestApplicationImpl();
-        try {
-            final Infinispan5Server infini = new Infinispan5Server(parent:app)
-            infini.config().set(Infinispan5Server.PORT.getConfigKey(), DEFAULT_PORT)
-            infini.start([ new LocalhostMachineProvisioningLocation(name:'london') ])
-            
-            executeUntilSucceeds {
-                assertTrue infini.getAttribute(Infinispan5Server.SERVICE_UP)
-            }
-        } finally {
-            Entities.destroy(app);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.java b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.java
new file mode 100644
index 0000000..a541c7a
--- /dev/null
+++ b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.nosql.infinispan;
+
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.SocketException;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.test.entity.TestApplicationImpl;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.groovy.TimeExtras;
+import org.apache.brooklyn.util.net.Networking;
+import org.apache.brooklyn.util.repeat.Repeater;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+class Infinispan5ServerIntegrationTest {
+    private static final Logger logger = LoggerFactory.getLogger(Infinispan5ServerIntegrationTest.class);
+    
+    static String DEFAULT_PROTOCOL = "memcached";
+    static int DEFAULT_PORT = 11219;
+
+    static boolean portLeftOpen = false;
+    
+    static { TimeExtras.init(); }
+
+    @BeforeMethod(groups = "Integration")
+    public void failIfPortInUse() {
+        if (Networking.isPortAvailable(DEFAULT_PORT)) {
+            portLeftOpen = true;
+            fail("someone is already listening on port $DEFAULT_PORT; tests assume that port $DEFAULT_PORT is free on localhost");
+        }
+    }
+ 
+    @AfterMethod(groups = "Integration")
+    public void ensureIsShutDown() {
+        boolean socketClosed = new Repeater("Checking Infinispan has shut down")
+            .every(Duration.millis(100))
+            .until(new Callable<Boolean>() {
+                @Override
+                public Boolean call() throws Exception {
+                    Socket shutdownSocket = null;
+
+                    try { shutdownSocket = new Socket(Networking.getLocalHost(), DEFAULT_PORT); }
+                    catch (SocketException e) { return true; }
+                    shutdownSocket.close();
+
+                    return false;
+                }
+            })
+            .limitIterationsTo(25)
+            .run();
+
+        if (socketClosed == false) {
+            logger.error("Infinispan did not shut down");
+            throw new IllegalStateException("Infinispan did not shut down");
+        }
+    }
+
+    public void ensureIsUp() throws IOException {
+        Socket socket = new Socket(Networking.getLocalHost(), DEFAULT_PORT);
+        socket.close();
+    }
+
+    @Test(groups = {"Integration", "WIP"})
+    public void testInfinispanStartsAndStops() {
+        Application app = new TestApplicationImpl();
+        try {
+            final Infinispan5Server infini = new Infinispan5Server(ImmutableMap.of("parent", app));
+            infini.config().set(Infinispan5Server.PORT.getConfigKey(), PortRanges.fromInteger(DEFAULT_PORT));
+            infini.start(ImmutableList.of(new LocalhostMachineProvisioningLocation(ImmutableMap.of("name","london"))));
+            EntityTestUtils.assertAttributeEqualsEventually(infini, Infinispan5Server.SERVICE_UP, Boolean.TRUE);
+        } finally {
+            Entities.destroy(app);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/software/webapp/pom.xml
----------------------------------------------------------------------
diff --git a/software/webapp/pom.xml b/software/webapp/pom.xml
index 8e8cae3..77c327c 100644
--- a/software/webapp/pom.xml
+++ b/software/webapp/pom.xml
@@ -53,20 +53,6 @@
                 </plugin>
             </plugins>
         </pluginManagement>
-        <plugins>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <inherited>true</inherited>
-                <executions>
-                    <execution>
-                        <id>default-testCompile</id>
-                        <configuration>
-                            <compilerId>groovy-eclipse-compiler</compilerId>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
     </build>
     
     <dependencies>    
@@ -113,10 +99,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpcore</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy
deleted file mode 100644
index 4706654..0000000
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.groovy
+++ /dev/null
@@ -1,101 +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 org.apache.brooklyn.entity.webapp
-
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import org.apache.brooklyn.api.entity.Application
-import org.apache.brooklyn.api.location.Location
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.core.entity.trait.Startable
-import org.apache.brooklyn.core.location.BasicLocationRegistry
-import org.apache.brooklyn.core.internal.BrooklynProperties
-import org.apache.brooklyn.core.test.entity.TestApplicationImpl
-import org.apache.brooklyn.entity.software.base.SoftwareProcess
-import org.apache.brooklyn.entity.webapp.jboss.JBoss6Server
-import org.apache.brooklyn.entity.webapp.jboss.JBoss6ServerImpl
-import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server
-import org.apache.brooklyn.entity.webapp.jboss.JBoss7ServerImpl
-import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer
-import org.apache.brooklyn.entity.webapp.tomcat.TomcatServerImpl
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.DataProvider
-import org.testng.annotations.Test
-
-/**
- * This tests that we can run jboss entity on AWS.
- */
-public class WebAppLiveIntegrationTest {
-    private static final Logger logger = LoggerFactory.getLogger(WebAppLiveIntegrationTest.class)
-
-    public static final int DEFAULT_HTTP_PORT = 8080
-    public static final int DEFAULT_JMX_PORT = 32199
-
-    // Port increment for JBoss 6.
-    public static final int PORT_INCREMENT = 400
-
-    // The parent application entity for these tests
-    Application application = new TestApplicationImpl()
-
-    Location loc
-
-    /**
-     * Provides instances of {@link TomcatServer}, {@link JBoss6Server} and {@link JBoss7Server} to the tests below.
-     *
-     * TODO combine the data provider here with the integration tests
-     *
-     * @see WebAppIntegrationTest#basicEntities()
-     */
-    @DataProvider(name = "basicEntities")
-    public Object[][] basicEntities() {
-        TomcatServer tomcat = new TomcatServerImpl(parent:application, httpPort:DEFAULT_HTTP_PORT, jmxPort:DEFAULT_JMX_PORT)
-        JBoss6Server jboss6 = new JBoss6ServerImpl(parent:application, portIncrement:PORT_INCREMENT, jmxPort:DEFAULT_JMX_PORT)
-        JBoss7Server jboss7 = new JBoss7ServerImpl(parent:application, httpPort:DEFAULT_HTTP_PORT, jmxPort:DEFAULT_JMX_PORT)
-        return [ [ tomcat ], [ jboss6 ], [ jboss7 ] ]
-    }
-
-    @BeforeMethod(alwaysRun = true)
-    public void setUp() {
-        Entities.manage(application)
-
-        BrooklynProperties props = BrooklynProperties.Factory.newDefault()
-        props.put("brooklyn.location.jclouds.aws-ec2.imagel-id", "us-east-1/ami-2342a94a")
-        props.put("brooklyn.location.jclouds.aws-ec2.image-owner", "411009282317")
-
-        loc = new BasicLocationRegistry(props).resolve("aws-ec2:us-east-1")
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void shutdown() {
-        if (application != null) Entities.destroyAll(application.getManagementContext());
-    }
-
-    @Test(groups = "Live", dataProvider="basicEntities")
-    public void testStartsWebAppInAws(final SoftwareProcess entity) {
-        entity.start([ loc ])
-        executeUntilSucceedsWithShutdown(entity, abortOnError:false, timeout:75*SECONDS, useGroovyTruth:true) {
-            assertTrue(entity.getAttribute(Startable.SERVICE_UP))
-            true
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.java
new file mode 100644
index 0000000..cfc33a9
--- /dev/null
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppLiveIntegrationTest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.webapp;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.location.PortRanges;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.entity.webapp.jboss.JBoss6Server;
+import org.apache.brooklyn.entity.webapp.jboss.JBoss6ServerImpl;
+import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
+import org.apache.brooklyn.entity.webapp.jboss.JBoss7ServerImpl;
+import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.time.Duration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * This tests that we can run jboss entity on AWS.
+ */
+public class WebAppLiveIntegrationTest extends BrooklynAppUnitTestSupport {
+    public static final PortRange DEFAULT_HTTP_PORT = PortRanges.fromInteger(8080);
+    public static final PortRange DEFAULT_JMX_PORT = PortRanges.fromInteger(32199);
+
+    // Port increment for JBoss 6.
+    public static final int PORT_INCREMENT = 400;
+
+    // The parent application entity for these tests
+    Location loc;
+
+    /**
+     * Provides instances of {@link TomcatServer}, {@link JBoss6Server} and {@link JBoss7Server} to the tests below.
+     *
+     * TODO combine the data provider here with the integration tests
+     *
+     * @see WebAppIntegrationTest#basicEntities()
+     */
+    @DataProvider(name = "basicEntities")
+    public Object[][] basicEntities() {
+        return new Object[][] {
+                { EntitySpec.create(TomcatServer.class)
+                    .configure(TomcatServer.HTTP_PORT, DEFAULT_HTTP_PORT)
+                    .configure(TomcatServer.JMX_PORT, DEFAULT_JMX_PORT) },
+                { EntitySpec.create(JBoss6ServerImpl.class)
+                    .configure(JBoss6Server.PORT_INCREMENT, PORT_INCREMENT)
+                    .configure(JBoss6Server.JMX_PORT, DEFAULT_JMX_PORT) },
+                { EntitySpec.create(JBoss7ServerImpl.class)
+                    .configure(JBoss7Server.PORT_INCREMENT, PORT_INCREMENT) } };
+    }
+
+    @Override
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() {
+        loc = mgmt.getLocationRegistry().resolve("aws-ec2:us-east-1", ImmutableMap.of(
+                "imagel-id", "us-east-1/ami-2342a94a",
+                "image-owner", "411009282317"));
+    }
+
+    @Test(groups = "Live", dataProvider="basicEntities")
+    public void testStartsWebAppInAws(final EntitySpec<JavaWebAppSoftwareProcess> spec) {
+        JavaWebAppSoftwareProcess server = app.createAndManageChild(spec);
+        server.start(ImmutableList.of(loc));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", Duration.seconds(75)),
+                server, Attributes.SERVICE_UP, Boolean.TRUE);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/usage/cli/pom.xml
----------------------------------------------------------------------
diff --git a/usage/cli/pom.xml b/usage/cli/pom.xml
index 507a377..dbc5d44 100644
--- a/usage/cli/pom.xml
+++ b/usage/cli/pom.xml
@@ -121,18 +121,6 @@
                     </instructions>
                 </configuration>
             </plugin>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <inherited>true</inherited>
-                <executions>
-                    <execution>
-                        <id>default-testCompile</id>
-                        <configuration>
-                            <compilerId>groovy-eclipse-compiler</compilerId>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
             
             <plugin>
                 <!-- we publish the BOM in case anyone wants to access it directly.


[6/7] incubator-brooklyn git commit: Remove groovy dependencies

Posted by al...@apache.org.
Remove groovy dependencies


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

Branch: refs/heads/master
Commit: 4ba22be8457bad0ebb1472aae6216ba689a34c31
Parents: 0d0214c
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 22 09:49:37 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Thu Oct 22 16:44:58 2015 +0300

----------------------------------------------------------------------
 core/pom.xml                        | 16 +++++++++
 examples/simple-web-cluster/pom.xml |  4 ---
 parent/pom.xml                      | 56 +++++++++++---------------------
 sandbox/database/pom.xml            | 17 ----------
 sandbox/nosql/pom.xml               | 12 -------
 software/base/pom.xml               |  9 -----
 software/database/pom.xml           | 23 -------------
 software/messaging/pom.xml          |  9 -----
 software/nosql/pom.xml              |  9 -----
 software/osgi/pom.xml               |  4 ---
 usage/cli/pom.xml                   |  4 ---
 usage/downstream-parent/pom.xml     |  1 -
 usage/launcher/pom.xml              |  4 ---
 usage/qa/pom.xml                    |  4 ---
 usage/rest-server/pom.xml           |  4 ---
 usage/test-support/pom.xml          |  5 ---
 utils/groovy/pom.xml                | 12 -------
 17 files changed, 35 insertions(+), 158 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 222ccfd..1a0e04b 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -224,6 +224,10 @@
             <plugin>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <inherited>true</inherited>
+                <configuration>
+                    <fork>true</fork>
+                    <verbose>false</verbose>
+                </configuration>
                 <executions>
                     <!-- 
                       Compile only Groovy files with the eclipse-groovy compiler.
@@ -247,6 +251,18 @@
                         </configuration>
                     </execution>
                 </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.codehaus.groovy</groupId>
+                        <artifactId>groovy-eclipse-compiler</artifactId>
+                        <version>2.9.0-01</version>
+                    </dependency>
+                    <dependency>
+                        <groupId>org.codehaus.groovy</groupId>
+                        <artifactId>groovy-eclipse-batch</artifactId>
+                        <version>2.3.4-01</version>
+                    </dependency>
+                </dependencies>
             </plugin>
         </plugins>
     </build>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/examples/simple-web-cluster/pom.xml
----------------------------------------------------------------------
diff --git a/examples/simple-web-cluster/pom.xml b/examples/simple-web-cluster/pom.xml
index afeb419..afe9364 100644
--- a/examples/simple-web-cluster/pom.xml
+++ b/examples/simple-web-cluster/pom.xml
@@ -45,10 +45,6 @@
             <optional>true</optional>
         </dependency>
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index 1ca10ad..42ec0b1 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -1040,26 +1040,6 @@
                     <encoding>${project.build.sourceEncoding}</encoding>
                 </configuration>
             </plugin>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <inherited>true</inherited>
-                <configuration>
-                    <fork>true</fork>
-                    <verbose>false</verbose>
-                </configuration>
-                <dependencies>
-                    <dependency>
-                        <groupId>org.codehaus.groovy</groupId>
-                        <artifactId>groovy-eclipse-compiler</artifactId>
-                        <version>2.9.0-01</version>
-                    </dependency>
-                    <dependency>
-                        <groupId>org.codehaus.groovy</groupId>
-                        <artifactId>groovy-eclipse-batch</artifactId>
-                        <version>2.3.4-01</version>
-                    </dependency>
-                </dependencies>
-            </plugin>
             <!--  workaround for src/main/resources excluding all in eclipse, as per
                   https://issues.sonatype.org/browse/MNGECLIPSE-864
             -->
@@ -1865,23 +1845,25 @@
         <profile>
             <id>eclipse-compiler</id>
             <build>
-                <plugins>
-                    <plugin>
-                       <groupId>org.apache.maven.plugins</groupId>
-                       <artifactId>maven-compiler-plugin</artifactId>
-                       <configuration>
-                           <compilerId>eclipse</compilerId>
-                           <optimize>true</optimize>
-                       </configuration>
-                       <dependencies>
-                               <dependency>
-                                   <groupId>org.codehaus.plexus</groupId>
-                                   <artifactId>plexus-compiler-eclipse</artifactId>
-                                   <version>2.6</version>
-                               </dependency>
-                       </dependencies>
-                    </plugin>
-                </plugins>
+                <pluginManagement>
+                    <plugins>
+                      <plugin>
+                         <groupId>org.apache.maven.plugins</groupId>
+                         <artifactId>maven-compiler-plugin</artifactId>
+                         <configuration>
+                             <compilerId>eclipse</compilerId>
+                             <optimize>true</optimize>
+                         </configuration>
+                         <dependencies>
+                             <dependency>
+                                 <groupId>org.codehaus.plexus</groupId>
+                                 <artifactId>plexus-compiler-eclipse</artifactId>
+                                 <version>2.6</version>
+                             </dependency>
+                         </dependencies>
+                      </plugin>
+                  </plugins>
+              </pluginManagement>
             </build>
         </profile>
     </profiles>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/sandbox/database/pom.xml
----------------------------------------------------------------------
diff --git a/sandbox/database/pom.xml b/sandbox/database/pom.xml
index 5305b03..b38a65d 100644
--- a/sandbox/database/pom.xml
+++ b/sandbox/database/pom.xml
@@ -63,21 +63,4 @@
             <scope>test</scope>
         </dependency>
     </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <inherited>true</inherited>
-                <executions>
-                    <execution>
-                        <id>default-testCompile</id>
-                        <configuration>
-                            <compilerId>groovy-eclipse-compiler</compilerId>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/sandbox/nosql/pom.xml
----------------------------------------------------------------------
diff --git a/sandbox/nosql/pom.xml b/sandbox/nosql/pom.xml
index d3a7f52..d62be44 100644
--- a/sandbox/nosql/pom.xml
+++ b/sandbox/nosql/pom.xml
@@ -80,18 +80,6 @@
     <build>
         <plugins>
             <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <inherited>true</inherited>
-                <executions>
-                    <execution>
-                        <id>default-testCompile</id>
-                        <configuration>
-                            <compilerId>groovy-eclipse-compiler</compilerId>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
                 <groupId>org.apache.rat</groupId>
                 <artifactId>apache-rat-plugin</artifactId>
                 <configuration>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/software/base/pom.xml
----------------------------------------------------------------------
diff --git a/software/base/pom.xml b/software/base/pom.xml
index 32bb09b..556e982 100644
--- a/software/base/pom.xml
+++ b/software/base/pom.xml
@@ -72,11 +72,6 @@
         </dependency>
         <dependency>
             <groupId>org.apache.brooklyn</groupId>
-            <artifactId>brooklyn-utils-groovy</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.brooklyn</groupId>
             <artifactId>brooklyn-policy</artifactId>
             <version>${project.version}</version>
         </dependency>
@@ -102,10 +97,6 @@
             <artifactId>gson</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/software/database/pom.xml
----------------------------------------------------------------------
diff --git a/software/database/pom.xml b/software/database/pom.xml
index a48081e..890cbfb 100644
--- a/software/database/pom.xml
+++ b/software/database/pom.xml
@@ -60,20 +60,6 @@
                 </plugin>
             </plugins>
         </pluginManagement>
-        <plugins>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <inherited>true</inherited>
-                <executions>
-                    <execution>
-                        <id>default-testCompile</id>
-                        <configuration>
-                            <compilerId>groovy-eclipse-compiler</compilerId>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
     </build>
     
     <dependencies>
@@ -98,15 +84,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.brooklyn</groupId>
-            <artifactId>brooklyn-utils-groovy</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/software/messaging/pom.xml
----------------------------------------------------------------------
diff --git a/software/messaging/pom.xml b/software/messaging/pom.xml
index 26f9810..38a6ff5 100644
--- a/software/messaging/pom.xml
+++ b/software/messaging/pom.xml
@@ -82,15 +82,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.brooklyn</groupId>
-            <artifactId>brooklyn-utils-common</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/software/nosql/pom.xml
----------------------------------------------------------------------
diff --git a/software/nosql/pom.xml b/software/nosql/pom.xml
index be0887d..4fd2d18 100644
--- a/software/nosql/pom.xml
+++ b/software/nosql/pom.xml
@@ -82,15 +82,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.brooklyn</groupId>
-            <artifactId>brooklyn-utils-groovy</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/software/osgi/pom.xml
----------------------------------------------------------------------
diff --git a/software/osgi/pom.xml b/software/osgi/pom.xml
index e391334..6d6b141 100644
--- a/software/osgi/pom.xml
+++ b/software/osgi/pom.xml
@@ -60,10 +60,6 @@
             <artifactId>guava</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/usage/cli/pom.xml
----------------------------------------------------------------------
diff --git a/usage/cli/pom.xml b/usage/cli/pom.xml
index dbc5d44..92e925d 100644
--- a/usage/cli/pom.xml
+++ b/usage/cli/pom.xml
@@ -70,10 +70,6 @@
             <artifactId>guava</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>javax.inject</groupId>
             <artifactId>javax.inject</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/usage/downstream-parent/pom.xml
----------------------------------------------------------------------
diff --git a/usage/downstream-parent/pom.xml b/usage/downstream-parent/pom.xml
index be889de..974f367 100644
--- a/usage/downstream-parent/pom.xml
+++ b/usage/downstream-parent/pom.xml
@@ -62,7 +62,6 @@
     <jersey.version>1.18.1</jersey.version>
     <httpclient.version>4.4.1</httpclient.version>
     <commons-lang3.version>3.1</commons-lang3.version>
-    <groovy.version>2.3.4</groovy.version> <!-- Version supported by https://github.com/groovy/groovy-eclipse/wiki/Groovy-Eclipse-2.9.0-Release-Notes -->
     <jsr305.version>2.0.1</jsr305.version>
     <snakeyaml.version>1.11</snakeyaml.version>
   </properties>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/usage/launcher/pom.xml
----------------------------------------------------------------------
diff --git a/usage/launcher/pom.xml b/usage/launcher/pom.xml
index 9143e45..24504e0 100644
--- a/usage/launcher/pom.xml
+++ b/usage/launcher/pom.xml
@@ -93,10 +93,6 @@
             <artifactId>concurrentlinkedhashmap-lru</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>com.sun.jersey</groupId>
             <artifactId>jersey-server</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/usage/qa/pom.xml
----------------------------------------------------------------------
diff --git a/usage/qa/pom.xml b/usage/qa/pom.xml
index b4495e6..fd0266d 100644
--- a/usage/qa/pom.xml
+++ b/usage/qa/pom.xml
@@ -61,10 +61,6 @@
             <artifactId>guava</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/usage/rest-server/pom.xml
----------------------------------------------------------------------
diff --git a/usage/rest-server/pom.xml b/usage/rest-server/pom.xml
index 12630bc..28cfc7e 100644
--- a/usage/rest-server/pom.xml
+++ b/usage/rest-server/pom.xml
@@ -76,10 +76,6 @@
         </dependency>
 
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.yaml</groupId>
             <artifactId>snakeyaml</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/usage/test-support/pom.xml
----------------------------------------------------------------------
diff --git a/usage/test-support/pom.xml b/usage/test-support/pom.xml
index f1eca53..4d241d0 100644
--- a/usage/test-support/pom.xml
+++ b/usage/test-support/pom.xml
@@ -59,10 +59,5 @@
             <groupId>org.testng</groupId>
             <artifactId>testng</artifactId>
         </dependency>
-
-        <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/4ba22be8/utils/groovy/pom.xml
----------------------------------------------------------------------
diff --git a/utils/groovy/pom.xml b/utils/groovy/pom.xml
index 07a0736..f25e30f 100644
--- a/utils/groovy/pom.xml
+++ b/utils/groovy/pom.xml
@@ -67,16 +67,4 @@
             <artifactId>groovy-all</artifactId>
         </dependency>
     </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <inherited>true</inherited>
-                <configuration>
-                    <compilerId>groovy-eclipse-compiler</compilerId>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
 </project>


[3/7] incubator-brooklyn git commit: Adjuncts shouldn't mutate passed flags

Posted by al...@apache.org.
Adjuncts shouldn't mutate passed flags

The constructor would mutate the passed in map and even keep reference to it, modifying it on the next .configure call.


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

Branch: refs/heads/master
Commit: de3b706ed24d69c31752a97a4188215c537d41b9
Parents: f69ade3
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Fri Jul 10 18:14:19 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Thu Oct 22 16:33:19 2015 +0300

----------------------------------------------------------------------
 .../core/objs/AbstractEntityAdjunct.java        | 21 ++++----
 .../policy/basic/AbstractEntityAdjunctTest.java | 52 ++++++++++++++++++++
 2 files changed, 61 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/de3b706e/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
index 3fc2839..55b6b16 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/AbstractEntityAdjunct.java
@@ -148,7 +148,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
             if (entry.getKey() instanceof ConfigKey) {
                 ConfigKey key = (ConfigKey)entry.getKey();
                 if (adjunctType.getConfigKeys().contains(key)) {
-                    setConfig(key, entry.getValue());
+                    config().set(key, entry.getValue());
                 } else {
                     log.warn("Unknown configuration key {} for policy {}; ignoring", key, this);
                     iter.remove();
@@ -161,25 +161,20 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
         FlagUtils.setAllConfigKeys(this, bag, false);
         leftoverProperties.putAll(bag.getUnusedConfig());
 
-        //replace properties _contents_ with leftovers so subclasses see leftovers only
-        flags.clear();
-        flags.putAll(leftoverProperties);
-        leftoverProperties = flags;
-        
-        if (!truth(name) && flags.containsKey("displayName")) {
+        if (!truth(name) && leftoverProperties.containsKey("displayName")) {
             //TODO inconsistent with entity and location, where name is legacy and displayName is encouraged!
             //'displayName' is a legacy way to refer to a policy's name
-            Preconditions.checkArgument(flags.get("displayName") instanceof CharSequence, "'displayName' property should be a string");
-            setDisplayName(flags.remove("displayName").toString());
+            Preconditions.checkArgument(leftoverProperties.get("displayName") instanceof CharSequence, "'displayName' property should be a string");
+            setDisplayName(leftoverProperties.remove("displayName").toString());
         }
         
-        // set leftover flags should as config items; particularly useful when these have come from a brooklyn.config map 
-        for (Object flag: flags.keySet()) {
+        // set leftover leftoverProperties should as config items; particularly useful when these have come from a brooklyn.config map 
+        for (Object flag: leftoverProperties.keySet()) {
             ConfigKey<Object> key = ConfigKeys.newConfigKey(Object.class, Strings.toString(flag));
             if (config().getRaw(key).isPresent()) {
                 log.warn("Config '"+flag+"' on "+this+" conflicts with key already set; ignoring");
             } else {
-                config().set(key, flags.get(flag));
+                config().set(key, leftoverProperties.get(flag));
             }
         }
         
@@ -417,6 +412,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
         return getClass().getCanonicalName();
     }
     
+    @Override
     public void setDisplayName(String name) {
         this.name = name;
     }
@@ -560,6 +556,7 @@ public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject imple
         return uniqueTag;
     }
 
+    @Override
     public TagSupport tags() {
         return new AdjunctTagSupport();
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/de3b706e/core/src/test/java/brooklyn/policy/basic/AbstractEntityAdjunctTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/AbstractEntityAdjunctTest.java b/core/src/test/java/brooklyn/policy/basic/AbstractEntityAdjunctTest.java
new file mode 100644
index 0000000..d6d41de
--- /dev/null
+++ b/core/src/test/java/brooklyn/policy/basic/AbstractEntityAdjunctTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.policy.basic;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
+import org.apache.brooklyn.core.objs.AbstractEntityAdjunct;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class AbstractEntityAdjunctTest {
+    private static class TestAdjunct extends AbstractEntityAdjunct {
+        public TestAdjunct(Map<?, ?> properties) {
+            super(properties);
+        }
+ 
+        @Override
+        public RebindSupport<?> getRebindSupport() {
+            return null;
+        }
+
+        @Override
+        protected void onChanged() {
+        }
+    }
+
+    @Test
+    public void testImmutableFlags() {
+        //shouldn't try to mutate passed flags map (or previous references to it)
+        TestAdjunct testAdjunct = new TestAdjunct(ImmutableMap.of("unusedKey", "unusedValue"));
+        testAdjunct.configure(ImmutableMap.of("finalKey", "finalValue"));
+    }
+
+}


[7/7] incubator-brooklyn git commit: This closes #984

Posted by al...@apache.org.
This closes #984


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

Branch: refs/heads/master
Commit: 9a441be8f73f80800b6bac807486959f3881bc4a
Parents: 9a80ebe 4ba22be
Author: Aled Sage <al...@gmail.com>
Authored: Sun Oct 25 22:47:32 2015 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Sun Oct 25 22:47:32 2015 +0000

----------------------------------------------------------------------
 core/pom.xml                                    |  16 +
 .../core/objs/AbstractEntityAdjunct.java        |  21 +-
 .../util/core/BrooklynLanguageExtensions.java   |   2 -
 .../brooklyn/util/core/internal/Repeater.java   |   3 -
 .../policy/basic/AbstractEntityAdjunctTest.java |  52 +++
 ...stomAggregatingEnricherDeprecatedTest.groovy | 368 -----------------
 ...CustomAggregatingEnricherDeprecatedTest.java | 405 +++++++++++++++++++
 .../TransformingEnricherDeprecatedTest.groovy   |  83 ----
 .../TransformingEnricherDeprecatedTest.java     |  92 +++++
 .../util/core/internal/RepeaterTest.groovy      | 256 ------------
 .../util/core/internal/RepeaterTest.java        | 251 ++++++++++++
 examples/simple-web-cluster/pom.xml             |   4 -
 .../demo/WebClusterDatabaseExampleGroovy.groovy |  92 -----
 locations/jclouds/pom.xml                       |  21 -
 .../AwsEc2LocationWindowsLiveTest.groovy        |  94 -----
 .../provider/AwsEc2LocationWindowsLiveTest.java |  95 +++++
 .../provider/CarrenzaLocationLiveTest.groovy    | 132 ------
 .../provider/CarrenzaLocationLiveTest.java      | 135 +++++++
 .../provider/GoGridLocationLiveTest.groovy      |  52 ---
 .../provider/GoGridLocationLiveTest.java        |  52 +++
 parent/pom.xml                                  |  56 +--
 policy/pom.xml                                  |  25 +-
 .../policy/enricher/DeltaEnrichersTests.groovy  | 123 ------
 .../policy/enricher/DeltaEnrichersTests.java    | 144 +++++++
 .../enricher/RollingMeanEnricherTest.groovy     | 105 -----
 .../enricher/RollingMeanEnricherTest.java       | 106 +++++
 .../RollingTimeWindowMeanEnricherTest.groovy    | 155 -------
 .../RollingTimeWindowMeanEnricherTest.java      | 156 +++++++
 sandbox/database/pom.xml                        |  17 -
 .../brooklyn/entity/database/Database.groovy    |  53 ---
 .../brooklyn/entity/database/Database.java      |  42 ++
 .../apache/brooklyn/entity/database/Schema.java |  37 ++
 sandbox/nosql/pom.xml                           |  12 -
 .../Infinispan5ServerIntegrationTest.groovy     | 103 -----
 .../Infinispan5ServerIntegrationTest.java       | 104 +++++
 software/base/pom.xml                           |   9 -
 software/database/pom.xml                       |  23 --
 software/messaging/pom.xml                      |   9 -
 software/nosql/pom.xml                          |   9 -
 .../nosql/couchdb/AbstractCouchDBNodeTest.java  |   5 -
 software/osgi/pom.xml                           |   4 -
 software/webapp/pom.xml                         |  18 -
 .../webapp/WebAppLiveIntegrationTest.groovy     | 101 -----
 .../webapp/WebAppLiveIntegrationTest.java       |  91 +++++
 ...namicWebAppClusterRebindIntegrationTest.java |   3 -
 usage/cli/pom.xml                               |  16 -
 usage/downstream-parent/pom.xml                 |   1 -
 usage/launcher/pom.xml                          |   4 -
 usage/qa/pom.xml                                |   4 -
 usage/rest-server/pom.xml                       |   4 -
 usage/test-support/pom.xml                      |   5 -
 utils/groovy/pom.xml                            |  12 -
 .../util/groovy/FromCallableClosure.java        |  38 ++
 .../util/groovy/FromFunctionClosure.java        |  39 ++
 .../util/groovy/FromRunnableClosure.java        |  46 +++
 .../util/groovy/GroovyJavaMethods.groovy        | 146 -------
 .../brooklyn/util/groovy/GroovyJavaMethods.java | 200 +++++++++
 .../brooklyn/util/groovy/JavadocDummy.java      |  30 --
 .../brooklyn/util/groovy/LanguageUtils.groovy   | 383 ------------------
 .../brooklyn/util/groovy/TimeExtras.groovy      |  83 ----
 .../util/groovy/LanguageUtilsTest.groovy        | 152 -------
 .../brooklyn/util/groovy/TimeExtrasTest.groovy  |  49 ---
 62 files changed, 2131 insertions(+), 2817 deletions(-)
----------------------------------------------------------------------



[2/7] incubator-brooklyn git commit: Convert groovy tests to java

Posted by al...@apache.org.
Convert groovy tests to java


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

Branch: refs/heads/master
Commit: f69ade37a641e1b1997b71986e8a5731b1dccc59
Parents: 24b0f3e
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 22 15:48:07 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Thu Oct 22 16:33:08 2015 +0300

----------------------------------------------------------------------
 ...stomAggregatingEnricherDeprecatedTest.groovy | 368 -----------------
 ...CustomAggregatingEnricherDeprecatedTest.java | 405 +++++++++++++++++++
 .../TransformingEnricherDeprecatedTest.groovy   |  83 ----
 .../TransformingEnricherDeprecatedTest.java     |  92 +++++
 .../util/core/internal/RepeaterTest.groovy      | 256 ------------
 .../util/core/internal/RepeaterTest.java        | 251 ++++++++++++
 .../demo/WebClusterDatabaseExampleGroovy.groovy |  92 -----
 locations/jclouds/pom.xml                       |  21 -
 .../AwsEc2LocationWindowsLiveTest.groovy        |  94 -----
 .../provider/AwsEc2LocationWindowsLiveTest.java |  95 +++++
 .../provider/CarrenzaLocationLiveTest.groovy    | 132 ------
 .../provider/CarrenzaLocationLiveTest.java      | 135 +++++++
 .../provider/GoGridLocationLiveTest.groovy      |  52 ---
 .../provider/GoGridLocationLiveTest.java        |  52 +++
 policy/pom.xml                                  |  25 +-
 .../policy/enricher/DeltaEnrichersTests.groovy  | 123 ------
 .../policy/enricher/DeltaEnrichersTests.java    | 144 +++++++
 .../enricher/RollingMeanEnricherTest.groovy     | 105 -----
 .../enricher/RollingMeanEnricherTest.java       | 106 +++++
 .../RollingTimeWindowMeanEnricherTest.groovy    | 155 -------
 .../RollingTimeWindowMeanEnricherTest.java      | 156 +++++++
 .../brooklyn/entity/database/Database.groovy    |  53 ---
 .../brooklyn/entity/database/Database.java      |  42 ++
 .../apache/brooklyn/entity/database/Schema.java |  37 ++
 .../Infinispan5ServerIntegrationTest.groovy     | 103 -----
 .../Infinispan5ServerIntegrationTest.java       | 107 +++++
 software/webapp/pom.xml                         |  18 -
 .../webapp/WebAppLiveIntegrationTest.groovy     | 101 -----
 .../webapp/WebAppLiveIntegrationTest.java       |  91 +++++
 usage/cli/pom.xml                               |  12 -
 30 files changed, 1715 insertions(+), 1791 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy b/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy
deleted file mode 100644
index 72acb74..0000000
--- a/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy
+++ /dev/null
@@ -1,368 +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 org.apache.brooklyn.enricher.stock
-
-import static org.testng.Assert.assertEquals
-
-import org.apache.brooklyn.api.entity.EntitySpec
-import org.apache.brooklyn.api.sensor.AttributeSensor
-import org.apache.brooklyn.core.test.entity.TestApplication
-import org.apache.brooklyn.core.test.entity.TestEntity
-import org.apache.brooklyn.enricher.stock.CustomAggregatingEnricher;
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.entity.group.BasicGroup
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.core.location.SimulatedLocation
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import com.google.common.base.Function
-
-class CustomAggregatingEnricherDeprecatedTest {
-
-    public static final Logger log = LoggerFactory.getLogger(CustomAggregatingEnricherDeprecatedTest.class);
-            
-    private static final long TIMEOUT_MS = 10*1000
-    private static final long SHORT_WAIT_MS = 250
-    
-    TestApplication app
-    TestEntity producer
-    
-    AttributeSensor<Integer> intSensor
-    AttributeSensor<Integer> target
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() {
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor")
-        target = new BasicAttributeSensor<Integer>(Long.class, "target sensor")
-        
-        app.start([new SimulatedLocation()])
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() {
-        if (app!=null) Entities.destroyAll(app.getManagementContext());
-    }
-    
-    @Test
-    public void testEnrichersWithNoProducers() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher([:], intSensor, target, 11, 40)
-        producer.enrichers().add(cae)
-        assertEquals cae.getAggregate(), 40
-    }
-
-    @Test
-    public void testSummingEnricherWhenNoSensorValuesYet() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, producers:[producer], 11, 40)
-        producer.enrichers().add(cae)
-        assertEquals cae.getAggregate(), 11
-    }
-
-    @Test
-    public void testSingleProducerSum() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, null, null, producers:[producer])
-        producer.enrichers().add(cae)
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producer, 1))
-        assertEquals cae.getAggregate(), 1
-    }
-    
-    @Test
-    public void testSummingEnricherWhenNoAndNullSensorValue() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, null, null, producers:[producer])
-        producer.enrichers().add(cae)
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producer, null))
-        assertEquals cae.getAggregate(), null
-    }
-    
-    @Test
-    public void testSummingEnricherWhenNoAndNullSensorValueExplicitValue() {
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, 3 /** if null */, 5 /** if none */, producers:[producer])
-        producer.enrichers().add(cae)
-        assertEquals cae.getAggregate(), 3
-        cae.onEvent(intSensor.newEvent(producer, null))
-        assertEquals cae.getAggregate(), 3
-        cae.onEvent(intSensor.newEvent(producer, 1))
-        assertEquals cae.getAggregate(), 1
-        cae.onEvent(intSensor.newEvent(producer, 7))
-        assertEquals cae.getAggregate(), 7
-    }
-    
-    @Test
-    public void testMultipleProducersSum() {
-        List<TestEntity> producers = [
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-            intSensor, target, null, null, producers:producers)
-        
-        producer.enrichers().add(cae)
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producers[2], 1))
-        assertEquals cae.getAggregate(), 1
-        cae.onEvent(intSensor.newEvent(producers[0], 3))
-        assertEquals cae.getAggregate(), 4
-        cae.onEvent(intSensor.newEvent(producers[1], 3))
-        assertEquals cae.getAggregate(), 7
-
-    }
-    
-    @Test
-    public void testAveragingEnricherWhenNoAndNullSensorValues() {
-        List<TestEntity> producers = [ 
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null, producers:producers)
-        producer.enrichers().add(cae)
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producers[0], null))
-        assertEquals cae.getAggregate(), null
-    }
-
-    @Test
-    public void testAveragingEnricherWhenNoAndNullSensorValuesExplicit() {
-        List<TestEntity> producers = [
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5 /** if none */,
-                producers:producers)
-        producer.enrichers().add(cae)
-        
-        assertEquals cae.getAggregate(), 3d
-        cae.onEvent(intSensor.newEvent(producers[0], null))
-        assertEquals cae.getAggregate(), 3d
-        cae.onEvent(intSensor.newEvent(producers[0], 4))
-        assertEquals cae.getAggregate(), 4d
-    }
-
-    @Test
-    public void testAveragingEnricherWhenNoSensors() {
-        List<TestEntity> producers = [
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5 /** if none */,
-                producers:producers)
-        producer.enrichers().add(cae)
-        
-        assertEquals cae.getAggregate(), 5d
-    }
-
-    @Test
-    public void testMultipleProducersAverage() {
-        List<TestEntity> producers = [
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null, producers:producers)
-        
-        producer.enrichers().add(cae)
-        
-        assertEquals cae.getAggregate(), null
-        cae.onEvent(intSensor.newEvent(producers[0], 3))
-        assertEquals cae.getAggregate(), 3d
-        
-        cae.onEvent(intSensor.newEvent(producers[1], 3))
-        assertEquals cae.getAggregate(), 3d
-        
-        cae.onEvent(intSensor.newEvent(producers[2], 6))
-        assertEquals cae.getAggregate(), 4d
-
-        // change p2's value to 7.5, average increase of 0.5.
-        cae.onEvent(intSensor.newEvent(producers[2], 7.5))
-        assertEquals cae.getAggregate(), 4.5d
-    }
-    
-    @Test
-    public void testMultipleProducersAverageDefaultingZero() {
-        List<TestEntity> producers = [
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
-                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
-                app.createAndManageChild(EntitySpec.create(TestEntity.class))
-                ]
-        CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
-                intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 0, 0, producers:producers)
-        
-        producer.enrichers().add(cae)
-        
-        assertEquals cae.getAggregate(), 0d
-        cae.onEvent(intSensor.newEvent(producers[0], 3))
-        assertEquals cae.getAggregate(), 1d
-        
-        cae.onEvent(intSensor.newEvent(producers[1], 3))
-        assertEquals cae.getAggregate(), 2d
-        
-        cae.onEvent(intSensor.newEvent(producers[2], 6))
-        assertEquals cae.getAggregate(), 4d
-
-        // change p2's value to 7.5, average increase of 0.5.
-        cae.onEvent(intSensor.newEvent(producers[2], 7.5))
-        assertEquals cae.getAggregate(), 4.5d
-    }
-    
-    @Test
-    public void testAddingAndRemovingProducers() {
-        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
-        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(
-                intSensor, target, null, null, producers:[p1])
-
-        producer.enrichers().add(cae)
-        assertEquals cae.getAggregate(), null
-        
-        // Event by initial producer
-        cae.onEvent(intSensor.newEvent(p1, 1))
-        assertEquals cae.getAggregate(), 1
-        
-        // Add producer and fire event
-        cae.addProducer(p2)
-        cae.onEvent(intSensor.newEvent(p2, 4))
-        assertEquals cae.getAggregate(), 5
-        
-        cae.removeProducer(p2)
-        assertEquals cae.getAggregate(), 1
-    }
-    
-    @Test
-    public void testAggregatesNewMembersOfGroup() {
-        try {
-            BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
-            TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class))
-            TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class))
-            log.debug("created $group and the entities it will contain $p1 $p2")
-
-            CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, 0, 0, allMembers:true)
-            group.enrichers().add(cae)
-
-            assertEquals cae.getAggregate(), 0
-
-            group.addMember(p1)
-            p1.sensors().set(intSensor, 1)
-            Asserts.succeedsEventually(timeout:TIMEOUT_MS) {
-                assertEquals cae.getAggregate(), 1
-            }
-
-            group.addMember(p2)
-            p2.sensors().set(intSensor, 2)
-            Asserts.succeedsEventually(timeout:TIMEOUT_MS) {
-                assertEquals cae.getAggregate(), 3
-            }
-
-            group.removeMember(p2)
-            Asserts.succeedsEventually(timeout:TIMEOUT_MS) {
-                assertEquals cae.getAggregate(), 1
-            }
-        } catch (Exception e) {
-            log.error("testAggregatesNewMembersOfGroup failed (now cleaning up): "+e)
-            throw e;
-        }
-    }
-    
-    @Test(groups = "Integration")
-    public void testAggregatesGroupMembersFiftyTimes() {
-        for (int i=0; i<50; i++) {
-            log.debug "testAggregatesNewMembersOfGroup $i"
-            testAggregatesNewMembersOfGroup();
-        }
-    }
-    
-    @Test
-    public void testAggregatesExistingMembersOfGroup() {
-        BasicGroup group = app.addChild(EntitySpec.create(BasicGroup.class));
-        TestEntity p1 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
-        TestEntity p2 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
-        group.addMember(p1)
-        group.addMember(p2)
-        p1.sensors().set(intSensor, 1)
-        Entities.manage(group);
-        
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, null, null, allMembers:true)
-        group.enrichers().add(cae)
-        
-        assertEquals cae.getAggregate(), 1
-
-        p2.sensors().set(intSensor, 2)
-        Asserts.succeedsEventually(timeout:TIMEOUT_MS) {
-            assertEquals cae.getAggregate(), 3
-        }
-        
-        group.removeMember(p2)
-        Asserts.succeedsEventually(timeout:TIMEOUT_MS) {
-            assertEquals cae.getAggregate(), 1
-        }
-    }
-    
-    @Test
-    public void testAppliesFilterWhenAggregatingMembersOfGroup() {
-        BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
-        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        TestEntity p3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        group.addMember(p1)
-        group.addMember(p2)
-        p1.sensors().set(intSensor, 1)
-        p2.sensors().set(intSensor, 2)
-        p3.sensors().set(intSensor, 4)
-        
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, null, null, allMembers:true, filter:{it == p1})
-        group.enrichers().add(cae)
-        
-        assertEquals cae.getAggregate(), 1
-        
-        group.addMember(p3)
-        Asserts.succeedsContinually(timeout:SHORT_WAIT_MS) {
-            assertEquals cae.getAggregate(), 1
-        }
-    }
-    
-    @Test
-    public void testCustomAggregatingFunction() {
-        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
-        Function<Collection<Integer>,Integer> aggregator = { Collection c -> 
-            int result = 0; c.each { result += it*it }; return result;
-        } as Function
-         
-        CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newEnricher(
-                intSensor, target, aggregator, 0, producers:[p1])
-
-        producer.enrichers().add(cae)
-        assertEquals cae.getAggregate(), 0
-        
-        // Event by producer
-        cae.onEvent(intSensor.newEvent(p1, 2))
-        assertEquals cae.getAggregate(), 4
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.java
new file mode 100644
index 0000000..5f3e8b5
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.java
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.enricher.stock;
+
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.entity.group.BasicGroup;
+import org.apache.brooklyn.test.Asserts;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+@SuppressWarnings("deprecation")
+public class CustomAggregatingEnricherDeprecatedTest {
+
+    public static final Logger log = LoggerFactory.getLogger(CustomAggregatingEnricherDeprecatedTest.class);
+            
+    private static final long TIMEOUT_MS = 10*1000;
+    private static final long SHORT_WAIT_MS = 250;
+    
+    TestApplication app;
+    TestEntity producer;
+    Map<String, ?> producersFlags;
+    
+    AttributeSensor<Integer> intSensor = Sensors.newIntegerSensor("int sensor");
+    AttributeSensor<Double> doubleSensor = Sensors.newDoubleSensor("double sensor");
+    AttributeSensor<Integer> target = Sensors.newIntegerSensor("target sensor");
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        producersFlags = ImmutableMap.of("producers", ImmutableList.of(producer));
+        
+        app.start(ImmutableList.of(new SimulatedLocation()));
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() {
+        if (app!=null) Entities.destroyAll(app.getManagementContext());
+    }
+    
+    @Test
+    public void testEnrichersWithNoProducers() {
+        CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(ImmutableMap.<String,Object>of(), intSensor, target, 11, 40);
+        producer.enrichers().add(cae);
+        assertEquals(cae.getAggregate(), 40);
+    }
+
+    @Test
+    public void testSummingEnricherWhenNoSensorValuesYet() {
+        CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(
+                producersFlags, intSensor, target, 11, 40);
+        producer.enrichers().add(cae);
+        assertEquals(cae.getAggregate(), 11);
+    }
+
+    @Test
+    public void testSingleProducerSum() {
+        CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(
+                producersFlags, intSensor, target, null, null);
+        producer.enrichers().add(cae);
+        Assert.assertEquals(cae.getAggregate(), null);
+        cae.onEvent(intSensor.newEvent(producer, 1));
+        assertEquals(cae.getAggregate(), 1);
+    }
+    
+    @Test
+    public void testSummingEnricherWhenNoAndNullSensorValue() {
+        CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(
+                producersFlags, intSensor, target, null, null);
+        producer.enrichers().add(cae);
+        Assert.assertEquals(cae.getAggregate(), null);
+        cae.onEvent(intSensor.newEvent(producer, null));
+        Assert.assertEquals(cae.getAggregate(), null);
+    }
+    
+    @Test
+    public void testSummingEnricherWhenNoAndNullSensorValueExplicitValue() {
+        CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(
+                producersFlags, intSensor, target, 3 /** if null */, 5 /** if none */);
+        producer.enrichers().add(cae);
+        assertEquals(cae.getAggregate(), 3);
+        cae.onEvent(intSensor.newEvent(producer, null));
+        assertEquals(cae.getAggregate(), 3);
+        cae.onEvent(intSensor.newEvent(producer, 1));
+        assertEquals(cae.getAggregate(), 1);
+        cae.onEvent(intSensor.newEvent(producer, 7));
+        assertEquals(cae.getAggregate(), 7);
+    }
+    
+    @Test
+    public void testMultipleProducersSum() {
+        List<TestEntity> producers = ImmutableList.of(
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                );
+        CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(
+                ImmutableMap.of("producers", producers), intSensor, target, null, null);
+        
+        producer.enrichers().add(cae);
+        Assert.assertEquals(cae.getAggregate(), null);
+        cae.onEvent(intSensor.newEvent(producers.get(2), 1));
+        assertEquals(cae.getAggregate(), 1);
+        cae.onEvent(intSensor.newEvent(producers.get(0), 3));
+        assertEquals(cae.getAggregate(), 4);
+        cae.onEvent(intSensor.newEvent(producers.get(1), 3));
+        assertEquals(cae.getAggregate(), 7);
+
+    }
+    
+    @Test
+    public void testAveragingEnricherWhenNoAndNullSensorValues() {
+        List<TestEntity> producers = ImmutableList.of(
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                );
+        CustomAggregatingEnricher<Integer, Double> cae = CustomAggregatingEnricher.<Integer>newAveragingEnricher(
+                ImmutableMap.of("producers", producers), intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null);
+        producer.enrichers().add(cae);
+        Assert.assertEquals(cae.getAggregate(), null);
+        cae.onEvent(intSensor.newEvent(producers.get(0), null));
+        Assert.assertEquals(cae.getAggregate(), null);
+    }
+
+    @Test
+    public void testAveragingEnricherWhenNoAndNullSensorValuesExplicit() {
+        List<TestEntity> producers = ImmutableList.of(
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                );
+        CustomAggregatingEnricher<Integer, Double> cae = CustomAggregatingEnricher.<Integer>newAveragingEnricher(
+                ImmutableMap.of("producers", producers), intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5d /** if none */);
+        producer.enrichers().add(cae);
+        
+        assertEquals(cae.getAggregate(), 3d);
+        cae.onEvent(intSensor.newEvent(producers.get(0), null));
+        assertEquals(cae.getAggregate(), 3d);
+        cae.onEvent(intSensor.newEvent(producers.get(0), 4));
+        assertEquals(cae.getAggregate(), 4d);
+    }
+
+    @Test
+    public void testAveragingEnricherWhenNoSensors() {
+        List<TestEntity> producers = ImmutableList.of(
+                );
+        CustomAggregatingEnricher<Integer, Double> cae = CustomAggregatingEnricher.<Integer>newAveragingEnricher(
+                ImmutableMap.of("producers", producers), intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5d /** if none */);
+        producer.enrichers().add(cae);
+        
+        assertEquals(cae.getAggregate(), 5d);
+    }
+
+    @Test
+    public void testMultipleProducersAverage() {
+        List<TestEntity> producers = ImmutableList.of(
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                );
+        CustomAggregatingEnricher<Double, Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
+                ImmutableMap.of("producers", producers),
+                doubleSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null);
+        
+        producer.enrichers().add(cae);
+        
+        Assert.assertEquals(cae.getAggregate(), null);
+        cae.onEvent(doubleSensor.newEvent(producers.get(0), 3d));
+        assertEquals(cae.getAggregate(), 3d);
+        
+        cae.onEvent(doubleSensor.newEvent(producers.get(1), 3d));
+        assertEquals(cae.getAggregate(), 3d);
+        
+        cae.onEvent(doubleSensor.newEvent(producers.get(2), 6d));
+        assertEquals(cae.getAggregate(), 4d);
+
+        // change p2's value to 7.5, average increase of 0.5.
+        cae.onEvent(doubleSensor.newEvent(producers.get(2), 7.5d));
+        assertEquals(cae.getAggregate(), 4.5d);
+    }
+    
+    @Test
+    public void testMultipleProducersAverageDefaultingZero() {
+        List<TestEntity> producers = ImmutableList.of(
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)), 
+                app.createAndManageChild(EntitySpec.create(TestEntity.class)),
+                app.createAndManageChild(EntitySpec.create(TestEntity.class))
+                );
+        CustomAggregatingEnricher<Double, Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher(
+                ImmutableMap.of("producers", producers),
+                doubleSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 0d, 0d);
+        
+        producer.enrichers().add(cae);
+        
+        assertEquals(cae.getAggregate(), 0d);
+        cae.onEvent(doubleSensor.newEvent(producers.get(0), 3d));
+        assertEquals(cae.getAggregate(), 1d);
+        
+        cae.onEvent(doubleSensor.newEvent(producers.get(1), 3d));
+        assertEquals(cae.getAggregate(), 2d);
+        
+        cae.onEvent(doubleSensor.newEvent(producers.get(2), 6d));
+        assertEquals(cae.getAggregate(), 4d);
+
+        // change p2's value to 7.5, average increase of 0.5.
+        cae.onEvent(doubleSensor.newEvent(producers.get(2), 7.5d));
+        assertEquals(cae.getAggregate(), 4.5d);
+    }
+    
+    @Test
+    public void testAddingAndRemovingProducers() {
+        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
+        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        
+        CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(
+                ImmutableMap.of("producers", ImmutableList.of(p1)),
+                intSensor, target, null, null);
+
+        producer.enrichers().add(cae);
+        Assert.assertEquals(cae.getAggregate(), null);
+        
+        // Event by initial producer
+        cae.onEvent(intSensor.newEvent(p1, 1));
+        assertEquals(cae.getAggregate(), 1);
+        
+        // Add producer and fire event
+        cae.addProducer(p2);
+        cae.onEvent(intSensor.newEvent(p2, 4));
+        assertEquals(cae.getAggregate(), 5);
+        
+        cae.removeProducer(p2);
+        assertEquals(cae.getAggregate(), 1);
+    }
+    
+    @Test
+    public void testAggregatesNewMembersOfGroup() {
+        try {
+            BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
+            TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+            TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+            log.debug("created $group and the entities it will contain $p1 $p2");
+
+            CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(
+                    ImmutableMap.of("allMembers", true),
+                    intSensor, target, 0, 0);
+            group.enrichers().add(cae);
+
+            assertEquals(cae.getAggregate(), 0);
+
+            group.addMember(p1);
+            p1.sensors().set(intSensor, 1);
+            aggregateIsEventually(cae, 1);
+
+            group.addMember(p2);
+            p2.sensors().set(intSensor, 2);
+            aggregateIsEventually(cae, 3);
+
+            group.removeMember(p2);
+            aggregateIsEventually(cae, 1);
+        } catch (Exception e) {
+            log.error("testAggregatesNewMembersOfGroup failed (now cleaning up): "+e);
+            throw e;
+        }
+    }
+    
+    @Test(groups = "Integration")
+    public void testAggregatesGroupMembersFiftyTimes() {
+        for (int i=0; i<50; i++) {
+            log.debug("testAggregatesNewMembersOfGroup $i");
+            testAggregatesNewMembersOfGroup();
+        }
+    }
+    
+    @Test
+    public void testAggregatesExistingMembersOfGroup() {
+        BasicGroup group = app.addChild(EntitySpec.create(BasicGroup.class));
+        TestEntity p1 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
+        TestEntity p2 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); 
+        group.addMember(p1);
+        group.addMember(p2);
+        p1.sensors().set(intSensor, 1);
+        Entities.manage(group);
+        
+        CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(
+                ImmutableMap.of("allMembers", true),
+                intSensor, target, null, null);
+        group.enrichers().add(cae);
+        
+        assertEquals(cae.getAggregate(), 1);
+
+        p2.sensors().set(intSensor, 2);
+        aggregateIsEventually(cae, 3);
+        
+        group.removeMember(p2);
+        aggregateIsEventually(cae, 1);
+    }
+    
+    @Test
+    public void testAppliesFilterWhenAggregatingMembersOfGroup() {
+        BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class));
+        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        TestEntity p3 = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        group.addMember(p1);
+        group.addMember(p2);
+        p1.sensors().set(intSensor, 1);
+        p2.sensors().set(intSensor, 2);
+        p3.sensors().set(intSensor, 4);
+        
+        final CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newSummingEnricher(
+                ImmutableMap.of("allMembers", true, "filter", Predicates.equalTo(p1)),
+                intSensor, target, null, null);
+        group.enrichers().add(cae);
+        
+        assertEquals(cae.getAggregate(), 1);
+        
+        group.addMember(p3);
+        Asserts.succeedsContinually(ImmutableMap.of("timeout", SHORT_WAIT_MS), new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(cae.getAggregate(), 1);
+            }
+        });
+    }
+    
+    @Test
+    public void testCustomAggregatingFunction() {
+        TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); 
+        Function<Collection<Integer>,Integer> aggregator = new Function<Collection<Integer>, Integer>() {
+            @Override
+            public Integer apply(Collection<Integer> c) {
+                int result = 0;
+                for (Integer it : c) {
+                    result += it*it;
+                }
+                return result;
+            }
+        };
+
+        CustomAggregatingEnricher<Integer, Integer> cae = CustomAggregatingEnricher.<Integer, Integer>newEnricher(
+                ImmutableMap.of("producers", ImmutableList.of(p1)),
+                intSensor, target, aggregator, 0);
+
+        producer.enrichers().add(cae);
+        assertEquals(cae.getAggregate(), 0);
+
+        // Event by producer
+        cae.onEvent(intSensor.newEvent(p1, 2));
+        assertEquals(cae.getAggregate(), 4);
+    }
+
+
+    private void assertEquals(Integer i1, int i2) {
+        Assert.assertEquals(i1, (Integer)i2);
+     }
+    private void assertEquals(Double i1, double i2) {
+        Assert.assertEquals(i1, (Double)i2);
+    }
+
+    private void aggregateIsEventually(final CustomAggregatingEnricher<Integer, Integer> cae, final int avg) {
+        ImmutableMap<String, Long> timeout = ImmutableMap.of("timeout", TIMEOUT_MS);
+
+        Asserts.succeedsEventually(timeout, new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(cae.getAggregate(), avg);
+            }
+        });
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.groovy b/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.groovy
deleted file mode 100644
index 9d4952d..0000000
--- a/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.groovy
+++ /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 org.apache.brooklyn.enricher.stock
-
-import java.util.concurrent.Callable
-
-import org.apache.brooklyn.api.entity.EntitySpec
-import org.apache.brooklyn.api.sensor.AttributeSensor
-import org.apache.brooklyn.core.test.entity.TestApplication
-import org.apache.brooklyn.core.test.entity.TestEntity
-import org.apache.brooklyn.enricher.stock.SensorTransformingEnricher;
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.core.location.SimulatedLocation
-import org.apache.brooklyn.core.sensor.BasicAttributeSensor
-import org.apache.brooklyn.test.Asserts;
-import org.apache.brooklyn.util.collections.MutableMap
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.Assert
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-public class TransformingEnricherDeprecatedTest {
-
-    public static final Logger log = LoggerFactory.getLogger(TransformingEnricherDeprecatedTest.class);
-            
-    private static final long TIMEOUT_MS = 10*1000;
-//    private static final long SHORT_WAIT_MS = 250;
-    
-    TestApplication app;
-    TestEntity producer;
-    AttributeSensor<Integer> intSensorA;
-    AttributeSensor<Long> target;
-
-    @BeforeMethod()
-    public void before() {
-        app = TestApplication.Factory.newManagedInstanceForTests();
-        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        intSensorA = new BasicAttributeSensor<Integer>(Integer.class, "int.sensor.a");
-        target = new BasicAttributeSensor<Long>(Long.class, "long.sensor.target");
-        
-        app.start(Arrays.asList(new SimulatedLocation()));
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void after() {
-        if (app!=null) Entities.destroyAll(app.getManagementContext());
-    }
-    
-    @Test
-    public void testTransformingEnricher() throws InterruptedException {
-        final SensorTransformingEnricher e1 = new SensorTransformingEnricher<Integer,Long>(intSensorA, target, 
-            { 2*it });
-        
-        producer.sensors().set(intSensorA, 3);
-        //ensure previous values get picked up
-        producer.enrichers().add(e1);
-
-        Asserts.succeedsEventually(MutableMap.of("timeout", TIMEOUT_MS), 
-                new Callable<Object>() { public Object call() {
-                    Assert.assertEquals(producer.getAttribute(target), (Long)((long)6));
-                    return null;
-                }});
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.java b/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.java
new file mode 100644
index 0000000..e52ff45
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/TransformingEnricherDeprecatedTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.enricher.stock;
+
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
+import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+
+@SuppressWarnings("deprecation")
+public class TransformingEnricherDeprecatedTest {
+
+    public static final Logger log = LoggerFactory.getLogger(TransformingEnricherDeprecatedTest.class);
+            
+    private static final long TIMEOUT_MS = 10*1000;
+//    private static final long SHORT_WAIT_MS = 250;
+    
+    TestApplication app;
+    TestEntity producer;
+    AttributeSensor<Integer> intSensorA;
+    AttributeSensor<Long> target;
+
+    @BeforeMethod()
+    public void before() {
+        app = TestApplication.Factory.newManagedInstanceForTests();
+        producer = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        intSensorA = new BasicAttributeSensor<Integer>(Integer.class, "int.sensor.a");
+        target = new BasicAttributeSensor<Long>(Long.class, "long.sensor.target");
+        
+        app.start(Arrays.asList(new SimulatedLocation()));
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void after() {
+        if (app!=null) Entities.destroyAll(app.getManagementContext());
+    }
+    
+    @Test
+    public void testTransformingEnricher() throws InterruptedException {
+        final SensorTransformingEnricher<Integer, Long> e1 = new SensorTransformingEnricher<Integer,Long>(intSensorA, target, new DoubleFn());
+        
+        producer.sensors().set(intSensorA, 3);
+        //ensure previous values get picked up
+        producer.enrichers().add(e1);
+
+        Asserts.succeedsEventually(MutableMap.of("timeout", TIMEOUT_MS), new Callable<Object>() { 
+                @Override
+                public Object call() {
+                    Assert.assertEquals(producer.getAttribute(target), (Long)((long)6));
+                    return null;
+                }});
+    }
+
+    private static class DoubleFn implements Function<Integer, Long> {
+        @Override
+        public Long apply(Integer i) {
+            return ((long)i)*2;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy b/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy
deleted file mode 100644
index 5eae3c9..0000000
--- a/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.groovy
+++ /dev/null
@@ -1,256 +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 org.apache.brooklyn.util.core.internal
-
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit
-
-import org.testng.annotations.Test
-import org.apache.brooklyn.util.core.internal.Repeater
-import org.apache.brooklyn.util.groovy.TimeExtras;
-import org.apache.brooklyn.util.time.Duration;
-
-import com.google.common.base.Stopwatch
-
-public class RepeaterTest {
-    static { TimeExtras.init() }
-
-    @Test
-    public void sanityTest() {
-        new Repeater("Sanity test")
-            .repeat()
-            .until { true }
-            .every(10 * MILLISECONDS);
-    }
-
-    @Test
-    public void sanityTestDescription() {
-        new Repeater()
-            .repeat()
-            .until { true }
-            .every(10 * MILLISECONDS);
-    }
-
-    @Test
-    public void sanityTestBuilder() {
-        Repeater.create("Sanity test")
-            .repeat()
-            .until { true }
-            .every(10 * MILLISECONDS);
-    }
-
-    @Test
-    public void sanityTestBuilderDescription() {
-        Repeater.create()
-            .repeat()
-            .until { true }
-            .every(10 * MILLISECONDS);
-    }
-
-    @Test(expectedExceptions = [ NullPointerException.class ])
-    public void repeatFailsIfClosureIsNull() {
-        new Repeater("repeatFailsIfClosureIsNull").repeat((Callable<?>)null);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void repeatSucceedsIfClosureIsNonNull() {
-        new Repeater("repeatSucceedsIfClosureIsNonNull").repeat { true };
-    }
-
-    @Test(expectedExceptions = [ NullPointerException.class ])
-    public void untilFailsIfClosureIsNull() {
-        new Repeater("untilFailsIfClosureIsNull").until(null);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void untilSucceedsIfClosureIsNonNull() {
-        new Repeater("untilSucceedsIfClosureIsNonNull").until { true };
-    }
-
-    @Test(expectedExceptions = [ IllegalArgumentException.class ])
-    public void everyFailsIfPeriodIsZero() {
-        new Repeater("everyFailsIfPeriodIsZero").every(0 * MILLISECONDS);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ IllegalArgumentException.class ])
-    public void everyFailsIfPeriodIsNegative() {
-        new Repeater("everyFailsIfPeriodIsNegative").every(-1 * MILLISECONDS);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ NullPointerException.class ])
-    public void everyFailsIfUnitsIsNull() {
-        new Repeater("everyFailsIfUnitsIsNull").every(10, null);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void everySucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
-        new Repeater("repeatSucceedsIfClosureIsNonNull").every(10 * MILLISECONDS);
-    }
-
-    @Test(expectedExceptions = [ IllegalArgumentException.class ])
-    public void limitTimeToFailsIfPeriodIsZero() {
-        new Repeater("limitTimeToFailsIfPeriodIsZero").limitTimeTo(0, TimeUnit.MILLISECONDS);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ IllegalArgumentException.class ])
-    public void limitTimeToFailsIfPeriodIsNegative() {
-        new Repeater("limitTimeToFailsIfPeriodIsNegative").limitTimeTo(-1, TimeUnit.MILLISECONDS);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ NullPointerException.class ])
-    public void limitTimeToFailsIfUnitsIsNull() {
-        new Repeater("limitTimeToFailsIfUnitsIsNull").limitTimeTo(10, null);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void limitTimeToSucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
-        new Repeater("limitTimeToSucceedsIfClosureIsNonNull").limitTimeTo(10, TimeUnit.MILLISECONDS);
-    }
-
-    @Test
-    public void everyAcceptsDuration() {
-        new Repeater("everyAcceptsDuration").every(Duration.ONE_SECOND);
-    }
-
-    @Test
-    public void everyAcceptsLong() {
-        new Repeater("everyAcceptsLong").every(1000L);
-    }
-
-    @Test
-    public void everyAcceptsTimeUnit() {
-        new Repeater("everyAcceptsTimeUnit").every(1000000L, TimeUnit.MICROSECONDS);
-    }
-
-    @Test
-    public void runReturnsTrueIfExitConditionIsTrue() {
-        assertTrue new Repeater("runReturnsTrueIfExitConditionIsTrue")
-            .repeat()
-            .every(1 * MILLISECONDS)
-            .until { true }
-            .run();
-    }
-
-    @Test
-    public void runRespectsMaximumIterationLimitAndReturnsFalseIfReached() {
-        int iterations = 0;
-        assertFalse new Repeater("runRespectsMaximumIterationLimitAndReturnsFalseIfReached")
-            .repeat { iterations++ }
-            .every(1 * MILLISECONDS)
-            .until { false }
-            .limitIterationsTo(5)
-            .run();
-        assertEquals 5, iterations;
-    }
-
-    /**
-     * Check that the {@link Repeater} will stop after a time limit.
-     *
-     * The repeater is configured to run every 100ms and never stop until the limit is reached.
-     * This is given as {@link Repeater#limitTimeTo(groovy.time.Duration)} and the execution time
-     * is then checked to ensure it is between 100% and 400% of the specified value. Due to scheduling
-     * delays and other factors in a non RTOS system it is expected that the repeater will take much
-     * longer to exit occasionally.
-     *
-     * @see #runRespectsMaximumIterationLimitAndReturnsFalseIfReached()
-     */
-    @Test(groups="Integration")
-    public void runRespectsTimeLimitAndReturnsFalseIfReached() {
-        final long LIMIT = 2000l;
-        Repeater repeater = new Repeater("runRespectsTimeLimitAndReturnsFalseIfReached")
-            .repeat()
-            .every(100 * MILLISECONDS)
-            .until { false }
-            .limitTimeTo(LIMIT, TimeUnit.MILLISECONDS);
-
-        Stopwatch stopwatch = new Stopwatch().start();
-        boolean result = repeater.run();
-        stopwatch.stop();
-
-        assertFalse result;
-
-        long difference = stopwatch.elapsed(TimeUnit.MILLISECONDS);
-        assertTrue(difference >= LIMIT, "Difference was: " + difference);
-        assertTrue(difference < 4 * LIMIT, "Difference was: " + difference);
-    }
-
-    @Test(expectedExceptions = [ IllegalStateException.class ])
-    public void runFailsIfUntilWasNotSet() {
-        new Repeater("runFailsIfUntilWasNotSet")
-            .repeat()
-            .every(10 * MILLISECONDS)
-            .run();
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ IllegalStateException.class ])
-    public void runFailsIfEveryWasNotSet() {
-        new Repeater("runFailsIfEveryWasNotSet")
-            .repeat()
-            .until { true }
-            .run();
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ UnsupportedOperationException.class ])
-    public void testRethrowsException() {
-        boolean result = new Repeater("throwRuntimeException")
-            .repeat()
-            .every(10 * MILLISECONDS)
-            .until { throw new UnsupportedOperationException("fail") }
-            .rethrowException()
-            .limitIterationsTo(2)
-            .run();
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void testNoRethrowsException() {
-        try {
-	        boolean result = new Repeater("throwRuntimeException")
-	            .repeat()
-	            .every(10 * MILLISECONDS)
-	            .until { throw new UnsupportedOperationException("fail") }
-	            .limitIterationsTo(2)
-	            .run();
-	        assertFalse result
-        } catch (RuntimeException re) {
-            fail "Exception should not have been thrown: " + re.getMessage()
-        }
-    }
-	
-	public void testFlags() {
-		int count=0;
-		new Repeater(period: 5*MILLISECONDS, timeout: 100*MILLISECONDS).repeat({ count++ }).until({ count>100}).run();
-		assertTrue count>10
-		assertTrue count<30
-	}
-	
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.java b/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.java
new file mode 100644
index 0000000..de26857
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/util/core/internal/RepeaterTest.java
@@ -0,0 +1,251 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.core.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.util.time.Duration;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Callables;
+
+@SuppressWarnings("deprecation")
+public class RepeaterTest {
+
+    @Test
+    public void sanityTest() {
+        new Repeater("Sanity test")
+            .repeat()
+            .until(Callables.returning(true))
+            .every(Duration.millis(10));
+    }
+
+    @Test
+    public void sanityTestDescription() {
+        new Repeater()
+            .repeat()
+            .until(Callables.returning(true))
+            .every(Duration.millis(10));
+    }
+
+    @Test
+    public void sanityTestBuilder() {
+        Repeater.create("Sanity test")
+            .repeat()
+            .until(Callables.returning(true))
+            .every(Duration.millis(10));
+    }
+
+    @Test
+    public void sanityTestBuilderDescription() {
+        Repeater.create()
+            .repeat()
+            .until(Callables.returning(true))
+            .every(Duration.millis(10));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void repeatFailsIfClosureIsNull() {
+        new Repeater("repeatFailsIfClosureIsNull").repeat((Callable<?>)null);
+    }
+
+    @Test
+    public void repeatSucceedsIfClosureIsNonNull() {
+        new Repeater("repeatSucceedsIfClosureIsNonNull").repeat(Callables.returning(true));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void untilFailsIfClosureIsNull() {
+        new Repeater("untilFailsIfClosureIsNull").until(null);
+    }
+
+    @Test
+    public void untilSucceedsIfClosureIsNonNull() {
+        new Repeater("untilSucceedsIfClosureIsNonNull").until(Callables.returning(true));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void everyFailsIfPeriodIsZero() {
+        new Repeater("everyFailsIfPeriodIsZero").every(Duration.ZERO);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void everyFailsIfPeriodIsNegative() {
+        new Repeater("everyFailsIfPeriodIsNegative").every(Duration.millis(-1));
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void everyFailsIfUnitsIsNull() {
+        new Repeater("everyFailsIfUnitsIsNull").every(10, null);
+    }
+
+    @Test
+    public void everySucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
+        new Repeater("repeatSucceedsIfClosureIsNonNull").every(Duration.millis(10));
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void limitTimeToFailsIfPeriodIsZero() {
+        new Repeater("limitTimeToFailsIfPeriodIsZero").limitTimeTo(0, TimeUnit.MILLISECONDS);
+    }
+
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void limitTimeToFailsIfPeriodIsNegative() {
+        new Repeater("limitTimeToFailsIfPeriodIsNegative").limitTimeTo(-1, TimeUnit.MILLISECONDS);
+    }
+
+    @Test(expectedExceptions = NullPointerException.class)
+    public void limitTimeToFailsIfUnitsIsNull() {
+        new Repeater("limitTimeToFailsIfUnitsIsNull").limitTimeTo(10, null);
+    }
+
+    @Test
+    public void limitTimeToSucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
+        new Repeater("limitTimeToSucceedsIfClosureIsNonNull").limitTimeTo(10, TimeUnit.MILLISECONDS);
+    }
+
+    @Test
+    public void everyAcceptsDuration() {
+        new Repeater("everyAcceptsDuration").every(Duration.ONE_SECOND);
+    }
+
+    @Test
+    public void everyAcceptsLong() {
+        new Repeater("everyAcceptsLong").every(1000L);
+    }
+
+    @Test
+    public void everyAcceptsTimeUnit() {
+        new Repeater("everyAcceptsTimeUnit").every(1000000L, TimeUnit.MICROSECONDS);
+    }
+
+    @Test
+    public void runReturnsTrueIfExitConditionIsTrue() {
+        assertTrue(new Repeater("runReturnsTrueIfExitConditionIsTrue")
+            .repeat()
+            .every(Duration.millis(1))
+            .until(Callables.returning(true))
+            .run());
+    }
+
+    @Test
+    public void runRespectsMaximumIterationLimitAndReturnsFalseIfReached() {
+        final AtomicInteger iterations = new AtomicInteger();
+        assertFalse(new Repeater("runRespectsMaximumIterationLimitAndReturnsFalseIfReached")
+            .repeat(new Runnable() {@Override public void run() {iterations.incrementAndGet();}})
+            .every(Duration.millis(1))
+            .until(Callables.returning(false))
+            .limitIterationsTo(5)
+            .run());
+        assertEquals(iterations.get(), 5);
+    }
+
+    /**
+     * Check that the {@link Repeater} will stop after a time limit.
+     *
+     * The repeater is configured to run every 100ms and never stop until the limit is reached.
+     * This is given as {@link Repeater#limitTimeTo(groovy.time.Duration)} and the execution time
+     * is then checked to ensure it is between 100% and 400% of the specified value. Due to scheduling
+     * delays and other factors in a non RTOS system it is expected that the repeater will take much
+     * longer to exit occasionally.
+     *
+     * @see #runRespectsMaximumIterationLimitAndReturnsFalseIfReached()
+     */
+    @Test(groups="Integration")
+    public void runRespectsTimeLimitAndReturnsFalseIfReached() {
+        final long LIMIT = 2000l;
+        Repeater repeater = new Repeater("runRespectsTimeLimitAndReturnsFalseIfReached")
+            .repeat()
+            .every(Duration.millis(100))
+            .until(Callables.returning(false))
+            .limitTimeTo(LIMIT, TimeUnit.MILLISECONDS);
+
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        boolean result = repeater.run();
+        stopwatch.stop();
+
+        assertFalse(result);
+
+        long difference = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+        assertTrue(difference >= LIMIT, "Difference was: " + difference);
+        assertTrue(difference < 4 * LIMIT, "Difference was: " + difference);
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void runFailsIfUntilWasNotSet() {
+        new Repeater("runFailsIfUntilWasNotSet")
+            .repeat()
+            .every(Duration.millis(10))
+            .run();
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public void runFailsIfEveryWasNotSet() {
+        new Repeater("runFailsIfEveryWasNotSet")
+            .repeat()
+            .until(Callables.returning(true))
+            .run();
+    }
+
+    @Test(expectedExceptions = UnsupportedOperationException.class)
+    public void testRethrowsException() {
+        new Repeater("throwRuntimeException")
+            .repeat()
+            .every(Duration.millis(10))
+            .until(new Callable<Boolean>() {@Override public Boolean call() {throw new UnsupportedOperationException("fail"); }})
+            .rethrowException()
+            .limitIterationsTo(2)
+            .run();
+    }
+
+    @Test
+    public void testNoRethrowsException() {
+        try {
+            boolean result = new Repeater("throwRuntimeException")
+                .repeat()
+                .every(Duration.millis(10))
+                .until(new Callable<Boolean>() {@Override public Boolean call() {throw new UnsupportedOperationException("fail"); }})
+                .limitIterationsTo(2)
+                .run();
+            assertFalse(result);
+        } catch (RuntimeException re) {
+            fail("Exception should not have been thrown: " + re.getMessage(), re);
+        }
+    }
+    
+    public void testFlags() {
+        final AtomicInteger count = new AtomicInteger();
+        new Repeater(ImmutableMap.of("period", Duration.millis(5), "timeout", Duration.millis(100)))
+                .repeat(new Runnable() {@Override public void run() {count.incrementAndGet();}})
+                .until(new Callable<Boolean>() { @Override public Boolean call() {return count.get() > 0;}})
+                .run();
+        assertTrue(count.get()>10);
+        assertTrue(count.get()<30);
+    }
+    
+}

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

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/locations/jclouds/pom.xml
----------------------------------------------------------------------
diff --git a/locations/jclouds/pom.xml b/locations/jclouds/pom.xml
index ed10132..3338893 100644
--- a/locations/jclouds/pom.xml
+++ b/locations/jclouds/pom.xml
@@ -85,10 +85,6 @@
             <artifactId>httpclient</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.codehaus.groovy</groupId>
-            <artifactId>groovy-all</artifactId>
-        </dependency>
-        <dependency>
             <groupId>javax.annotation</groupId>
             <artifactId>jsr250-api</artifactId>
         </dependency>
@@ -199,21 +195,4 @@
             <scope>test</scope>
         </dependency>
     </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <inherited>true</inherited>
-                <executions>
-                    <execution>
-                        <id>default-testCompile</id>
-                        <configuration>
-                            <compilerId>groovy-eclipse-compiler</compilerId>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
 </project>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationWindowsLiveTest.groovy
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationWindowsLiveTest.groovy b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationWindowsLiveTest.groovy
deleted file mode 100644
index 6a04784..0000000
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationWindowsLiveTest.groovy
+++ /dev/null
@@ -1,94 +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 org.apache.brooklyn.location.jclouds.provider;
-
-import static org.testng.Assert.*
-
-import org.apache.brooklyn.api.mgmt.ManagementContext
-import org.apache.brooklyn.core.entity.Entities
-import org.apache.brooklyn.location.jclouds.JcloudsLocation
-import org.apache.brooklyn.location.jclouds.JcloudsSshMachineLocation
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import com.google.common.collect.ImmutableMap
-
-public class AwsEc2LocationWindowsLiveTest {
-    private static final Logger LOG = LoggerFactory.getLogger(AwsEc2LocationWindowsLiveTest.class)
-    
-    private static final String PROVIDER = "aws-ec2"
-    private static final String EUWEST_REGION_NAME = "eu-west-1" 
-    private static final String EUWEST_IMAGE_ID = EUWEST_REGION_NAME+"/"+"ami-7f0c260b";//"ami-41d3d635"
-    private static final String LOCATION_ID = "jclouds:"+PROVIDER+":"+EUWEST_REGION_NAME;
-    
-    protected JcloudsLocation loc;
-    protected Collection<SshMachineLocation> machines = []
-    protected ManagementContext ctx;
-    
-    @BeforeMethod(groups = "Live")
-    public void setUp() {
-        ctx = Entities.newManagementContext(ImmutableMap.of("provider", PROVIDER));
-
-        loc = ctx.locationRegistry.resolve LOCATION_ID
-    }
-
-    @AfterMethod(groups = "Live")
-    public void tearDown() {
-        List<Exception> exceptions = []
-        machines.each {
-            try {
-                loc?.release(it)
-            } catch (Exception e) {
-                LOG.warn("Error releasing machine $it; continuing...", e)
-                exceptions.add(e)
-            }
-        }
-        if (exceptions) {
-            throw exceptions.get(0)
-        }
-        machines.clear()
-    }
-    
-    // TODO Note careful choice of image due to jclouds 1.4 issue 886
-    // TODO Blocks for long time, waiting for IP:22 to be reachable, before falling back to using public IP
-    //      10*2 minutes per attempt in jclouds 1.4 because done sequentially, and done twice by us so test takes 40 minutes!
-    @Test(enabled=true, groups = [ "Live" ])
-    public void testProvisionWindowsVm() {
-        JcloudsSshMachineLocation machine = obtainMachine([ imageId:EUWEST_IMAGE_ID ]);
-
-        LOG.info("Provisioned Windows VM {}; checking if has password", machine)
-        assertNotNull(machine.waitForPassword())
-    }
-    
-    // Use this utility method to ensure machines are released on tearDown
-    protected SshMachineLocation obtainMachine(Map flags) {
-        SshMachineLocation result = loc.obtain(flags)
-        machines.add(result)
-        return result
-    }
-    
-    protected SshMachineLocation release(SshMachineLocation machine) {
-        machines.remove(machine)
-        loc.release(machine)
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationWindowsLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationWindowsLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationWindowsLiveTest.java
new file mode 100644
index 0000000..7c3618c
--- /dev/null
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/AwsEc2LocationWindowsLiveTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.location.jclouds.provider;
+
+import static org.testng.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsSshMachineLocation;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableMap;
+
+public class AwsEc2LocationWindowsLiveTest {
+    private static final Logger LOG = LoggerFactory.getLogger(AwsEc2LocationWindowsLiveTest.class);
+    
+    private static final String PROVIDER = "aws-ec2";
+    private static final String EUWEST_REGION_NAME = "eu-west-1";
+    private static final String EUWEST_IMAGE_ID = EUWEST_REGION_NAME+"/"+"ami-7f0c260b";//"ami-41d3d635"
+    private static final String LOCATION_ID = "jclouds:"+PROVIDER+":"+EUWEST_REGION_NAME;
+    
+    protected JcloudsLocation loc;
+    protected Collection<SshMachineLocation> machines = new ArrayList<SshMachineLocation>();
+    protected ManagementContext ctx;
+    
+    @BeforeMethod(groups = "Live")
+    public void setUp() {
+        ctx = Entities.newManagementContext(ImmutableMap.of("provider", PROVIDER));
+
+        loc = (JcloudsLocation) ctx.getLocationRegistry().resolve(LOCATION_ID);
+    }
+
+    @AfterMethod(groups = "Live")
+    public void tearDown() throws Exception {
+        List<Exception> exceptions = new ArrayList<Exception>();
+        for (SshMachineLocation machine : machines) {
+            try {
+                loc.release(machine);
+            } catch (Exception e) {
+                LOG.warn("Error releasing machine $it; continuing...", e);
+                exceptions.add(e);
+            }
+        }
+        if (!exceptions.isEmpty()) {
+            throw exceptions.get(0);
+        }
+        machines.clear();
+    }
+    
+    // TODO Note careful choice of image due to jclouds 1.4 issue 886
+    // TODO Blocks for long time, waiting for IP:22 to be reachable, before falling back to using public IP
+    //      10*2 minutes per attempt in jclouds 1.4 because done sequentially, and done twice by us so test takes 40 minutes!
+    @Test(enabled=true, groups = "Live")
+    public void testProvisionWindowsVm() throws NoMachinesAvailableException {
+        JcloudsSshMachineLocation machine = (JcloudsSshMachineLocation) obtainMachine(ImmutableMap.of("imageId", EUWEST_IMAGE_ID));
+
+        LOG.info("Provisioned Windows VM {}; checking if has password", machine);
+        assertNotNull(machine.waitForPassword());
+    }
+    
+    // Use this utility method to ensure machines are released on tearDown
+    protected SshMachineLocation obtainMachine(Map<?, ?> flags) throws NoMachinesAvailableException {
+        JcloudsSshMachineLocation result = (JcloudsSshMachineLocation) loc.obtain(flags);
+        machines.add(result);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f69ade37/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/CarrenzaLocationLiveTest.groovy
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/CarrenzaLocationLiveTest.groovy b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/CarrenzaLocationLiveTest.groovy
deleted file mode 100644
index 0c2197f..0000000
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/provider/CarrenzaLocationLiveTest.groovy
+++ /dev/null
@@ -1,132 +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 org.apache.brooklyn.location.jclouds.provider;
-
-import static org.testng.Assert.*
-
-import org.apache.brooklyn.core.internal.BrooklynProperties
-import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext
-import org.apache.brooklyn.location.jclouds.JcloudsLocation
-import org.apache.brooklyn.location.jclouds.JcloudsSshMachineLocation
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.collections.MutableMap
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.AfterMethod
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-import com.google.common.collect.ImmutableList
-
-/**
- * Tests vcloud, with Carrenza. Uses the cloudsoft test account (hard-coding its NAT Mapping, 
- * and one of its private vApp templates). Note that the template is for a Windows 2008 
- * machine with winsshd installed.
- * 
- * TODO Will only work with >= jclouds 1.5, due to jclouds issues 994 and 995. Therefore it 
- * will not work in brooklyn 0.4.0-M2 etc.
- */
-class CarrenzaLocationLiveTest {
-    private static final Logger LOG = LoggerFactory.getLogger(CarrenzaLocationLiveTest.class)
-    
-    private static final String PROVIDER = "vcloud"
-    private static final String ENDPOINT = "https://myvdc.carrenza.net/api"
-    private static final String LOCATION_ID = "jclouds:"+PROVIDER+":"+ENDPOINT;
-    private static final String WINDOWS_IMAGE_ID = "https://myvdc.carrenza.net/api/v1.0/vAppTemplate/vappTemplate-2bd5b0ff-ecd9-405e-8306-2f4f6c092a1b"
-    
-    private BrooklynProperties brooklynProperties;
-    private LocalManagementContext managementContext;
-    private JcloudsLocation loc;
-    private Collection<SshMachineLocation> machines = []
-    
-    // TODO Has not been tested since updating ot remove use of deleted LocationRegistry!
-    @BeforeMethod(groups = "Live")
-    public void setUp() {
-        System.out.println("classpath="+System.getProperty("java.class.path"));
-        
-        brooklynProperties = BrooklynProperties.Factory.newDefault();
-        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".image-description-regex");
-        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".image-name-regex");
-        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".image-id");
-        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".inboundPorts");
-        brooklynProperties.remove("brooklyn.jclouds."+PROVIDER+".hardware-id");
-
-        // Also removes scriptHeader (e.g. if doing `. ~/.bashrc` and `. ~/.profile`, then that can cause "stdin: is not a tty")
-        brooklynProperties.remove("brooklyn.ssh.config.scriptHeader");
-        
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".jclouds.endpoint", ENDPOINT)
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".imageId", WINDOWS_IMAGE_ID)
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".noDefaultSshKeys", true)
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".userName", "Administrator")
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".dontCreateUser", true)
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".overrideLoginUser", "Administrator")
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".waitForSshable", false)
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".runAsRoot", false)
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".inboundPorts", [22, 3389])
-        brooklynProperties.put("brooklyn.jclouds."+PROVIDER+".natMapping", [("192.168.0.100"):"195.3.186.200", ("192.168.0.101"):"195.3.186.42"])
-
-        managementContext = new LocalManagementContext(brooklynProperties);
-        loc = (JcloudsLocation) managementContext.getLocationRegistry().resolve(LOCATION_ID);
-    }
-    
-    @AfterMethod(groups = "Live")
-    public void tearDown() {
-        List<Exception> exceptions = []
-        machines.each {
-            try {
-                loc?.release(it)
-            } catch (Exception e) {
-                LOG.warn("Error releasing machine $it; continuing...", e)
-                exceptions.add(e)
-            }
-        }
-        if (exceptions) {
-            throw exceptions.get(0)
-        }
-        machines.clear()
-    }
-    
-    // FIXME Disabled because of jclouds issues #994 and #995 (fixed in jclouds 1.5, so not in brooklyn 0.4.0-M2 etc)
-    // Note the careful settings in setUp (e.g. so don't try to install ssh-keys etc
-    // Also, the windows image used has winsshd installed
-    @Test(enabled=false, groups = [ "Live" ])
-    public void testProvisionWindowsVm() {
-        JcloudsSshMachineLocation machine = obtainMachine(MutableMap.of(
-                "imageId", WINDOWS_IMAGE_ID));
-        
-        LOG.info("Provisioned Windows VM {}; checking if has password", machine)
-        String password = machine.waitForPassword();
-        assertNotNull(password);
-        
-        LOG.info("Checking can ssh to windows machine {} using password {}", machine, password);
-        assertEquals(machine.execCommands(MutableMap.of("password", password), "check-reachable", ImmutableList.of("hostname")), 0);
-    }
-    
-    // Use this utility method to ensure machines are released on tearDown
-    protected SshMachineLocation obtainMachine(Map flags) {
-        SshMachineLocation result = loc.obtain(flags)
-        machines.add(result)
-        return result
-    }
-    
-    protected SshMachineLocation release(SshMachineLocation machine) {
-        machines.remove(machine)
-        loc.release(machine)
-    }
-}


[4/7] incubator-brooklyn git commit: Reimplement GroovyJavaMethods in Java

Posted by al...@apache.org.
Reimplement GroovyJavaMethods in Java


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

Branch: refs/heads/master
Commit: 0d0214ccecc6222ffa7c712b1b9077c9356f6f46
Parents: 18c28d2
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Thu Oct 22 09:49:22 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Thu Oct 22 16:33:44 2015 +0300

----------------------------------------------------------------------
 .../util/groovy/FromCallableClosure.java        |  38 ++++
 .../util/groovy/FromFunctionClosure.java        |  39 ++++
 .../util/groovy/FromRunnableClosure.java        |  46 +++++
 .../util/groovy/GroovyJavaMethods.groovy        | 146 --------------
 .../brooklyn/util/groovy/GroovyJavaMethods.java | 200 +++++++++++++++++++
 .../brooklyn/util/groovy/JavadocDummy.java      |  30 ---
 6 files changed, 323 insertions(+), 176 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0d0214cc/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromCallableClosure.java
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromCallableClosure.java b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromCallableClosure.java
new file mode 100644
index 0000000..0ad414f
--- /dev/null
+++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromCallableClosure.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.groovy;
+
+import java.util.concurrent.Callable;
+
+import groovy.lang.Closure;
+
+public class FromCallableClosure<T> extends Closure<T> {
+    private static final long serialVersionUID = 1L;
+    private Callable<T> job;
+
+    public FromCallableClosure(Class<GroovyJavaMethods> owner, Callable<T> job) {
+        super(owner, owner);
+        this.job = job;
+    }
+
+    public T doCall() throws Exception {
+        return job.call();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0d0214cc/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromFunctionClosure.java
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromFunctionClosure.java b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromFunctionClosure.java
new file mode 100644
index 0000000..80203fb
--- /dev/null
+++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromFunctionClosure.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.groovy;
+
+import groovy.lang.Closure;
+
+import com.google.common.base.Function;
+
+public class FromFunctionClosure<T> extends Closure<T> {
+    private static final long serialVersionUID = 1L;
+    private Function<Object, T> job;
+
+    @SuppressWarnings("unchecked")
+    public FromFunctionClosure(Class<GroovyJavaMethods> owner, Function<?, T> job) {
+        super(owner, owner);
+        this.job = (Function<Object, T>) job;
+    }
+
+    public T doCall(Object it) throws Exception {
+        return job.apply(it);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0d0214cc/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromRunnableClosure.java
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromRunnableClosure.java b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromRunnableClosure.java
new file mode 100644
index 0000000..37fad87
--- /dev/null
+++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/FromRunnableClosure.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.groovy;
+
+import groovy.lang.Closure;
+
+import java.util.concurrent.Callable;
+
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+
+public class FromRunnableClosure<T> extends Closure<T> {
+    private static final long serialVersionUID = 1L;
+    private Runnable job;
+
+    public FromRunnableClosure(Class<GroovyJavaMethods> owner, Runnable job) {
+        super(owner, owner);
+        this.job = job;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T doCall() throws Throwable {
+        if (ScriptBytecodeAdapter.isCase(job, Callable.class)) {
+            return ((Callable<T>)job).call();
+        } else {
+            job.run();
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0d0214cc/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/GroovyJavaMethods.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/GroovyJavaMethods.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/GroovyJavaMethods.groovy
deleted file mode 100644
index ff0def2..0000000
--- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/GroovyJavaMethods.groovy
+++ /dev/null
@@ -1,146 +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 org.apache.brooklyn.util.groovy;
-
-import static org.apache.brooklyn.util.groovy.GroovyJavaMethods.truth;
-
-import java.util.concurrent.Callable
-
-import org.apache.brooklyn.util.concurrent.CallableFromRunnable;
-
-import com.google.common.base.Function
-import com.google.common.base.Predicate
-
-/** handy methods available in groovy packaged so they can be consumed from java,
- *  and other conversion/conveniences; but see JavaGroovyEquivalents for faster alternatives */
-public class GroovyJavaMethods {
-
-    //TODO use named subclasses, would that be more efficient?
-
-    // TODO xFromY methods not in correct class: they are not "handy method available in groovy"?
-    public static Closure closureFromRunnable(final Runnable job) {
-        return {
-            if (job in Callable) { return job.call() }
-            else { job.run(); null; }
-        };
-    }
-    
-    public static Closure closureFromCallable(final Callable job) {
-        return { job.call(); };
-    }
-
-    public static <T> Closure<T> closureFromFunction(final Function<?,T> job) {
-        return { it -> return job.apply(it); };
-    }
-
-    public static <T> Callable<T> callableFromClosure(final Closure<T> job) {
-        return job as Callable;
-    }
-
-    public static <T> Callable<T> callableFromRunnable(final Runnable job) {
-        return (job in Callable) ? callableFromClosure(job) : CallableFromRunnable.newInstance(job, null);
-    }
-
-    public static <T> Predicate<T> predicateFromClosure(final Closure<Boolean> job) {
-        // TODO using `Predicate<T>` on the line below gives "unable to resolve class T"
-        return new Predicate<Object>() {
-            public boolean apply(Object input) {
-                return job.call(input);
-            }
-        };
-    }
-
-    public static <F,T> Function<F,T> functionFromClosure(final Closure<T> job) {
-        // TODO using `Function<F,T>` on the line below gives "unable to resolve class T"
-        return new Function<Object,Object>() {
-            public Object apply(Object input) {
-                return job.call(input);
-            }
-        };
-    }
-
-    public static <T> Predicate<T> castToPredicate(Object o) {
-        if (o in Closure) {
-            return predicateFromClosure(o);
-        } else {
-            return (Predicate<T>) o;
-        }
-    }
-
-    public static <T> Closure castToClosure(Object o) {
-        if (o == null) {
-            return o;
-        } else if (o in Closure) {
-            return o;
-        } else if (o instanceof Runnable) {
-            return closureFromRunnable((Runnable)o);
-        } else if (o instanceof Callable) {
-            return closureFromCallable((Callable)o); 
-        } else if (o instanceof Function) {
-            return closureFromFunction((Function)o); 
-        } else {
-            throw new IllegalArgumentException("Cannot convert to closure: o="+o+"; type="+(o != null ? o.getClass() : null));
-        }
-    }
-
-/* alternatives to above; but I think the above is more efficient?  (even more efficient if moved from java to groovy)  --alex jun 2012
-    public static <K,T> Function<K,T> functionFromClosure(final Closure<T> job) {
-        return job as Function;
-    }
-
-    public static <T> Predicate<T> predicateFromClosure(final Closure<Boolean> job) {
-        return job as Predicate;
-    }
-*/
-    
-    public static Predicate<Object> truthPredicate() {
-        return new Predicate<Object>() {
-           @Override public boolean apply(Object input) {
-               return truth(input);
-           }
-        };
-    }
-    
-    public static boolean truth(Object o) {
-        if (o) return true;
-        return false;
-    }
-
-    public static <T> T elvis(Object preferred, Object fallback) {
-        return fix(preferred ?: fallback);
-    }
-    
-    public static <T> T elvis(Object... preferences) {
-        if (preferences.length == 0) throw new IllegalArgumentException("preferences must not be empty for elvis");
-        for (Object contender : preferences) {
-            if (contender) return fix(contender);
-        }
-        return fix(preferences[preferences.size()-1]);
-    }
-    
-    public static <T> T fix(Object o) {
-        if (o in GString) return (o as String);
-        return o;
-    }
-    
-    // args is expected to be an array, but for groovy compilation reasons it's not declared as such in the signature :-(
-    public static <T> T invokeMethodOnMetaClass(Object target, String methodName, Object args) {
-        return target.metaClass.invokeMethod(target, methodName, args);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0d0214cc/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/GroovyJavaMethods.java
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/GroovyJavaMethods.java b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/GroovyJavaMethods.java
new file mode 100644
index 0000000..7f019a9
--- /dev/null
+++ b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/GroovyJavaMethods.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.groovy;
+
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.util.concurrent.CallableFromRunnable;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+import org.codehaus.groovy.runtime.callsite.CallSite;
+import org.codehaus.groovy.runtime.callsite.CallSiteArray;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+
+import groovy.lang.Closure;
+import groovy.lang.GString;
+
+/** handy methods available in groovy packaged so they can be consumed from java,
+ *  and other conversion/conveniences; but see JavaGroovyEquivalents for faster alternatives */
+public class GroovyJavaMethods {
+    private static final CallSiteArray CALL_SITE_ARRAY = new CallSiteArray(GroovyJavaMethods.class, new String[] {"metaClass", "invokeMethod"});
+
+    //TODO use named subclasses, would that be more efficient?
+
+    // TODO xFromY methods not in correct class: they are not "handy method available in groovy"?
+    public static <T> Closure<T> closureFromRunnable(final Runnable job) {
+        return new FromRunnableClosure<T>(GroovyJavaMethods.class, job);
+    }
+    
+    public static <T> Closure<T> closureFromCallable(final Callable<T> job) {
+        return new FromCallableClosure<T>(GroovyJavaMethods.class, job);
+    }
+
+    public static <T> Closure<T> closureFromFunction(final Function<?,T> job) {
+        return new FromFunctionClosure<T>(GroovyJavaMethods.class, job);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> Callable<T> callableFromClosure(final Closure<T> job) {
+        try {
+            return (Callable<T>)ScriptBytecodeAdapter.asType(job, Callable.class);
+        } catch (Throwable e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> Callable<T> callableFromRunnable(final Runnable job) {
+        try {
+            if (ScriptBytecodeAdapter.isCase(job, Callable.class)) {
+                return (Callable<T>)ScriptBytecodeAdapter.asType(job, Callable.class);
+            } else {
+                return CallableFromRunnable.newInstance(job, null);
+            }
+        } catch (Throwable e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    public static <T> Predicate<T> predicateFromClosure(final Closure<Boolean> job) {
+        return new Predicate<T>() {
+            @Override
+            public boolean apply(Object input) {
+                return job.call(input);
+            }
+        };
+    }
+
+    public static <F,T> Function<F,T> functionFromClosure(final Closure<T> job) {
+        return new Function<F,T>() {
+            @Override
+            public T apply(F input) {
+                return job.call(input);
+            }
+        };
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> Predicate<T> castToPredicate(Object o) {
+        try {
+            if (ScriptBytecodeAdapter.isCase(o, Closure.class)) {
+                return predicateFromClosure((Closure<Boolean>)o);
+            } else {
+                return (Predicate<T>) o;
+            }
+        } catch (Throwable e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> Closure<T> castToClosure(Object o) {
+        try {
+            if (ScriptBytecodeAdapter.compareEqual(o, null)) {
+                return (Closure<T>)ScriptBytecodeAdapter.castToType(o, Closure.class);
+            } else if (ScriptBytecodeAdapter.isCase(o, Closure.class)) {
+                return (Closure<T>)ScriptBytecodeAdapter.castToType(o, Closure.class);
+            } else if (o instanceof Runnable) {
+                return closureFromRunnable((Runnable)ScriptBytecodeAdapter.createPojoWrapper(ScriptBytecodeAdapter.castToType(o, Runnable.class), Runnable.class));
+            } else if (o instanceof Callable) {
+                return closureFromCallable((Callable<T>)ScriptBytecodeAdapter.createPojoWrapper(ScriptBytecodeAdapter.castToType(o, Callable.class), Callable.class));
+            } else if (o instanceof Function) {
+                return closureFromFunction((Function<Object, T>)ScriptBytecodeAdapter.createPojoWrapper(ScriptBytecodeAdapter.castToType(o, Function.class), Function.class));
+            } else {
+                throw new IllegalArgumentException("Cannot convert to closure: o="+o+"; type="+(o != null ? o.getClass() : null));
+            }
+        } catch (Throwable e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+/* alternatives to above; but I think the above is more efficient?  (even more efficient if moved from java to groovy)  --alex jun 2012
+    public static <K,T> Function<K,T> functionFromClosure(final Closure<T> job) {
+        return job as Function;
+    }
+
+    public static <T> Predicate<T> predicateFromClosure(final Closure<Boolean> job) {
+        return job as Predicate;
+    }
+*/
+    
+    public static Predicate<Object> truthPredicate() {
+        return new Predicate<Object>() {
+           @Override public boolean apply(Object input) {
+               return truth(input);
+           }
+        };
+    }
+    
+    public static boolean truth(Object o) {
+        if (DefaultTypeTransformation.booleanUnbox(o)) return true;
+        return false;
+    }
+
+    public static <T> T elvis(Object preferred, Object fallback) {
+        try {
+            return fix(truth(preferred) ? preferred : fallback);
+        } catch (Throwable e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    public static <T> T elvis(Object... preferences) {
+        try {
+            if (preferences.length == 0) throw new IllegalArgumentException("preferences must not be empty for elvis");
+            for (Object contender : preferences) {
+                if (truth(contender)) return fix(contender);
+            }
+            return fix(preferences[preferences.length-1]);
+        } catch (Throwable e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static <T> T fix(Object o) {
+        try {
+            if (ScriptBytecodeAdapter.isCase(o, GString.class)) {
+                return (T)ScriptBytecodeAdapter.asType(o, String.class);
+            } else {
+                return (T)o;
+            }
+        } catch (Throwable e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static <T> T invokeMethodOnMetaClass(Object target, String methodName, Object args) {
+        try {
+            CallSite[] callSiteArray = getCallSiteArray();
+            Object metaClass = callSiteArray[0].callGetProperty(target);
+            return (T) callSiteArray[1].call(metaClass, target, methodName, args);
+        } catch (Throwable e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    private static CallSite[] getCallSiteArray() {
+        return CALL_SITE_ARRAY.array;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0d0214cc/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java
deleted file mode 100644
index c9a51b5..0000000
--- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/JavadocDummy.java
+++ /dev/null
@@ -1,30 +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 org.apache.brooklyn.util.groovy;
-
-/** Maven Central requires javadoc to promote as a release. This seemed to happen when this was built by maven as a bundle,
- * but now that it is built as a jar it does not. This class exists only to provide that javadoc.
- * <p>
- * Note the groovy code does javadoc but the maven build is not picking it up. It *is* generated as part of the site build.
- */
-public class JavadocDummy {
-
-    private JavadocDummy() {}
-    
-}


[5/7] incubator-brooklyn git commit: Remove deprecated and unused groovy code

Posted by al...@apache.org.
Remove deprecated and unused groovy code


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

Branch: refs/heads/master
Commit: 18c28d24f1e0828ee1064b32da3840822ee21f2c
Parents: de3b706
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Fri Jul 10 18:15:34 2015 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Thu Oct 22 16:33:44 2015 +0300

----------------------------------------------------------------------
 .../util/core/BrooklynLanguageExtensions.java   |   2 -
 .../brooklyn/util/core/internal/Repeater.java   |   3 -
 .../Infinispan5ServerIntegrationTest.java       |   3 -
 .../nosql/couchdb/AbstractCouchDBNodeTest.java  |   5 -
 ...namicWebAppClusterRebindIntegrationTest.java |   3 -
 .../brooklyn/util/groovy/LanguageUtils.groovy   | 383 -------------------
 .../brooklyn/util/groovy/TimeExtras.groovy      |  83 ----
 .../util/groovy/LanguageUtilsTest.groovy        | 152 --------
 .../brooklyn/util/groovy/TimeExtrasTest.groovy  |  49 ---
 9 files changed, 683 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/18c28d24/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java b/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java
index afad73f..6e4958a 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/BrooklynLanguageExtensions.java
@@ -21,7 +21,6 @@ package org.apache.brooklyn.util.core;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.brooklyn.core.internal.BrooklynInitialization;
-import org.apache.brooklyn.util.groovy.TimeExtras;
 
 /** @deprecated since 0.7.0 use {@link BrooklynInitialization} */
 public class BrooklynLanguageExtensions {
@@ -38,7 +37,6 @@ public class BrooklynLanguageExtensions {
     /** performs the language extensions required for this project */
     public synchronized static void init() {
         if (done.getAndSet(true)) return;
-        TimeExtras.init();
         BrooklynInitialization.initPortRanges();
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/18c28d24/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java b/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java
index 77d15c7..422f31c 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/internal/Repeater.java
@@ -30,7 +30,6 @@ import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.flags.FlagUtils;
 import org.apache.brooklyn.util.core.flags.SetFromFlag;
 import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.groovy.TimeExtras;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;
 import org.slf4j.Logger;
@@ -86,8 +85,6 @@ public class Repeater {
     
     private static final Logger log = LoggerFactory.getLogger(Repeater.class);
 
-    static { TimeExtras.init(); }
-
     @SetFromFlag
     private String description;
     private Callable<?> body = Callables.returning(null);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/18c28d24/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.java b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.java
index a541c7a..2c2afc1 100644
--- a/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.java
+++ b/sandbox/nosql/src/test/java/org/apache/brooklyn/entity/nosql/infinispan/Infinispan5ServerIntegrationTest.java
@@ -31,7 +31,6 @@ import org.apache.brooklyn.core.location.PortRanges;
 import org.apache.brooklyn.core.test.entity.TestApplicationImpl;
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.util.groovy.TimeExtras;
 import org.apache.brooklyn.util.net.Networking;
 import org.apache.brooklyn.util.repeat.Repeater;
 import org.apache.brooklyn.util.time.Duration;
@@ -52,8 +51,6 @@ class Infinispan5ServerIntegrationTest {
 
     static boolean portLeftOpen = false;
     
-    static { TimeExtras.init(); }
-
     @BeforeMethod(groups = "Integration")
     public void failIfPortInUse() {
         if (Networking.isPortAvailable(DEFAULT_PORT)) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/18c28d24/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java
index 2ecfac8..22d4bc6 100644
--- a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java
+++ b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/couchdb/AbstractCouchDBNodeTest.java
@@ -27,7 +27,6 @@ import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.util.groovy.TimeExtras;
 
 /**
  * CouchDB test framework for integration and live tests.
@@ -36,10 +35,6 @@ public class AbstractCouchDBNodeTest {
 
     private static final Logger log = LoggerFactory.getLogger(AbstractCouchDBNodeTest.class);
 
-    static {
-        TimeExtras.init();
-    }
-
     protected TestApplication app;
     protected Location testLocation;
     protected CouchDBNode couchdb;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/18c28d24/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
index b05a747..517c756 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/jboss/ControlledDynamicWebAppClusterRebindIntegrationTest.java
@@ -41,7 +41,6 @@ import org.apache.brooklyn.entity.software.base.SoftwareProcess;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.test.WebAppMonitor;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
-import org.apache.brooklyn.util.groovy.TimeExtras;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;
@@ -57,8 +56,6 @@ import com.google.common.io.Files;
 public class ControlledDynamicWebAppClusterRebindIntegrationTest {
     private static final Logger LOG = LoggerFactory.getLogger(ControlledDynamicWebAppClusterRebindIntegrationTest.class);
     
-    static { TimeExtras.init(); }
-
     private LocalhostMachineProvisioningLocation localhostProvisioningLocation;
     private TestApplication origApp;
     private TestApplication newApp;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/18c28d24/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy
deleted file mode 100644
index d4fe86c..0000000
--- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/LanguageUtils.groovy
+++ /dev/null
@@ -1,383 +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 org.apache.brooklyn.util.groovy
-
-import java.lang.reflect.Field
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier
-import java.util.Collection;
-import java.util.concurrent.atomic.AtomicLong
-
-import org.apache.brooklyn.util.javalang.Reflections;
-import org.apache.brooklyn.util.text.Identifiers
-
-import com.google.common.annotations.Beta
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-/**
- * Useful Groovy utility methods.
- * 
- * @deprecated since 0.5; requires thorough review for what will be kept.
- *             e.g. consider instead using guava's {@link com.google.common.collect.Multimap} instead of addToMapOfSets etc
- */
-@Deprecated
-@Beta
-public class LanguageUtils {
-    // For unique identifiers
-    private static final AtomicLong seed = new AtomicLong(0L)
-
-    public static <T> T getRequiredField(String name, Map<?,?> m) {
-        if (!m.containsKey(name))
-            throw new IllegalArgumentException("a parameter '"+name+"' was required in the argument to this function")
-        m.get name
-    }
-
-    public static <T> T getOptionalField(String name, Map<?,?> m, T defaultValue=null) {
-        m.get(name) ?: defaultValue
-    }
-
-    public static <T> T getPropertySafe(Object target, String name, T defaultValue=null) {
-        target.hasProperty(name)?.getProperty(target) ?: defaultValue
-    }
-
-    //TODO find with annotation
-
-    public static byte[] serialize(Object orig) {
-        if (orig == null) return null;
-
-        // Write the object out to a byte array
-        ByteArrayOutputStream fbos = []
-        ObjectOutputStream out = new ObjectOutputStream(fbos);
-        out.writeObject(orig);
-        out.flush();
-        out.close();
-        return fbos.toByteArray();
-    }
-
-    public static <T> T deserialize(byte[] bytes, ClassLoader classLoader) {
-        if (bytes == null) return null;
-
-        ObjectInputStream ins =
-                //new ObjectInputStreamWithLoader(new FastByteArrayInputStream(bytes, bytes.length), classLoader);
-                new ObjectInputStream(new ByteArrayInputStream(bytes));
-        (T) ins.readObject();
-    }
-
-    /**
-     * @deprecated use Identifiers.makeRandomId(8)
-     */
-    @Deprecated
-    public static String newUid() { Identifiers.makeRandomId(8) }
-
-    public static Map setFieldsFromMap(Object target, Map fieldValues) {
-        Map unused = [:]
-        fieldValues.each {
-            //            println "looking for "+it.key+" in "+target+": "+target.metaClass.hasProperty(it.key)
-            target.hasProperty(it.key) ? target.(it.key) = it.value : unused << it
-        }
-        unused
-    }
-
-    /**
-     * Adds the given value to a collection in the map under the key.
-     * 
-     * A collection (as {@link LinkedHashMap}) will be created if necessary,
-     * synchronized on map for map access/change and set for addition there
-     *
-     * @return the updated set (instance, not copy)
-     * 
-     * @deprecated since 0.5; use {@link HashMultimap}, and {@link Multimaps#synchronizedSetMultimap(com.google.common.collect.SetMultimap)}
-     */
-    @Deprecated
-    public static <K,V> Set<V> addToMapOfSets(Map<K,Set<V>> map, K key, V valueInCollection) {
-        Set<V> coll;
-        synchronized (map) {
-            coll = map.get(key)
-            if (coll==null) {
-                coll = new LinkedHashSet<V>()
-                map.put(key, coll)
-            }
-            if (coll.isEmpty()) {
-                synchronized (coll) {
-                    coll.add(valueInCollection)
-                }
-                //if collection was empty then add to the collection while holding the map lock, to prevent removal
-                return coll
-            }
-        }
-        synchronized (coll) {
-            if (!coll.isEmpty()) {
-                coll.add(valueInCollection)
-                return coll;
-            }
-        }
-        //if was empty, recurse, because someone else might be removing the collection
-        return addToMapOfSets(map, key, valueInCollection);
-    }
-
-    /**
-     * as {@link #addToMapOfSets(Map, Object, Object)} but for {@link ArrayList}
-     * 
-     * @deprecated since 0.5; use {@link ArrayListMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)}
-     */
-    @Deprecated
-    public static <K,V> List<V> addToMapOfLists(Map<K,List<V>> map, K key, V valueInCollection) {
-        List<V> coll;
-        synchronized (map) {
-            coll = map.get(key)
-            if (coll==null) {
-                coll = new ArrayList<V>()
-                map.put(key, coll)
-            }
-            if (coll.isEmpty()) {
-                synchronized (coll) {
-                    coll.add(valueInCollection)
-                }
-                //if collection was empty then add to the collection while holding the map lock, to prevent removal
-                return coll
-            }
-        }
-        synchronized (coll) {
-            if (!coll.isEmpty()) {
-                coll.add(valueInCollection)
-                return coll;
-            }
-        }
-        //if was empty, recurse, because someone else might be removing the collection
-        return addToMapOfLists(map, key, valueInCollection);
-    }
-
-    /**
-     * Removes the given value from a collection in the map under the key.
-     *
-     * @return the updated set (instance, not copy)
-     * 
-     * @deprecated since 0.5; use {@link ArrayListMultimap} or {@link HashMultimap}, and {@link Multimaps#synchronizedListMultimap(com.google.common.collect.ListMultimap)} etc
-     */
-    @Deprecated
-    public static <K,V> boolean removeFromMapOfCollections(Map<K,? extends Collection<V>> map, K key, V valueInCollection) {
-        Collection<V> coll;
-        synchronized (map) {
-            coll = map.get(key)
-            if (coll==null) return false;
-        }
-        boolean result;
-        synchronized (coll) {
-            result = coll.remove(valueInCollection)
-        }
-        if (coll.isEmpty()) {
-            synchronized (map) {
-                synchronized (coll) {
-                    if (coll.isEmpty()) {
-                        //only remove from the map if no one is adding to the collection or to the map, and the collection is still in the map
-                        if (map.get(key)==coll) {
-                            map.remove(key)
-                        }
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Visits all fields of a given object, recursively.
-     *
-     * For collections, arrays, and maps it visits the items within, passing null for keys where it isn't a map.
-     */
-    public static void visitFields(Object o, FieldVisitor fv, Collection<Object> objectsToSkip=([] as Set)) {
-        if (o == null || objectsToSkip.contains(o)) return
-        objectsToSkip << o
-        if (o in String) return
-        if (o in Map) {
-            o.each { key, value ->
-                fv.visit(o, key.toString(), value)
-                visitFields(value, fv, objectsToSkip)
-            }
-        } else if ((o in Collection) || (o.getClass().isArray())) {
-            o.each {
-                entry ->
-                fv.visit(o, null, entry)
-                visitFields(entry, fv, objectsToSkip)
-            }
-        } else {
-            o.getClass().getDeclaredFields().each {
-                Field field ->
-                if ((field.getModifiers() & Modifier.STATIC) || field.isSynthetic()) return;  //skip static
-                field.setAccessible true
-                def v = field.get(o);
-                fv.visit(o, field.name, v)
-                visitFields(v, fv, objectsToSkip)
-            }
-        }
-    }
-
-    public interface FieldVisitor {
-        /** Invoked by visitFields; fieldName will be null for collections */
-        public void visit(Object parent, String fieldName, Object value)
-    }
-
-    /**
-     * Iterates through two collections simultaneously, passing both args to code.
-     * 
-     * <pre>
-     * a = ['a','b']; b=[1,2];
-     * assert ['a1','b2'] == forboth(a,b) { x,y -> x+y }
-     * </pre>
-     */
-    public static Collection forBoth(Collection l1, Collection l2, Closure code) {
-        def result=[]
-        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) }
-        result
-    }
-
-    public static Collection forBothWithIndex(Collection l1, Collection l2, Closure code) {
-        def result=[]
-        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) }
-        result
-    }
-
-    public static Collection forBoth(Object[] l1, Object[] l2, Closure code) {
-        def result=[]
-        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i]) ) }
-        result
-    }
-
-    public static Collection forBothWithIndex(Object[] l1, Object[] l2, Closure code) {
-        def result=[]
-        l1.eachWithIndex { a, i -> result.add( code.call(a, l2[i], i) ) }
-        result
-    }
-
-    /** return value used to indicate that there is no such field */
-    public static final Object NO_SUCH_FIELD = new Object();
-
-    /**
-     * Default field getter.
-     *
-     * Delegates to {@code object[field]} (which will invoke a getter if one exists, in groovy),
-     * unless field starts with {@literal @} in which case it looks up the actual java field (bypassing getter).
-     * <p>
-     * Can be extended as needed when passed to {@link #equals(Object, Object, Class, String[])}
-     */
-    public static final Closure DEFAULT_FIELD_GETTER = { Object object, Object field ->
-        try {
-            if ((field in String) && field.startsWith("@")) {
-                return object.@"${field.substring(1)}"
-            }
-            return object[field]
-        } catch (Exception e) {
-            return NO_SUCH_FIELD
-        }
-    }
-
-    /**
-     * Checks equality of o1 and o2 with respect to the named fields, optionally enforcing a common superclass
-     * and using a custom field-getter.
-     *
-     * Other types can be supplied if they are supported by {@code object[field]} (what the {@link #DEFAULT_FIELD_GETTER} does)
-     * or if the {@literal optionalGetter} handles it. Note that {@code object[field]} causes invocation of {@code object.getAt(field)}
-     * (which can be provided on the object for non-strings - this is preferred to an optionalGetter, generally)
-     * looking for {@code object.getXxx()}, where field is a string {@literal xxx}, then {@code object.xxx}.
-     * <p>
-     * One exception is that field names which start with {@literal @} get the field directly according to {@link #DEFAULT_FIELD_GETTER},
-     * but use with care on private fields, as they must be on the object and not a superclass, and with groovy properties
-     * (formerly known as package-private, i.e. with no access modifiers) because they become private fields.
-     * <p>
-     * For example
-     * <pre>
-     * public class Foo {
-     *   Object bar;
-     *   public boolean equals(Object other) { LangaugeUtils.equals(this, other, Foo.class, ["bar"]); }
-     *   public int hashCode() { LangaugeUtils.hashCode(this, ["bar"]); }
-     * }
-     * </pre>
-     *
-     * @param o1 one object to compare
-     * @param o2 other object to compare
-     * @param optionalCommonSuperClass if supplied, returns false unless both objects are instances of the given type;
-     *     (if not supplied it effectively does duck typing, returning false if any field is not present)
-     * @param optionalGetter if supplied, a closure which takes (object, field) and returns the value of field on object;
-     *  should return static {@link #NO_SUCH_FIELD} if none found;
-     *  recommended to delegate to {@link #DEFAULT_FIELD_GETTER} at least for strings (or for anything)
-     * @param fields typically a list of strings being names of fields on the class to compare
-     * @return true if the two objects are equal in all indicated fields, and conform to the optionalCommonSuperClass if supplied
-     */
-    public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Iterable<Object> fieldNames) {
-        if (o1==null) return o2==null;
-        if (o2==null) return false;
-        if (optionalCommonSuperClass) {
-            if (!(o1 in optionalCommonSuperClass) || !(o2 in optionalCommonSuperClass)) return false
-        }
-        Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER
-        for (it in fieldNames) {
-            def v1 = get.call(o1, it)
-            if (v1==NO_SUCH_FIELD) return false
-            if (v1!=get.call(o2, it)) return false
-        }
-        return true
-    }
-
-    public static boolean equals(Object o1, Object o2, Class<?> optionalCommonSuperClass=null, Closure optionalGetter=null, Object[] fieldNames) {
-        return equals(o1, o2, optionalCommonSuperClass, optionalGetter, Arrays.asList(fieldNames) )
-    }
-
-    /**
-     * Generates a hashcode for an object.
-     * 
-     * Similar to {@link com.google.common.base.Objects#hashCode()} but taking field <em>names</em> and an optional getter,
-     * with the same rich groovy semantics as described in {@link #equals(Object, Object, Class)}.
-     */
-    public static int hashCode(Object o, Closure optionalGetter=null, Collection<Object> fieldNames) {
-        if (o==null) return 0;
-        Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER
-        int result = 1;
-        for (it in fieldNames) {
-            def v1 = get.call(o, it)
-            if (v1==NO_SUCH_FIELD)
-                throw new NoSuchFieldError("Cannot access $it on "+o.getClass());
-            result = 31 * result + (it == null ? 0 : it.hashCode());
-        }
-        result
-    }
-
-    public static int hashCode(Object o, Closure optionalGetter=null, Object[] fieldNames) {
-        hashCode(o, optionalGetter, Arrays.asList(fieldNames))
-    }
-    
-    /** Default String representation is simplified name of class, together with selected fields. */
-    public static String toString(Object o, Closure optionalGetter=null, Collection<? extends CharSequence> fieldNames) {
-        if (o==null) return null;
-        Closure get = optionalGetter ?: DEFAULT_FIELD_GETTER
-        
-        StringBuilder result = new StringBuilder();
-        result.append(o.getClass().getSimpleName());
-        if (result.length() == 0) result.append(o.getClass().getName());
-        List<Object> fieldVals = fieldNames.collect {
-                Object v = get.call(o, it);
-                return (v != null) ? it+"="+v : null;
-        }
-        result.append("[").append(Joiner.on(",").skipNulls().join(fieldVals)).append("]");
-        return result.toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/18c28d24/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy b/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy
deleted file mode 100644
index 4bca76f..0000000
--- a/utils/groovy/src/main/java/org/apache/brooklyn/util/groovy/TimeExtras.groovy
+++ /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 org.apache.brooklyn.util.groovy
-
-import groovy.time.TimeDuration
-
-import java.util.concurrent.TimeUnit
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-import org.apache.brooklyn.util.time.Time
-
-
-/**
- * Classloading this class will cause multiply/add to be made available on TimeDuration.
- * For example, I could write: 2*TimeUnit.MINUTES+5*TimeUnit.SECONDS.
- * 
- * That is why nothing seems to use this class, because the methods it defines are not 
- * on this class!
- * 
- * @author alex
- * 
- * @deprecated since 0.6.0 - just use brooklyn.util.time.Duration, simpler and easier to configure, and avoids language problems
- */
-@Deprecated
-class TimeExtras {
-    public static final Logger log = LoggerFactory.getLogger(TimeExtras.class);
-    
-    public static void init() {
-        Number.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) }
-        Number.metaClass.multiply << { TimeDuration t -> t.multiply(doubleValue()) }
-        Integer.metaClass.multiply << { TimeUnit t -> new TimeDuration(t.toMillis(intValue())) }
-        
-        TimeDuration.metaClass.multiply << { Number n -> new TimeDuration( (int)(toMilliseconds()*n) ) }
-        TimeDuration.metaClass.constructor << { long millis ->
-            def shift = { int modulus -> int v=millis%modulus; millis/=modulus; v }
-            def l = [shift(1000), shift(60), shift(60), shift(24), (int)millis]
-            Collections.reverse(l)
-            l as TimeDuration
-        }
-    }
-    
-    static { init(); }
-    
-    /** creates a duration object
-     * <p>
-     * fix for irritating classloading/metaclass order 
-     * where an int may get constructed too early and not have the multiply syntax available
-     * (because grail is invoked?; if e.g. 5*SECONDS throws an error, try duration(5, SECONDS)  */ 
-    public static TimeDuration duration(int value, TimeUnit unit) {
-        return new TimeDuration(0, 0, 0, (int)unit.toMillis(value));
-    }
-    
-    public static final TimeDuration ONE_SECOND = duration(1, TimeUnit.SECONDS);
-    public static final TimeDuration FIVE_SECONDS = duration(5, TimeUnit.SECONDS);
-    public static final TimeDuration TEN_SECONDS = duration(10, TimeUnit.SECONDS);
-    public static final TimeDuration THIRTY_SECONDS = duration(30, TimeUnit.SECONDS);
-    public static final TimeDuration ONE_MINUTE = duration(1, TimeUnit.MINUTES);
-    public static final TimeDuration TWO_MINUTES = duration(2, TimeUnit.MINUTES);
-    public static final TimeDuration FIVE_MINUTES = duration(5, TimeUnit.MINUTES);
-
-    public static void sleep(TimeDuration duration) {
-        Time.sleep(duration.toMilliseconds());
-    }    
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/18c28d24/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy
deleted file mode 100644
index 961db5d..0000000
--- a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/LanguageUtilsTest.groovy
+++ /dev/null
@@ -1,152 +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 org.apache.brooklyn.util.groovy;
-
-import static org.testng.Assert.*
-
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.testng.annotations.Test
-import org.apache.brooklyn.util.groovy.LanguageUtils.FieldVisitor
-
-
-/**
- * Test the operation of the {@link LanguageUtils} utilities.
- */
-public class LanguageUtilsTest {
-    private static final Logger log = LoggerFactory.getLogger(LanguageUtilsTest.class)
- 
-    @Test
-    public void testSetFieldsFromMap() {
-        A a = []
-        Map unused = LanguageUtils.setFieldsFromMap(a, [num:1,mun:2])
-        assertEquals(1, a.num);
-        assertEquals([mun:2], unused)
-    }
-    
-    @Test
-    public void testVisitingFieldsDeepNonLooping() {
-        BigUn b2 = new BigUn(name:"L'il Guy", num:10, dates:[ new Date() ])
-//        b2.dates = [ new Date() ] as Date[]
-        BigUn b1 = new BigUn(name:"Big Guy", num:40)
-        b1.child = b2;
-        b1.children += b2
-        b2.child = b1
-        
-        int sum = 0;
-        FieldVisitor numSummer = { parent, name, value -> if ("num"==name) sum+=value } as FieldVisitor
-        LanguageUtils.visitFields(b1, numSummer)
-        
-        assertEquals(50, sum) 
-    }
-    
-    private static class A {
-        int num;
-    }
-    
-    private static class BigUn {
-        String name;
-        int num;
-        BigUn child;
-        Set children = []
-        Date[] dates;
-    }
-
-    //test the default getter, and equals
-    static class TestingFieldA {
-        public int a = 6;
-        int getAt(A aa) { return aa.num * a; }
-        static A aa = [num:10];
-        int x = -1;
-    }
-    static class TestingFields extends TestingFieldA {
-        int b = 7;
-        int getB() { -7 }
-        public int c = 8;
-        int getD() { 9 }
-    }
-    @Test
-    public void testSomeGet() {
-        TestingFields tf = []
-        assertEquals( [6, -7, 7, 8, 9, 60],
-            ["a", "b", "@b", "c", "d", TestingFields.aa].collect {
-                LanguageUtils.DEFAULT_FIELD_GETTER.call(tf, it)
-            })
-    }
-    
-    @Test
-    public void testEquals() {
-        //basic
-        TestingFields t1 = [], t2 = []
-        assertTrue LanguageUtils.equals(t1, t2, null, ["a", "b"])
-        assertTrue LanguageUtils.equals(t1, t2, TestingFields, ["a", "b"])
-        assertFalse LanguageUtils.equals(t1, t2, String, ["a", "b"])
-        assertFalse LanguageUtils.equals(t1, t2, null, ["z"])
-        assertTrue LanguageUtils.equals(t1, t2, null, (["a", "b"] as String[]))
-        
-        //type hierarchy
-        TestingFieldA t1a = []
-        assertTrue LanguageUtils.equals(t1, t1a, null, "a")
-        assertTrue LanguageUtils.equals(t1, t1a, TestingFieldA, "a")
-        assertFalse LanguageUtils.equals(t1, t1a, TestingFields, "a")
-        assertFalse LanguageUtils.equals(t1, t1a, null, "a", "b")
-        t1.b = 0
-        assertTrue LanguageUtils.equals(t1, t1a, null, "a")
-        t1a.a = -6
-        assertFalse LanguageUtils.equals(t1, t1a, null, "a")
-        
-        //direct access to field
-        assertTrue LanguageUtils.equals(t1, t2, null, "b")
-        assertFalse LanguageUtils.equals(t1, t2, null, "@b")
-        assertTrue LanguageUtils.equals(t1, t2, null, "@a")
-        
-        //and complex field
-        assertTrue LanguageUtils.equals(t1, t2, null, TestingFields.aa)
-        //because we changed t1a.a, and getAt(A) refers to int a
-        assertFalse LanguageUtils.equals(t1, t1a, null, TestingFields.aa)
-        
-        //test it works with POJO objects (non-groovy)
-        assertTrue LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(1), null, "privateInt")
-        assertFalse LanguageUtils.equals(new PojoTestingFields(1), new PojoTestingFields(2), null, "privateInt")
-        
-        //and a tricky one, because x is a groovy property, it is _private_ so we cannot see it as a field wrt t1
-        assertFalse LanguageUtils.equals(t1, t1a, null, "@x")
-        //but in the context of t1a we can.. in short, be careful with fields
-        assertTrue LanguageUtils.equals(t1a, t1a, null, "@x")
-    }
-
-    @Test
-    public void testHashCode() {
-        //basic
-        TestingFields t1 = [], t2 = []
-        assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"])
-        assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"])
-        assertFalse LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "@b"])
-        t2.b = 0;
-        assertTrue LanguageUtils.hashCode(t1, ["a", "b"]) == LanguageUtils.hashCode(t2, ["a", "b"])
-        assertTrue LanguageUtils.hashCode(t1, ["a", "@b"]) == LanguageUtils.hashCode(t2, ["a", "@b"])
-        assertEquals 0, LanguageUtils.hashCode(null, ["a", "@b"])
-    }
-    
-    @Test
-    public void testToString() {
-        TestingFields t1 = [];
-        assertEquals(LanguageUtils.toString(t1, ["a", "b"]), "TestingFields[a=6,b=-7]");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/18c28d24/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy
----------------------------------------------------------------------
diff --git a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy b/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy
deleted file mode 100644
index 11ae3d0..0000000
--- a/utils/groovy/src/test/java/org/apache/brooklyn/util/groovy/TimeExtrasTest.groovy
+++ /dev/null
@@ -1,49 +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 org.apache.brooklyn.util.groovy;
-
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import groovy.time.TimeDuration
-
-import org.testng.annotations.BeforeMethod
-import org.testng.annotations.Test
-
-/**
- * Test the operation of the {@link TimeExtras} class.
- * 
- * TODO clarify test purpose
- */
-public class TimeExtrasTest {
-    @BeforeMethod
-    public void setUp() throws Exception {
-        TimeExtras.init();
-    }
-
-    @Test
-    public void testMultiplyTimeDurations() {
-        assertEquals(new TimeDuration(6).toMilliseconds(), (new TimeDuration(3)*2).toMilliseconds());
-    }
-
-    @Test
-    public void testAddTimeDurations() {
-        assertEquals(new TimeDuration(0,2,5,0).toMilliseconds(), (5*SECONDS + 2*MINUTES).toMilliseconds());
-    }
-}