You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/06/24 10:05:12 UTC

[01/22] incubator-brooklyn git commit: yaml-friendly enrichers for delta and rolling avg

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master b08fe4eca -> 45dd54940


yaml-friendly enrichers for delta and rolling avg


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

Branch: refs/heads/master
Commit: 089fe862677e5588b68b9c084fefe88fb2cc2a1d
Parents: 78cbc22
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jun 19 04:56:39 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:32 2015 -0700

----------------------------------------------------------------------
 .../enricher/basic/AbstractTransformer.java     | 106 +++++++++++
 .../brooklyn/enricher/basic/Transformer.java    |  64 +------
 .../YamlRollingTimeWindowMeanEnricher.java      | 178 +++++++++++++++++++
 .../basic/YamlTimeWeightedDeltaEnricher.java    |  81 +++++++++
 .../YamlRollingTimeWindowMeanEnricherTest.java  | 178 +++++++++++++++++++
 .../YamlTimeWeightedDeltaEnricherTest.java      | 107 +++++++++++
 .../enricher/RollingTimeWindowMeanEnricher.java |   4 +-
 .../enricher/TimeWeightedDeltaEnricher.java     |   3 +
 8 files changed, 658 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/089fe862/core/src/main/java/brooklyn/enricher/basic/AbstractTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractTransformer.java b/core/src/main/java/brooklyn/enricher/basic/AbstractTransformer.java
new file mode 100644
index 0000000..28a6de1
--- /dev/null
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractTransformer.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 brooklyn.enricher.basic;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.EntityLocal;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.Sensor;
+import brooklyn.event.SensorEvent;
+import brooklyn.event.SensorEventListener;
+import brooklyn.event.basic.BasicSensorEvent;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.task.Tasks;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+import com.google.common.reflect.TypeToken;
+
+@SuppressWarnings("serial")
+public abstract class AbstractTransformer<T,U> extends AbstractEnricher implements SensorEventListener<T> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractTransformer.class);
+
+    public static ConfigKey<Entity> PRODUCER = ConfigKeys.newConfigKey(Entity.class, "enricher.producer");
+
+    public static ConfigKey<Sensor<?>> SOURCE_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.sourceSensor");
+
+    public static ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor");
+    
+    protected Entity producer;
+    protected Sensor<T> sourceSensor;
+    protected Sensor<U> targetSensor;
+
+    public AbstractTransformer() {
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public void setEntity(EntityLocal entity) {
+        super.setEntity(entity);
+
+        Function<SensorEvent<T>, U> transformation = getTransformation();
+        this.producer = getConfig(PRODUCER) == null ? entity: getConfig(PRODUCER);
+        this.sourceSensor = (Sensor<T>) getRequiredConfig(SOURCE_SENSOR);
+        Sensor<?> targetSensorSpecified = getConfig(TARGET_SENSOR);
+        this.targetSensor = targetSensorSpecified!=null ? (Sensor<U>) targetSensorSpecified : (Sensor<U>) this.sourceSensor;
+        if (producer.equals(entity) && targetSensorSpecified==null) {
+            LOG.error("Refusing to add an enricher which reads and publishes on the same sensor: "+
+                producer+"."+sourceSensor+" (computing "+transformation+")");
+            // we don't throw because this error may manifest itself after a lengthy deployment, 
+            // and failing it at that point simply because of an enricher is not very pleasant
+            // (at least not until we have good re-run support across the board)
+            return;
+        }
+        
+        subscribe(producer, sourceSensor, this);
+        
+        if (sourceSensor instanceof AttributeSensor) {
+            Object value = producer.getAttribute((AttributeSensor<?>)sourceSensor);
+            // TODO would be useful to have a convenience to "subscribeAndThenIfItIsAlreadySetRunItOnce"
+            if (value!=null) {
+                onEvent(new BasicSensorEvent(sourceSensor, producer, value, -1));
+            }
+        }
+    }
+
+    /** returns a function for transformation, for immediate use only (not for caching, as it may change) */
+    protected abstract Function<SensorEvent<T>, U> getTransformation();
+
+    @Override
+    public void onEvent(SensorEvent<T> event) {
+        emit(targetSensor, compute(event));
+    }
+
+    protected Object compute(SensorEvent<T> event) {
+        // transformation is not going to change, but this design makes it easier to support changing config in future. 
+        // if it's an efficiency hole we can switch to populate the transformation at start.
+        U result = getTransformation().apply(event);
+        if (LOG.isTraceEnabled())
+            LOG.trace("Enricher "+this+" computed "+result+" from "+event);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/089fe862/core/src/main/java/brooklyn/enricher/basic/Transformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Transformer.java b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
index c6c88a6..2fa85fe 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Transformer.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
@@ -24,14 +24,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
-import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.EntityLocal;
-import brooklyn.event.AttributeSensor;
-import brooklyn.event.Sensor;
 import brooklyn.event.SensorEvent;
-import brooklyn.event.SensorEventListener;
-import brooklyn.event.basic.BasicSensorEvent;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
@@ -41,7 +35,7 @@ import com.google.common.reflect.TypeToken;
 
 //@Catalog(name="Transformer", description="Transforms attributes of an entity; see Enrichers.builder().transforming(...)")
 @SuppressWarnings("serial")
-public class Transformer<T,U> extends AbstractEnricher implements SensorEventListener<T> {
+public class Transformer<T,U> extends AbstractTransformer<T,U> {
 
     private static final Logger LOG = LoggerFactory.getLogger(Transformer.class);
 
@@ -50,50 +44,11 @@ public class Transformer<T,U> extends AbstractEnricher implements SensorEventLis
     public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_VALUE = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation");
     public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_EVENT = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation.fromevent");
     
-    public static ConfigKey<Entity> PRODUCER = ConfigKeys.newConfigKey(Entity.class, "enricher.producer");
-
-    public static ConfigKey<Sensor<?>> SOURCE_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.sourceSensor");
-
-    public static ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor");
-    
-    protected Entity producer;
-    protected Sensor<T> sourceSensor;
-    protected Sensor<U> targetSensor;
-
     public Transformer() {
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    public void setEntity(EntityLocal entity) {
-        super.setEntity(entity);
-
-        Function<SensorEvent<T>, U> transformation = getTransformation();
-        this.producer = getConfig(PRODUCER) == null ? entity: getConfig(PRODUCER);
-        this.sourceSensor = (Sensor<T>) getRequiredConfig(SOURCE_SENSOR);
-        Sensor<?> targetSensorSpecified = getConfig(TARGET_SENSOR);
-        this.targetSensor = targetSensorSpecified!=null ? (Sensor<U>) targetSensorSpecified : (Sensor<U>) this.sourceSensor;
-        if (producer.equals(entity) && targetSensorSpecified==null) {
-            LOG.error("Refusing to add an enricher which reads and publishes on the same sensor: "+
-                producer+"."+sourceSensor+" (computing "+transformation+")");
-            // we don't throw because this error may manifest itself after a lengthy deployment, 
-            // and failing it at that point simply because of an enricher is not very pleasant
-            // (at least not until we have good re-run support across the board)
-            return;
-        }
-        
-        subscribe(producer, sourceSensor, this);
-        
-        if (sourceSensor instanceof AttributeSensor) {
-            Object value = producer.getAttribute((AttributeSensor<?>)sourceSensor);
-            // TODO would be useful to have a convenience to "subscribeAndThenIfItIsAlreadySetRunItOnce"
-            if (value!=null) {
-                onEvent(new BasicSensorEvent(sourceSensor, producer, value, -1));
-            }
-        }
-    }
-
     /** returns a function for transformation, for immediate use only (not for caching, as it may change) */
+    @Override
     @SuppressWarnings("unchecked")
     protected Function<SensorEvent<T>, U> getTransformation() {
         MutableSet<Object> suppliers = MutableSet.of();
@@ -144,18 +99,5 @@ public class Transformer<T,U> extends AbstractEnricher implements SensorEventLis
             }
         };
     }
-
-    @Override
-    public void onEvent(SensorEvent<T> event) {
-        emit(targetSensor, compute(event));
-    }
-
-    protected Object compute(SensorEvent<T> event) {
-        // transformation is not going to change, but this design makes it easier to support changing config in future. 
-        // if it's an efficiency hole we can switch to populate the transformation at start.
-        U result = getTransformation().apply(event);
-        if (LOG.isTraceEnabled())
-            LOG.trace("Enricher "+this+" computed "+result+" from "+event);
-        return result;
-    }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/089fe862/core/src/main/java/brooklyn/enricher/basic/YamlRollingTimeWindowMeanEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/YamlRollingTimeWindowMeanEnricher.java b/core/src/main/java/brooklyn/enricher/basic/YamlRollingTimeWindowMeanEnricher.java
new file mode 100644
index 0000000..64333d4
--- /dev/null
+++ b/core/src/main/java/brooklyn/enricher/basic/YamlRollingTimeWindowMeanEnricher.java
@@ -0,0 +1,178 @@
+/*
+ * 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.enricher.basic;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.event.Sensor;
+import brooklyn.event.SensorEvent;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+
+/**
+ * Transforms {@link Sensor} data into a rolling average based on a time window.
+ * 
+ * All values within the window are weighted or discarded based on the timestamps associated with
+ * them (discards occur when a new value is added or an average is requested)
+ * <p>
+ * This will not extrapolate figures - it is assumed a value is valid and correct for the entire
+ * time period between it and the previous value. Normally, the average attribute is only updated
+ * when a new value arrives so it can give a fully informed average, but there is a danger of this
+ * going stale.
+ * <p>
+ * When an average is requested, it is likely there will be a segment of the window for which there
+ * isn't a value. Instead of extrapolating a value and providing different extrapolation techniques,
+ * the average is reported with a confidence value which reflects the fraction of the time
+ * window for which the values were valid.
+ * <p>
+ * Consumers of the average may ignore the confidence value and just use the last known average.
+ * They could multiply the returned value by the confidence value to get a decay-type behavior as
+ * the window empties. A third alternative is to, at a certain confidence threshold, report that
+ * the average is no longer meaningful.
+ * <p>
+ * The default average when no data has been received is 0, with a confidence of 0
+ */
+public class YamlRollingTimeWindowMeanEnricher<T extends Number> extends AbstractTransformer<T,Double> {
+    
+    public static ConfigKey<Duration> WINDOW_DURATION = ConfigKeys.newConfigKey(Duration.class, "enricher.window.duration",
+        "Duration for which this window should store data, default one minute", Duration.ONE_MINUTE);
+
+    public static ConfigKey<Double> CONFIDENCE_REQUIRED_TO_PUBLISH = ConfigKeys.newDoubleConfigKey("enricher.window.confidenceRequired",
+        "Minimum confidence level (ie period covered) required to publish a rolling average", 0.8d);
+
+    public static class ConfidenceQualifiedNumber {
+        final Double value;
+        final double confidence;
+        
+        public ConfidenceQualifiedNumber(Double value, double confidence) {
+            this.value = value;
+            this.confidence = confidence;
+        }
+        
+        @Override
+        public String toString() {
+            return ""+value+" ("+(int)(confidence*100)+"%)";
+        } 
+        
+    }
+    
+    private final LinkedList<T> values = new LinkedList<T>();
+    private final LinkedList<Long> timestamps = new LinkedList<Long>();
+    volatile ConfidenceQualifiedNumber lastAverage = new ConfidenceQualifiedNumber(0d,0d);
+    
+    @Override
+    protected Function<SensorEvent<T>, Double> getTransformation() {
+        return new Function<SensorEvent<T>, Double>() {
+            @Override
+            public Double apply(SensorEvent<T> event) {
+                long eventTime = event.getTimestamp();
+                if (event.getValue()==null) {
+                    return null;
+                }
+                values.addLast(event.getValue());
+                timestamps.addLast(eventTime);
+                if (eventTime>0) {
+                    ConfidenceQualifiedNumber average = getAverage(eventTime, 0);
+
+                    if (average.confidence > getConfig(CONFIDENCE_REQUIRED_TO_PUBLISH)) { 
+                        // without confidence, we might publish wildly varying estimates,
+                        // causing spurious resizes, so allow it to be configured, and
+                        // by default require a high value
+
+                        // TODO would be nice to include timestamp, etc
+                        return average.value; 
+                    }
+                }
+                return null;
+            }
+        };
+    }
+    
+    public ConfidenceQualifiedNumber getAverage(long fromTime, long graceAllowed) {
+        if (timestamps.isEmpty()) {
+            return lastAverage = new ConfidenceQualifiedNumber(lastAverage.value, 0.0d);
+        }
+        
+        long firstTimestamp = -1;
+        Iterator<Long> ti = timestamps.iterator();
+        while (ti.hasNext()) {
+            firstTimestamp = ti.next();
+            if (firstTimestamp>0) break;
+        }
+        if (firstTimestamp<=0) {
+            // no values with reasonable timestamps
+            return lastAverage = new ConfidenceQualifiedNumber(values.get(values.size()-1).doubleValue(), 0.0d);
+        }
+
+        long lastTimestamp = timestamps.get(timestamps.size()-1);
+
+        long now = fromTime;
+        if (lastTimestamp > fromTime - graceAllowed) {
+            // without this, if the computation takes place X seconds after the publish,
+            // we treat X seconds as time for which we have no confidence in the data
+            now = lastTimestamp;
+        }
+        pruneValues(now);
+        
+        Duration timePeriod = getConfig(WINDOW_DURATION);
+        long windowStart = Math.max(now-timePeriod.toMilliseconds(), firstTimestamp);
+        long windowEnd = Math.max(now-timePeriod.toMilliseconds(), lastTimestamp);
+        Double confidence = ((double)(windowEnd - windowStart)) / timePeriod.toMilliseconds();
+        if (confidence <= 0.0000001d) {
+            // not enough timestamps in window 
+            double lastValue = values.get(values.size()-1).doubleValue();
+            return lastAverage = new ConfidenceQualifiedNumber(lastValue, 0.0d);
+        }
+        
+        long start = windowStart;
+        long end;
+        double weightedAverage = 0.0d;
+        
+        Iterator<T> valuesIter = values.iterator();
+        Iterator<Long> timestampsIter = timestamps.iterator();
+        while (valuesIter.hasNext()) {
+            // Ignores null and out-of-date values (and also values that are received out-of-order, but that shouldn't happen!)
+            Number val = valuesIter.next();
+            Long timestamp = timestampsIter.next();
+            if (val!=null && timestamp >= start) {
+                end = timestamp;
+                weightedAverage += ((end - start) / (confidence * timePeriod.toMilliseconds())) * val.doubleValue();
+                start = timestamp;
+            }
+        }
+        
+        return lastAverage = new ConfidenceQualifiedNumber(weightedAverage, confidence);
+    }
+    
+    /**
+     * Discards out-of-date values, but keeps at least one value.
+     */
+    private void pruneValues(long now) {
+        // keep one value from before the period, so that we can tell the window's start time
+        Duration timePeriod = getConfig(WINDOW_DURATION);
+        while(timestamps.size() > 1 && timestamps.get(1) < (now - timePeriod.toMilliseconds())) {
+            timestamps.removeFirst();
+            values.removeFirst();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/089fe862/core/src/main/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricher.java b/core/src/main/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricher.java
new file mode 100644
index 0000000..b515da4
--- /dev/null
+++ b/core/src/main/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricher.java
@@ -0,0 +1,81 @@
+/*
+ * 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.enricher.basic;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.enricher.basic.AbstractTransformer;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.event.SensorEvent;
+import brooklyn.util.flags.TypeCoercions;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+
+/**
+ * Converts an absolute count sensor into a delta sensor (i.e. the diff between the current and previous value),
+ * presented as a units/timeUnit based on the event timing.
+ * <p>
+ * For example, given a requests.count sensor, this can make a requests.per_sec sensor with {@link #DELTA_PERIOD} set to "1s" (the default).
+ * <p>
+ * Suitable for configuration from YAML.
+ */
+public class YamlTimeWeightedDeltaEnricher<T extends Number> extends AbstractTransformer<T,Double> {
+    private static final Logger LOG = LoggerFactory.getLogger(YamlTimeWeightedDeltaEnricher.class);
+    
+    Number lastValue;
+    long lastTime = -1;
+    
+    public static ConfigKey<Duration> DELTA_PERIOD = ConfigKeys.newConfigKey(Duration.class, "enricher.delta.period",
+        "Duration that this delta should compute for, default per second", Duration.ONE_SECOND);
+    
+    @Override
+    protected Function<SensorEvent<T>, Double> getTransformation() {
+        return new Function<SensorEvent<T>, Double>() {
+            @Override
+            public Double apply(SensorEvent<T> event) {
+                Number current = TypeCoercions.coerce(event.getValue(), Double.class);
+                
+                if (current == null) return null;
+
+                long eventTime = event.getTimestamp();
+                long unitMillis = getConfig(DELTA_PERIOD).toMilliseconds();
+                Double result = null;
+                
+                if (eventTime > 0 && eventTime > lastTime) {
+                    if (lastValue == null || lastTime < 0) {
+                        // cannot calculate time-based delta with a single value
+                        if (LOG.isTraceEnabled()) LOG.trace("{} received event but no last value so will not emit, null -> {} at {}", new Object[] {this, current, eventTime}); 
+                    } else {
+                        double duration = eventTime - lastTime;
+                        result = (current.doubleValue() - lastValue.doubleValue()) / (duration / unitMillis);
+                    }
+                }
+                
+                lastValue = current;
+                lastTime = eventTime;
+                
+                return result;
+            }
+        };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/089fe862/core/src/test/java/brooklyn/enricher/basic/YamlRollingTimeWindowMeanEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/enricher/basic/YamlRollingTimeWindowMeanEnricherTest.java b/core/src/test/java/brooklyn/enricher/basic/YamlRollingTimeWindowMeanEnricherTest.java
new file mode 100644
index 0000000..45b7ec3
--- /dev/null
+++ b/core/src/test/java/brooklyn/enricher/basic/YamlRollingTimeWindowMeanEnricherTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.enricher.basic;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.enricher.basic.YamlRollingTimeWindowMeanEnricher.ConfidenceQualifiedNumber;
+import brooklyn.entity.basic.AbstractApplication;
+import brooklyn.entity.basic.BasicEntity;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.BasicAttributeSensor;
+import brooklyn.event.basic.BasicSensorEvent;
+import brooklyn.management.SubscriptionContext;
+import brooklyn.policy.EnricherSpec;
+import brooklyn.util.time.Duration;
+
+public class YamlRollingTimeWindowMeanEnricherTest {
+    
+    AbstractApplication app;
+    
+    BasicEntity producer;
+
+    AttributeSensor<Integer> intSensor;
+    AttributeSensor<Double> avgSensor, deltaSensor;
+    
+    Duration timePeriod = Duration.ONE_SECOND;
+    
+    YamlTimeWeightedDeltaEnricher<Double> delta;
+    YamlRollingTimeWindowMeanEnricher<Double> averager;
+    
+    ConfidenceQualifiedNumber average;
+    SubscriptionContext subscription;
+    
+    @SuppressWarnings("unchecked")
+    @BeforeMethod
+    public void before() {
+        app = new AbstractApplication() {};
+        Entities.startManagement(app);
+        producer = app.addChild(EntitySpec.create(BasicEntity.class));
+
+        intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor");
+        deltaSensor = new BasicAttributeSensor<Double>(Double.class, "delta sensor");
+        avgSensor = new BasicAttributeSensor<Double>(Double.class, "avg sensor");
+            
+        delta = producer.addEnricher(EnricherSpec.create(YamlTimeWeightedDeltaEnricher.class)
+                .configure(YamlTimeWeightedDeltaEnricher.PRODUCER, producer)
+                .configure(YamlTimeWeightedDeltaEnricher.SOURCE_SENSOR, intSensor)
+                .configure(YamlTimeWeightedDeltaEnricher.TARGET_SENSOR, deltaSensor));
+
+        averager = producer.addEnricher(EnricherSpec.create(YamlRollingTimeWindowMeanEnricher.class)
+                .configure(YamlRollingTimeWindowMeanEnricher.PRODUCER, producer)
+                .configure(YamlRollingTimeWindowMeanEnricher.SOURCE_SENSOR, deltaSensor)
+                .configure(YamlRollingTimeWindowMeanEnricher.TARGET_SENSOR, avgSensor)
+                .configure(YamlRollingTimeWindowMeanEnricher.WINDOW_DURATION, timePeriod));
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+        
+    @Test
+    public void testDefaultAverageWhenEmpty() {
+        ConfidenceQualifiedNumber average = averager.getAverage(0, 0);
+        assertEquals(average.value, 0d);
+        assertEquals(average.confidence, 0.0d);
+    }
+    
+    protected BasicSensorEvent<Integer> newIntSensorEvent(int value, long timestamp) {
+        return new BasicSensorEvent<Integer>(intSensor, producer, value, timestamp);
+    }
+    protected BasicSensorEvent<Double> newDeltaSensorEvent(double value, long timestamp) {
+        return new BasicSensorEvent<Double>(deltaSensor, producer, value, timestamp);
+    }
+
+    @Test
+    public void testNoRecentValuesAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 0));
+        average = averager.getAverage(timePeriod.toMilliseconds()+1000, 0);
+        assertEquals(average.value, 10d);
+        assertEquals(average.confidence, 0d);
+    }
+
+    @Test
+    public void testNoRecentValuesUsesLastForAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 0));
+        averager.onEvent(newDeltaSensorEvent(20, 10));
+        average = averager.getAverage(timePeriod.toMilliseconds()+1000, 0);
+        assertEquals(average.value, 20d);
+        assertEquals(average.confidence, 0d);
+    }
+
+    @Test
+    public void testSingleValueTimeAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 1000));
+        average = averager.getAverage(1000, 0);
+        assertEquals(average.confidence, 0d);
+    }
+
+    @Test
+    public void testTwoValueAverageForPeriod() {
+        averager.onEvent(newDeltaSensorEvent(10, 1000));
+        averager.onEvent(newDeltaSensorEvent(10, 2000));
+        average = averager.getAverage(2000, 0);
+        assertEquals(average.value, 10 /1d);
+        assertEquals(average.confidence, 1d);
+    }
+
+    @Test
+    public void testMonospacedAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 1000));
+        averager.onEvent(newDeltaSensorEvent(20, 1250));
+        averager.onEvent(newDeltaSensorEvent(30, 1500));
+        averager.onEvent(newDeltaSensorEvent(40, 1750));
+        averager.onEvent(newDeltaSensorEvent(50, 2000));
+        average = averager.getAverage(2000, 0);
+        assertEquals(average.value, (20+30+40+50)/4d);
+        assertEquals(average.confidence, 1d);
+    }
+
+    @Test
+    public void testWeightedAverage() {
+        averager.onEvent(newDeltaSensorEvent(10, 1000));
+        averager.onEvent(newDeltaSensorEvent(20, 1100));
+        averager.onEvent(newDeltaSensorEvent(30, 1300));
+        averager.onEvent(newDeltaSensorEvent(40, 1600));
+        averager.onEvent(newDeltaSensorEvent(50, 2000));
+        
+        average = averager.getAverage(2000, 0);
+        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(newDeltaSensorEvent(10, 1000));
+        averager.onEvent(newDeltaSensorEvent(20, 1250));
+        averager.onEvent(newDeltaSensorEvent(30, 1500));
+        averager.onEvent(newDeltaSensorEvent(40, 1750));
+        averager.onEvent(newDeltaSensorEvent(50, 2000));
+
+        average = averager.getAverage(2250, 0);
+        assertEquals(average.value, (30+40+50)/3d);
+        assertEquals(average.confidence, 0.75d);
+        average = averager.getAverage(2500, 0);
+        assertEquals(average.value, (40+50)/2d);
+        assertEquals(average.confidence, 0.5d);
+        average = averager.getAverage(2750, 0);
+        assertEquals(average.value, 50d);
+        assertEquals(average.confidence, 0.25d);
+        average = averager.getAverage(3000, 0);
+        assertEquals(average.value, 50d);
+        assertEquals(average.confidence, 0d);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/089fe862/core/src/test/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricherTest.java b/core/src/test/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricherTest.java
new file mode 100644
index 0000000..2a7a974
--- /dev/null
+++ b/core/src/test/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricherTest.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 brooklyn.enricher.basic;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.AbstractApplication;
+import brooklyn.entity.basic.BasicEntity;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.proxying.EntitySpec;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.BasicAttributeSensor;
+import brooklyn.event.basic.BasicSensorEvent;
+import brooklyn.management.SubscriptionContext;
+import brooklyn.policy.EnricherSpec;
+
+public class YamlTimeWeightedDeltaEnricherTest {
+    
+    AbstractApplication app;
+    
+    BasicEntity producer;
+
+    AttributeSensor<Integer> intSensor;
+    AttributeSensor<Double> avgSensor, deltaSensor;
+    SubscriptionContext subscription;
+    
+    @BeforeMethod
+    public void before() {
+        app = new AbstractApplication() {};
+        Entities.startManagement(app);
+        producer = app.addChild(EntitySpec.create(BasicEntity.class));
+
+        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 testMonospaceTimeWeightedDeltaEnricher() {
+        @SuppressWarnings("unchecked")
+        YamlTimeWeightedDeltaEnricher<Integer> delta = producer.addEnricher(EnricherSpec.create(YamlTimeWeightedDeltaEnricher.class)
+            .configure(YamlTimeWeightedDeltaEnricher.PRODUCER, producer)
+            .configure(YamlTimeWeightedDeltaEnricher.SOURCE_SENSOR, intSensor)
+            .configure(YamlTimeWeightedDeltaEnricher.TARGET_SENSOR, deltaSensor));
+        
+        delta.onEvent(newIntSensorEvent(0, 0));
+        assertEquals(producer.getAttribute(deltaSensor), null);
+        delta.onEvent(newIntSensorEvent(0, 1000));
+        assertEquals(producer.getAttribute(deltaSensor), 0d);
+        delta.onEvent(newIntSensorEvent(1, 2000));
+        assertEquals(producer.getAttribute(deltaSensor), 1d);
+        delta.onEvent(newIntSensorEvent(3, 3000));
+        assertEquals(producer.getAttribute(deltaSensor), 2d);
+        delta.onEvent(newIntSensorEvent(8, 4000));
+        assertEquals(producer.getAttribute(deltaSensor), 5d);
+    }
+    
+    protected BasicSensorEvent<Integer> newIntSensorEvent(int value, long timestamp) {
+        return new BasicSensorEvent<Integer>(intSensor, producer, value, timestamp);
+    }
+    
+    @Test
+    public void testVariableTimeWeightedDeltaEnricher() {
+        @SuppressWarnings("unchecked")
+        YamlTimeWeightedDeltaEnricher<Integer> delta = producer.addEnricher(EnricherSpec.create(YamlTimeWeightedDeltaEnricher.class)
+            .configure(YamlTimeWeightedDeltaEnricher.PRODUCER, producer)
+            .configure(YamlTimeWeightedDeltaEnricher.SOURCE_SENSOR, intSensor)
+            .configure(YamlTimeWeightedDeltaEnricher.TARGET_SENSOR, deltaSensor));
+        
+        delta.onEvent(newIntSensorEvent(0, 0));
+        delta.onEvent(newIntSensorEvent(0, 2000));
+        assertEquals(producer.getAttribute(deltaSensor), 0d);
+        delta.onEvent(newIntSensorEvent(3, 5000));
+        assertEquals(producer.getAttribute(deltaSensor), 1d);
+        delta.onEvent(newIntSensorEvent(7, 7000));
+        assertEquals(producer.getAttribute(deltaSensor), 2d);
+        delta.onEvent(newIntSensorEvent(12, 7500));
+        assertEquals(producer.getAttribute(deltaSensor), 10d);
+        delta.onEvent(newIntSensorEvent(15, 9500));
+        assertEquals(producer.getAttribute(deltaSensor), 1.5d);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/089fe862/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java b/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
index 694977c..7c55a81 100644
--- a/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
@@ -128,12 +128,12 @@ public class RollingTimeWindowMeanEnricher<T extends Number> extends AbstractTyp
         }
     }
     
-    @Deprecated /** @deprecatedsince 0.7.0; not used; use the 2-arg method */
+    @Deprecated /** @deprecated since 0.7.0; not used except in groovy tests; use the 2-arg method */
     public ConfidenceQualifiedNumber getAverage() {
         return getAverage(System.currentTimeMillis(), 0);
     }
     
-    @Deprecated /** @deprecated since 0.7.0; not used; use the 2-arg method */
+    @Deprecated /** @deprecated since 0.7.0; not used except in groovy tests; use the 2-arg method */
     public ConfidenceQualifiedNumber getAverage(long fromTimeExact) {
         return getAverage(fromTimeExact, 0);
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/089fe862/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java b/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
index b746edd..42e418f 100644
--- a/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
@@ -24,6 +24,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.enricher.basic.AbstractTypeTransformingEnricher;
+import brooklyn.enricher.basic.YamlTimeWeightedDeltaEnricher;
 import brooklyn.entity.Entity;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.Sensor;
@@ -41,6 +42,8 @@ import com.google.common.base.Functions;
  * presented as a units/timeUnit based on the event timing.
  * <p>
  * NB for time (e.g. "total milliseconds consumed") use {@link TimeFractionDeltaEnricher}
+ * <p>
+ * See also {@link YamlTimeWeightedDeltaEnricher} designed for use from YAML.
  */
 //@Catalog(name="Time-weighted Delta", description="Converts an absolute sensor into a delta sensor "
 //        + "(i.e. the diff between the current and previous value), presented as a units/timeUnit "


[02/22] incubator-brooklyn git commit: improve ValueResolver task+timeout, and related work on tasks

Posted by he...@apache.org.
improve ValueResolver task+timeout, and related work on tasks

ValueResolver will now look if it is already in a task when computing the execution context,
so more things which need a context and/or have timeouts can be handled correctly --
esp when $brooklyn:config is passed from yaml to various places

More tasks are marked transient so don't clutter the GUI.

Cancellations are treated better, with fewer errors.

Also shell env vars where values are null are now treated as "" rather than "null",
and a few other string handling goodies


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

Branch: refs/heads/master
Commit: 78cbc22fff260ba13c8db622d8cfb8fad458e02f
Parents: ceee1c0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jun 18 08:56:17 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:32 2015 -0700

----------------------------------------------------------------------
 api/src/main/java/brooklyn/event/Sensor.java    |  4 +-
 .../main/java/brooklyn/enricher/Enrichers.java  |  5 +-
 .../internal/LocalSubscriptionManager.java      |  4 +-
 .../java/brooklyn/util/flags/TypeCoercions.java |  2 +-
 .../java/brooklyn/util/task/ValueResolver.java  | 65 +++++++++++++++-----
 .../util/internal/TypeCoercionsTest.java        |  2 +-
 .../policy/ha/AbstractFailureDetector.java      |  4 +-
 .../brooklyn/policy/ha/ServiceRestarter.java    |  3 +-
 .../policy/ha/SshMachineFailureDetector.java    |  1 -
 .../basic/AbstractSoftwareProcessSshDriver.java |  2 +-
 .../brooklyn/entity/software/StaticSensor.java  | 19 +++++-
 .../entity/software/ssh/SshCommandEffector.java |  2 +-
 .../entity/software/ssh/SshCommandSensor.java   |  2 +-
 .../spi/dsl/methods/BrooklynDslCommon.java      | 31 +++++-----
 .../brooklyn/spi/dsl/methods/DslComponent.java  | 25 +++++---
 .../java/brooklyn/util/text/StringEscapes.java  | 20 ++++--
 .../main/java/brooklyn/util/text/Strings.java   | 28 ++++++++-
 .../main/java/brooklyn/util/time/Durations.java |  3 +
 18 files changed, 159 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/api/src/main/java/brooklyn/event/Sensor.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/brooklyn/event/Sensor.java b/api/src/main/java/brooklyn/event/Sensor.java
index 88b0d13..2057020 100644
--- a/api/src/main/java/brooklyn/event/Sensor.java
+++ b/api/src/main/java/brooklyn/event/Sensor.java
@@ -39,8 +39,8 @@ public interface Sensor<T> extends Serializable {
      * <p>
      * This returns a "super" of T only in the case where T is generified, 
      * and in such cases it returns the Class instance for the unadorned T ---
-     * i.e. for List<String> this returns Class<List> ---
-     * this is of course because there is no actual Class<List<String>> instance.
+     * i.e. for List&lt;String&gt; this returns Class<List> ---
+     * this is of course because there is no actual Class&lt;List&lt;String&gt;&gt; instance.
      */
     Class<? super T> getType();
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/core/src/main/java/brooklyn/enricher/Enrichers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/Enrichers.java b/core/src/main/java/brooklyn/enricher/Enrichers.java
index d036b11..b34fc76 100644
--- a/core/src/main/java/brooklyn/enricher/Enrichers.java
+++ b/core/src/main/java/brooklyn/enricher/Enrichers.java
@@ -157,7 +157,8 @@ public class Enrichers {
             return new CombinerBuilder<S, Object>(vals);
         }
         /** as {@link #combining(Collection)} */
-        public <S> CombinerBuilder<S, Object> combining(AttributeSensor<? extends S>... vals) {
+        @SafeVarargs
+        public final <S> CombinerBuilder<S, Object> combining(AttributeSensor<? extends S>... vals) {
             return new CombinerBuilder<S, Object>(vals);
         }
         /** as {@link #combining(Collection)} but the collection of values comes from the given sensor on multiple entities */
@@ -351,6 +352,7 @@ public class Enrichers {
         // For summing/averaging
         protected Object defaultValueForUnreportedSensors;
         
+        @SafeVarargs
         public AbstractCombinerBuilder(AttributeSensor<? extends S>... vals) {
             this(ImmutableList.copyOf(vals));
         }
@@ -706,6 +708,7 @@ public class Enrichers {
     }
 
     public static class CombinerBuilder<S, T> extends AbstractCombinerBuilder<S, T, CombinerBuilder<S, T>> {
+        @SafeVarargs
         public CombinerBuilder(AttributeSensor<? extends S>... vals) {
             super(vals);
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java b/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java
index 805bf85..7121fc3 100644
--- a/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java
+++ b/core/src/main/java/brooklyn/management/internal/LocalSubscriptionManager.java
@@ -200,9 +200,9 @@ public class LocalSubscriptionManager extends AbstractSubscriptionManager {
                             sAtClosureCreation.listener.onEvent(event);
                         } catch (Throwable t) {
                             if (event!=null && event.getSource()!=null && Entities.isNoLongerManaged(event.getSource())) {
-                                LOG.debug("Error in "+this+", after entity unmanaged: "+t, t);
+                                LOG.debug("Error processing subscriptions to "+this+", after entity unmanaged: "+t, t);
                             } else {
-                                LOG.warn("Error in "+this+": "+t, t);
+                                LOG.warn("Error processing subscriptions to "+this+": "+t, t);
                             }
                         }
                     }});

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
index 67011b2..55649e8 100644
--- a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
+++ b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
@@ -430,7 +430,7 @@ public class TypeCoercions {
         try {
             return (T) wrappedType.getMethod("valueOf", String.class).invoke(null, value);
         } catch (Exception e) {
-            ClassCoercionException tothrow = new ClassCoercionException("Cannot coerce type String to "+targetType.getCanonicalName()+" ("+value+"): adapting failed");
+            ClassCoercionException tothrow = new ClassCoercionException("Cannot coerce "+JavaStringEscapes.wrapJavaString(value)+" to "+targetType.getCanonicalName()+" ("+value+"): adapting failed");
             tothrow.initCause(e);
             throw tothrow;
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/core/src/main/java/brooklyn/util/task/ValueResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ValueResolver.java b/core/src/main/java/brooklyn/util/task/ValueResolver.java
index 3a15bbd..71b34a0 100644
--- a/core/src/main/java/brooklyn/util/task/ValueResolver.java
+++ b/core/src/main/java/brooklyn/util/task/ValueResolver.java
@@ -29,6 +29,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.Entity;
+import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.management.ExecutionContext;
 import brooklyn.management.Task;
@@ -36,6 +37,7 @@ import brooklyn.management.TaskAdaptable;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
+import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Durations;
@@ -66,6 +68,7 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
     Boolean embedResolutionInTask;
     /** timeout on execution, if possible, or if embedResolutionInTask is true */
     Duration timeout;
+    boolean isTransientTask = true;
     
     T defaultValue = null;
     boolean returnDefaultOnGet = false;
@@ -170,6 +173,12 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
         return this;
     }
     
+    /** whether the task should be marked as transient; defaults true */
+    public ValueResolver<T> transientTask(boolean isTransientTask) {
+        this.isTransientTask = isTransientTask;
+        return this;
+    }
+    
     public Maybe<T> getDefault() {
         if (returnDefaultOnGet) return Maybe.of(defaultValue);
         else return Maybe.absent("No default value set");
@@ -213,13 +222,27 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
         return m.get();
     }
     
-    @SuppressWarnings({ "unchecked", "rawtypes" })
     public Maybe<T> getMaybe() {
+        Maybe<T> result = getMaybeInternal();
+        if (log.isTraceEnabled()) {
+            log.trace(this+" evaluated as "+result);
+        }
+        return result;
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected Maybe<T> getMaybeInternal() {
         if (started.getAndSet(true))
             throw new IllegalStateException("ValueResolver can only be used once");
         
         if (expired) return Maybe.absent("Nested resolution of "+getOriginalValue()+" did not complete within "+timeout);
         
+        ExecutionContext exec = this.exec;
+        if (exec==null) {
+            // if execution context not specified, take it from the current task if present
+            exec = BasicExecutionContext.getCurrentExecutionContext();
+        }
+        
         CountdownTimer timerU = parentTimer;
         if (timerU==null && timeout!=null)
             timerU = timeout.countdownTimer();
@@ -240,7 +263,6 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
             if (v instanceof TaskAdaptable<?>) {
                 //if it's a task, we make sure it is submitted
                 if (!((TaskAdaptable<?>) v).asTask().isSubmitted() ) {
-                    // TODO could try to get exec context from Tasks.current() ... should we?
                     if (exec==null)
                         return Maybe.absent("Value for unsubmitted task '"+getDescription()+"' requested but no execution context available");
                     exec.submit(((TaskAdaptable<?>) v).asTask());
@@ -269,22 +291,24 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
 
             } else if (v instanceof DeferredSupplier<?>) {
                 final Object vf = v;
-                Callable<Object> callable = new Callable<Object>() {
-                    public Object call() throws Exception {
-                        try {
-                            Tasks.setBlockingDetails("Retrieving "+vf);
-                            return ((DeferredSupplier<?>) vf).get();
-                        } finally {
-                            Tasks.resetBlockingDetails();
-                        }
-                    } };
-                    
-                if (Boolean.TRUE.equals(embedResolutionInTask) || timeout!=null) {
+
+                if ((!Boolean.FALSE.equals(embedResolutionInTask) && (exec!=null || timeout!=null)) || Boolean.TRUE.equals(embedResolutionInTask)) {
                     if (exec==null)
                         return Maybe.absent("Embedding in task needed for '"+getDescription()+"' but no execution context available");
                         
+                    Callable<Object> callable = new Callable<Object>() {
+                        public Object call() throws Exception {
+                            try {
+                                Tasks.setBlockingDetails("Retrieving "+vf);
+                                return ((DeferredSupplier<?>) vf).get();
+                            } finally {
+                                Tasks.resetBlockingDetails();
+                            }
+                        } };
                     String description = getDescription();
-                    Task<Object> vt = exec.submit(Tasks.<Object>builder().body(callable).name("Resolving dependent value").description(description).build());
+                    TaskBuilder<Object> vb = Tasks.<Object>builder().body(callable).name("Resolving dependent value").description(description);
+                    if (isTransientTask) vb.tag(BrooklynTaskTags.TRANSIENT_TASK_TAG);
+                    Task<Object> vt = exec.submit(vb.build());
                     // TODO to handle immediate resolution, it would be nice to be able to submit 
                     // so it executes in the current thread,
                     // or put a marker in the target thread or task while it is running that the task 
@@ -296,8 +320,12 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
                     v = vm.get();
                     
                 } else {
-                    v = callable.call();
-                    
+                    try {
+                        Tasks.setBlockingDetails("Retrieving (non-task) "+vf);
+                        v = ((DeferredSupplier<?>) vf).get();
+                    } finally {
+                        Tasks.resetBlockingDetails();
+                    }
                 }
 
             } else if (v instanceof Map) {
@@ -370,4 +398,9 @@ public class ValueResolver<T> implements DeferredSupplier<T> {
         if (parentOriginalValue!=null) return parentOriginalValue;
         return value;
     }
+    
+    @Override
+    public String toString() {
+        return JavaClassNames.cleanSimpleClassName(this)+"["+JavaClassNames.cleanSimpleClassName(type)+" "+value+"]";
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java b/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
index 9b2f6b0..66e7d2c 100644
--- a/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
+++ b/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
@@ -121,7 +121,7 @@ public class TypeCoercionsTest {
     public void testCoercePrimitiveFailures() {
         // error messages don't have to be this exactly, but they should include sufficient information...
         assertCoercionFailsWithErrorMatching("maybe", boolean.class, StringPredicates.containsAllLiterals("String", "boolean", "maybe"));
-        assertCoercionFailsWithErrorMatching("NaN", int.class, StringPredicates.containsAllLiterals("String", "int", "NaN"));
+        assertCoercionFailsWithErrorMatching("NaN", int.class, StringPredicates.containsAllLiterals("int", "NaN"));
         assertCoercionFailsWithErrorMatching('c', boolean.class, StringPredicates.containsAllLiterals("boolean", "(c)"));  // will say 'string' rather than 'char'
         assertCoercionFailsWithErrorMatching(0, boolean.class, StringPredicates.containsAllLiterals("Integer", "boolean", "0"));
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java b/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
index 6a1324c..2c772b8 100644
--- a/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
+++ b/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
@@ -192,10 +192,11 @@ public abstract class AbstractFailureDetector extends AbstractPolicy {
         doStartPolling();
     }
 
+    @SuppressWarnings("unchecked")
     protected void doStartPolling() {
         if (scheduledTask == null || scheduledTask.isDone()) {
             ScheduledTask task = new ScheduledTask(MutableMap.of("period", getPollPeriod(), "displayName", getTaskName()), pollingTaskFactory);
-            scheduledTask = ((EntityInternal)entity).getExecutionContext().submit(task);;
+            scheduledTask = ((EntityInternal)entity).getExecutionContext().submit(task);
         }
     }
 
@@ -271,6 +272,7 @@ public abstract class AbstractFailureDetector extends AbstractPolicy {
         schedulePublish(0);
     }
 
+    @SuppressWarnings("unchecked")
     protected void schedulePublish(long delay) {
         if (isRunning() && executorQueued.compareAndSet(false, true)) {
             long now = System.currentTimeMillis();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java b/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
index b71d6d6..02ea8e4 100644
--- a/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
+++ b/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
@@ -26,7 +26,6 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.catalog.Catalog;
 import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
@@ -76,7 +75,7 @@ public class ServiceRestarter extends AbstractPolicy {
 
     /** monitors this sensor, by default ENTITY_FAILED */
     @SetFromFlag("failureSensorToMonitor")
-    @SuppressWarnings("rawtypes")
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     public static final ConfigKey<Sensor<?>> FAILURE_SENSOR_TO_MONITOR = (ConfigKey) ConfigKeys.newConfigKey(Sensor.class, "failureSensorToMonitor", "", HASensors.ENTITY_FAILED); 
     
     protected final AtomicReference<Long> lastFailureTime = new AtomicReference<Long>();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java b/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java
index ee1c6ee..edb71b9 100644
--- a/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java
+++ b/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java
@@ -29,7 +29,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.location.basic.Machines;
 import brooklyn.location.basic.SshMachineLocation;
-import brooklyn.policy.ha.AbstractFailureDetector.LastPublished;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
index 3ebad57..954b842 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
@@ -314,7 +314,7 @@ public abstract class AbstractSoftwareProcessSshDriver extends AbstractSoftwareP
      * @see SoftwareProcess#SHELL_ENVIRONMENT
      */
     public Map<String, String> getShellEnvironment() {
-        return Strings.toStringMap(entity.getConfig(SoftwareProcess.SHELL_ENVIRONMENT));
+        return Strings.toStringMap(entity.getConfig(SoftwareProcess.SHELL_ENVIRONMENT), "");
     }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
index 8c20253..8688ec8 100644
--- a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
@@ -18,15 +18,22 @@
  */
 package brooklyn.entity.software;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.effector.AddSensor;
 import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.TypeCoercions;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.task.Tasks;
+import brooklyn.util.time.Duration;
 
 public class StaticSensor<T> extends AddSensor<T> {
 
+    private static final Logger log = LoggerFactory.getLogger(StaticSensor.class);
+    
     public static final ConfigKey<Object> STATIC_VALUE = ConfigKeys.newConfigKey(Object.class, "static.value");
 
     private final Object value;
@@ -36,9 +43,17 @@ public class StaticSensor<T> extends AddSensor<T> {
         value = params.get(STATIC_VALUE);
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public void apply(EntityLocal entity) {
         super.apply(entity);
-        entity.setAttribute(sensor, (T) TypeCoercions.coerce(value, sensor.getType()));
+        
+        Maybe<T> v = Tasks.resolving(value).as((Class<T>)sensor.getType()).timeout(Duration.millis(200)).getMaybe();
+        if (v.isPresent()) {
+            log.debug(this+" setting sensor "+sensor+" to "+v.get());
+            entity.setAttribute(sensor, v.get());
+        } else {
+            log.debug(this+" not setting sensor "+sensor+"; cannot resolve "+value);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java
index 200d0ce..9a86dce 100644
--- a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java
+++ b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java
@@ -82,7 +82,7 @@ public final class SshCommandEffector extends AddEffector {
             }
             
             // then set things from the entities defined shell environment, if applicable
-            env.putAll(Strings.toStringMap(entity().getConfig(SoftwareProcess.SHELL_ENVIRONMENT)));
+            env.putAll(Strings.toStringMap(entity().getConfig(SoftwareProcess.SHELL_ENVIRONMENT), ""));
             
             // if we wanted to resolve the surrounding environment in real time -- see above
 //            Map<String,Object> paramsResolved = (Map<String, Object>) Tasks.resolveDeepValue(effectorShellEnv, Map.class, entity().getExecutionContext());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
index 2c918f9..2d9e88d 100644
--- a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
@@ -87,7 +87,7 @@ public final class SshCommandSensor<T> extends AddSensor<T> {
         Supplier<Map<String,String>> envSupplier = new Supplier<Map<String,String>>() {
             @Override
             public Map<String, String> get() {
-                return MutableMap.copyOf(Strings.toStringMap(entity.getConfig(SoftwareProcess.SHELL_ENVIRONMENT)));
+                return MutableMap.copyOf(Strings.toStringMap(entity.getConfig(SoftwareProcess.SHELL_ENVIRONMENT), ""));
             }
         };
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
index 4c3f40b..f488d61 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
@@ -46,6 +46,7 @@ import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.javalang.Reflections;
 import brooklyn.util.task.DeferredSupplier;
+import brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Function;
@@ -57,27 +58,27 @@ public class BrooklynDslCommon {
 
     // Access specific entities
 
-    public static DslComponent entity(String scopeOrId) {
-        return new DslComponent(Scope.GLOBAL, scopeOrId);
+    public static DslComponent entity(String id) {
+        return new DslComponent(Scope.GLOBAL, id);
     }
     public static DslComponent parent() {
         return new DslComponent(Scope.PARENT, null);
     }
-    public static DslComponent child(String scopeOrId) {
-        return new DslComponent(Scope.CHILD, scopeOrId);
+    public static DslComponent child(String id) {
+        return new DslComponent(Scope.CHILD, id);
     }
-    public static DslComponent sibling(String scopeOrId) {
-        return new DslComponent(Scope.SIBLING, scopeOrId);
+    public static DslComponent sibling(String id) {
+        return new DslComponent(Scope.SIBLING, id);
     }
-    public static DslComponent descendant(String scopeOrId) {
-        return new DslComponent(Scope.DESCENDANT, scopeOrId);
+    public static DslComponent descendant(String id) {
+        return new DslComponent(Scope.DESCENDANT, id);
     }
-    public static DslComponent ancestor(String scopeOrId) {
-        return new DslComponent(Scope.ANCESTOR, scopeOrId);
+    public static DslComponent ancestor(String id) {
+        return new DslComponent(Scope.ANCESTOR, id);
     }
     // prefer the syntax above to the below now, but not deprecating the below
-    public static DslComponent component(String scopeOrId) {
-        return component("global", scopeOrId);
+    public static DslComponent component(String id) {
+        return component("global", id);
     }
     public static DslComponent component(String scope, String id) {
         if (!DslComponent.Scope.isValid(scope)) {
@@ -205,7 +206,9 @@ public class BrooklynDslCommon {
 
         @Override
         public String toString() {
-            return "$brooklyn:formatString("+pattern+(args==null || args.length==0 ? "" : ","+Strings.join(args, ","))+")";
+            return "$brooklyn:formatString("+
+                JavaStringEscapes.wrapJavaString(pattern)+
+                (args==null || args.length==0 ? "" : ","+Strings.join(args, ","))+")";
         }
     }
 
@@ -291,7 +294,7 @@ public class BrooklynDslCommon {
 
         @Override
         public String toString() {
-            return "$brooklyn:object("+type+")";
+            return "$brooklyn:object(\""+type.getName()+"\")";
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
index 7b1ab4b..1cb52b3 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
@@ -26,6 +26,7 @@ import java.util.Set;
 import java.util.concurrent.Callable;
 
 import brooklyn.entity.Entity;
+import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
@@ -39,6 +40,7 @@ import brooklyn.management.internal.EntityManagerInternal;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.TaskBuilder;
 import brooklyn.util.task.Tasks;
+import brooklyn.util.text.StringEscapes.JavaStringEscapes;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
@@ -72,8 +74,8 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
     
     @Override
     public Task<Entity> newTask() {
-        return TaskBuilder.<Entity>builder().name("component("+componentId+")").body(
-            new EntityInScopeFinder(scopeComponent, scope, componentId)).build();
+        return TaskBuilder.<Entity>builder().name(toString()).tag(BrooklynTaskTags.TRANSIENT_TASK_TAG)
+            .body(new EntityInScopeFinder(scopeComponent, scope, componentId)).build();
     }
     
     protected static class EntityInScopeFinder implements Callable<Entity> {
@@ -197,7 +199,8 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
         }
         @Override
         public String toString() {
-            return component.toString()+"."+"attributeWhenReady("+sensorName+")";
+            return (component.scope==Scope.THIS ? "" : component.toString()+".") +
+                "attributeWhenReady("+JavaStringEscapes.wrapJavaString(sensorName)+")";
         }
     }
 
@@ -216,7 +219,7 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
 
         @Override
         public Task<Object> newTask() {
-            return Tasks.builder().name("retrieving config for "+keyName).dynamic(false).body(new Callable<Object>() {
+            return Tasks.builder().name("retrieving config for "+keyName).tag(BrooklynTaskTags.TRANSIENT_TASK_TAG).dynamic(false).body(new Callable<Object>() {
                 @Override
                 public Object call() throws Exception {
                     Entity targetEntity = component.get();
@@ -227,7 +230,8 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
 
         @Override
         public String toString() {
-            return component.toString()+"."+"config("+keyName+")";
+            return (component.scope==Scope.THIS ? "" : component.toString()+".") + 
+                "config("+JavaStringEscapes.wrapJavaString(keyName)+")";
         }
     }
     
@@ -262,7 +266,8 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
 
         @Override
         public String toString() {
-            return component.toString()+"."+"sensor("+sensorName+")";
+            return (component.scope==Scope.THIS ? "" : component.toString()+".") + 
+                "sensor("+JavaStringEscapes.wrapJavaString(sensorName)+")";
         }
     }
 
@@ -305,10 +310,10 @@ public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
 
     @Override
     public String toString() {
-        return "$brooklyn:component("+
-            (scopeComponent==null ? "" : scopeComponent+", ")+
-            (scope==Scope.GLOBAL ? "" : scope+", ")+
-            componentId+
+        return "$brooklyn:entity("+
+            (scopeComponent==null ? "" : JavaStringEscapes.wrapJavaString(scopeComponent.toString())+", ")+
+            (scope==Scope.GLOBAL ? "" : JavaStringEscapes.wrapJavaString(scope.toString())+", ")+
+            JavaStringEscapes.wrapJavaString(componentId)+
             ")";
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/utils/common/src/main/java/brooklyn/util/text/StringEscapes.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/text/StringEscapes.java b/utils/common/src/main/java/brooklyn/util/text/StringEscapes.java
index 6d35361..b5b4976 100644
--- a/utils/common/src/main/java/brooklyn/util/text/StringEscapes.java
+++ b/utils/common/src/main/java/brooklyn/util/text/StringEscapes.java
@@ -24,6 +24,8 @@ import java.net.URLEncoder;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.annotation.Nonnull;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -205,6 +207,12 @@ public class StringEscapes {
             }
             return out.toString();
         }
+        public static List<String> wrapJavaStrings(Iterable<String> values) {
+            if (values==null) return null;
+            List<String> result = MutableList.of();
+            for (String v: values) result.add(wrapJavaString(v));
+            return result;
+        }
 
         /** as {@link #unwrapJavaString(String)} if the given string is wrapped in double quotes;
          * otherwise just returns the given string */
@@ -215,13 +223,17 @@ public class StringEscapes {
 
         /** converts normal string to java escaped for double-quotes and wrapped in those double quotes */
         public static void wrapJavaString(String value, Appendable out) throws IOException {
-            out.append('"');
-            escapeJavaString(value, out);
-            out.append('"');
+            if (value==null) {
+                out.append("null");
+            } else {
+                out.append('"');
+                escapeJavaString(value, out);
+                out.append('"');
+            }
         }
 
         /** converts normal string to java escaped for double-quotes (but not wrapped in double quotes) */
-        public static void escapeJavaString(String value, Appendable out) throws IOException {
+        public static void escapeJavaString(@Nonnull String value, Appendable out) throws IOException {
             for (int i=0; i<value.length(); i++) {
                 char c = value.charAt(i);
                 if (c=='\\' || c=='"') {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/utils/common/src/main/java/brooklyn/util/text/Strings.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/text/Strings.java b/utils/common/src/main/java/brooklyn/util/text/Strings.java
index cf61fad..5aa2089 100644
--- a/utils/common/src/main/java/brooklyn/util/text/Strings.java
+++ b/utils/common/src/main/java/brooklyn/util/text/Strings.java
@@ -687,7 +687,12 @@ public class Strings {
 
     /** returns toString of the object if it is not null, otherwise null */
     public static String toString(Object o) {
-        if (o==null) return null;
+        return toStringWithValueForNull(o, null);
+    }
+
+    /** returns toString of the object if it is not null, otherwise the given value */
+    public static String toStringWithValueForNull(Object o, String valueIfNull) {
+        if (o==null) return valueIfNull;
         return o.toString();
     }
 
@@ -807,15 +812,32 @@ public class Strings {
         return ies(count);
     }
 
-    /** converts a map of any objects to a map of strings, preserving nulls and invoking toString where needed */
+    /** converts a map of any objects to a map of strings, using the tostring, and returning "null" for nulls 
+     * @deprecated since 0.7.0 use {@link #toStringMap(Map, String)} to remove ambiguity about how to handle null */
+    // NB previously the javadoc here was wrong, said it returned null not "null"
+    @Deprecated
     public static Map<String, String> toStringMap(Map<?,?> map) {
+        return toStringMap(map, "null");
+    }
+    /** converts a map of any objects to a map of strings, using {@link Object#toString()},
+     * with the second argument used where a value (or key) is null */
+    public static Map<String, String> toStringMap(Map<?,?> map, String valueIfNull) {
         if (map==null) return null;
         Map<String,String> result = MutableMap.<String, String>of();
         for (Map.Entry<?,?> e: map.entrySet()) {
-            result.put(String.valueOf(e.getKey()), String.valueOf(e.getValue()));
+            result.put(toStringWithValueForNull(e.getKey(), valueIfNull), toStringWithValueForNull(e.getValue(), valueIfNull));
         }
         return result;
     }
+    
+    /** converts a list of any objects to a list of strings, using {@link Object#toString()},
+     * with the second argument used where an entry is null */
+    public static List<String> toStringList(List<?> list, String valueIfNull) {
+        if (list==null) return null;
+        List<String> result = MutableList.of();
+        for (Object v: list) result.add(toStringWithValueForNull(v, valueIfNull));
+        return result;
+    }
 
     /** returns base repeated count times */
     public static String repeat(String base, int count) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/78cbc22f/utils/common/src/main/java/brooklyn/util/time/Durations.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/time/Durations.java b/utils/common/src/main/java/brooklyn/util/time/Durations.java
index 3553ff4..21450a6 100644
--- a/utils/common/src/main/java/brooklyn/util/time/Durations.java
+++ b/utils/common/src/main/java/brooklyn/util/time/Durations.java
@@ -18,6 +18,7 @@
  */
 package brooklyn.util.time;
 
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -52,6 +53,8 @@ public class Durations {
             return Maybe.of(t.get(timeout.toMilliseconds(), TimeUnit.MILLISECONDS));
         } catch (TimeoutException e) {
             return Maybe.absent("Task "+t+" did not complete within "+timeout);
+        } catch (CancellationException e) {
+            return Maybe.absent("Task "+t+" was cancelled");
         } catch (Exception e) {
             throw Exceptions.propagate(e);
         }


[17/22] incubator-brooklyn git commit: comments on copying BOM from cli project to dist

Posted by he...@apache.org.
comments on copying BOM from cli project to dist


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

Branch: refs/heads/master
Commit: 622e03fb53f9dd747110ef023fe36d684fe85e98
Parents: b77ef94
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jun 23 23:11:44 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:34 2015 -0700

----------------------------------------------------------------------
 usage/cli/pom.xml  | 3 +++
 usage/dist/pom.xml | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/622e03fb/usage/cli/pom.xml
----------------------------------------------------------------------
diff --git a/usage/cli/pom.xml b/usage/cli/pom.xml
index 91894f1..07d65ab 100644
--- a/usage/cli/pom.xml
+++ b/usage/cli/pom.xml
@@ -135,6 +135,9 @@
             </plugin>
             
             <plugin>
+                <!-- we publish the BOM in case anyone wants to access it directly.
+                     the primary consumer to begin with is the dist,
+                     though it could use use unpack goal with an includes filter. -->
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>build-helper-maven-plugin</artifactId>
                 <executions>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/622e03fb/usage/dist/pom.xml
----------------------------------------------------------------------
diff --git a/usage/dist/pom.xml b/usage/dist/pom.xml
index f884372..f4c863c 100644
--- a/usage/dist/pom.xml
+++ b/usage/dist/pom.xml
@@ -64,7 +64,7 @@
         <plugins>
             <plugin>
                 <artifactId>maven-dependency-plugin</artifactId>
-                <!-- copy the config file from the CLI project -->
+                <!-- copy the config file from the CLI project (could instead use unpack goal with an includes filter) -->
                 <executions>
                     <execution>
                         <id>copy</id>


[10/22] incubator-brooklyn git commit: more enrichers ease-of-use

Posted by he...@apache.org.
more enrichers ease-of-use

aggregator doesn't require "fromMembers", instead it defaults sensibly,
plus better errors and messages around enrichers and policies


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

Branch: refs/heads/master
Commit: e5f93cc8d47ee8ab5755068f65e761c83aa974cc
Parents: 089fe86
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sun Jun 21 10:47:12 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:33 2015 -0700

----------------------------------------------------------------------
 .../enricher/basic/AbstractAggregator.java      | 32 +++++++++++++++-----
 .../enricher/basic/AbstractTransformer.java     |  5 ---
 .../brooklyn/enricher/basic/Aggregator.java     | 18 ++++++++---
 .../java/brooklyn/enricher/basic/Combiner.java  |  1 -
 .../brooklyn/enricher/basic/Transformer.java    |  1 +
 .../entity/basic/ServiceStateLogic.java         |  2 +-
 .../policy/autoscaling/AutoScalerPolicy.java    |  2 +-
 7 files changed, 41 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e5f93cc8/core/src/main/java/brooklyn/enricher/basic/AbstractAggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractAggregator.java b/core/src/main/java/brooklyn/enricher/basic/AbstractAggregator.java
index a76a602..951a75c 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractAggregator.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractAggregator.java
@@ -58,9 +58,11 @@ public abstract class AbstractAggregator<T,U> extends AbstractEnricher implement
 
     public static final ConfigKey<Set<? extends Entity>> FROM_HARDCODED_PRODUCERS = ConfigKeys.newConfigKey(new TypeToken<Set<? extends Entity>>() {}, "enricher.aggregating.fromHardcodedProducers");
 
-    public static final ConfigKey<Boolean> FROM_MEMBERS = ConfigKeys.newBooleanConfigKey("enricher.aggregating.fromMembers");
+    public static final ConfigKey<Boolean> FROM_MEMBERS = ConfigKeys.newBooleanConfigKey("enricher.aggregating.fromMembers",
+        "Whether this enricher looks at members; only supported if a Group producer is supplier; defaults to true for Group entities");
 
-    public static final ConfigKey<Boolean> FROM_CHILDREN = ConfigKeys.newBooleanConfigKey("enricher.aggregating.fromChildren");
+    public static final ConfigKey<Boolean> FROM_CHILDREN = ConfigKeys.newBooleanConfigKey("enricher.aggregating.fromChildren",
+        "Whether this enricher looks at children; this is the default for non-Group producers");
 
     public static final ConfigKey<Predicate<? super Entity>> ENTITY_FILTER = ConfigKeys.newConfigKey(new TypeToken<Predicate<? super Entity>>() {}, "enricher.aggregating.entityFilter");
 
@@ -85,8 +87,6 @@ public abstract class AbstractAggregator<T,U> extends AbstractEnricher implement
         if (fromHardcodedProducers == null && producer == null) producer = entity;
         checkState(fromHardcodedProducers != null ^ producer != null, "must specify one of %s (%s) or %s (%s)", 
                 PRODUCER.getName(), producer, FROM_HARDCODED_PRODUCERS.getName(), fromHardcodedProducers);
-        checkState(producer == null || Boolean.TRUE.equals(fromMembers) || Boolean.TRUE.equals(fromChildren), 
-                "when specifying producer, must specify at least one of fromMembers (%s) or fromChildren (%s)", fromMembers, fromChildren);
 
         if (fromHardcodedProducers != null) {
             for (Entity producer : Iterables.filter(fromHardcodedProducers, entityFilter)) {
@@ -94,13 +94,13 @@ public abstract class AbstractAggregator<T,U> extends AbstractEnricher implement
             }
         }
         
-        if (Boolean.TRUE.equals(fromMembers)) {
+        if (isAggregatingMembers()) {
             setEntityBeforeSubscribingProducerMemberEvents(entity);
             setEntitySubscribeProducerMemberEvents();
             setEntityAfterSubscribingProducerMemberEvents();
         }
         
-        if (Boolean.TRUE.equals(fromChildren)) {
+        if (isAggregatingChildren()) {
             setEntityBeforeSubscribingProducerChildrenEvents();
             setEntitySubscribingProducerChildrenEvents();
             setEntityAfterSubscribingProducerChildrenEvents();
@@ -132,7 +132,7 @@ public abstract class AbstractAggregator<T,U> extends AbstractEnricher implement
     }
 
     protected void setEntityBeforeSubscribingProducerMemberEvents(EntityLocal entity) {
-        checkState(producer instanceof Group, "must be a group when fromMembers true: producer=%s; entity=%s; "
+        checkState(producer instanceof Group, "Producer must be a group when fromMembers true: producer=%s; entity=%s; "
                 + "hardcodedProducers=%s", getConfig(PRODUCER), entity, fromHardcodedProducers);
     }
 
@@ -187,6 +187,24 @@ public abstract class AbstractAggregator<T,U> extends AbstractEnricher implement
         }
     }
 
+    /** true if this should aggregate members */
+    protected boolean isAggregatingMembers() {
+        if (Boolean.TRUE.equals(fromMembers)) return true;
+        if (Boolean.TRUE.equals(fromChildren)) return false;
+        if (fromHardcodedProducers!=null) return false;
+        if (producer instanceof Group) return true;
+        return false;
+    }
+    
+    /** true if this should aggregate members */
+    protected boolean isAggregatingChildren() {
+        if (Boolean.TRUE.equals(fromChildren)) return true;
+        if (Boolean.TRUE.equals(fromMembers)) return false;
+        if (fromHardcodedProducers!=null) return false;
+        if (producer instanceof Group) return false;
+        return true;
+    }
+    
     protected abstract void addProducerHardcoded(Entity producer);
     protected abstract void addProducerMember(Entity producer);
     protected abstract void addProducerChild(Entity producer);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e5f93cc8/core/src/main/java/brooklyn/enricher/basic/AbstractTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractTransformer.java b/core/src/main/java/brooklyn/enricher/basic/AbstractTransformer.java
index 28a6de1..47e3642 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractTransformer.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractTransformer.java
@@ -18,8 +18,6 @@
  */
 package brooklyn.enricher.basic;
 
-import static com.google.common.base.Preconditions.checkArgument;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,9 +30,6 @@ import brooklyn.event.Sensor;
 import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
 import brooklyn.event.basic.BasicSensorEvent;
-import brooklyn.util.collections.MutableSet;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e5f93cc8/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Aggregator.java b/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
index d7f4fca..a58d4a3 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
@@ -23,6 +23,7 @@ import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -60,7 +61,7 @@ public class Aggregator<T,U> extends AbstractAggregator<T,U> implements SensorEv
     @SetFromFlag("transformation")
     public static final ConfigKey<Object> TRANSFORMATION_UNTYPED = ConfigKeys.newConfigKey(Object.class, "enricher.transformation.untyped",
         "Specifies a transformation, as a function from a collection to the value, or as a string matching a pre-defined named transformation, "
-        + "such as 'average' (for numbers), 'add' (for numbers), or 'list' (the default, putting any collection of items into a list)");
+        + "such as 'average' (for numbers), 'sum' (for numbers), or 'list' (the default, putting any collection of items into a list)");
     public static final ConfigKey<Function<? super Collection<?>, ?>> TRANSFORMATION = ConfigKeys.newConfigKey(new TypeToken<Function<? super Collection<?>, ?>>() {}, "enricher.transformation");
     
     public static final ConfigKey<Boolean> EXCLUDE_BLANK = ConfigKeys.newBooleanConfigKey("enricher.aggregator.excludeBlank", "Whether explicit nulls or blank strings should be excluded (default false); this only applies if no value filter set", false);
@@ -82,13 +83,20 @@ public class Aggregator<T,U> extends AbstractAggregator<T,U> implements SensorEv
         super.setEntityLoadingConfig();
         this.sourceSensor = (Sensor<T>) getRequiredConfig(SOURCE_SENSOR);
         
+        this.transformation = (Function<? super Collection<T>, ? extends U>) config().get(TRANSFORMATION);
+        
         Object t1 = config().get(TRANSFORMATION_UNTYPED);
-        if (t1 instanceof String) t1 = lookupTransformation((String)t1);
+        Function<? super Collection<?>, ?> t2 = null;
+        if (t1 instanceof String) {
+            t2 = lookupTransformation((String)t1);
+            if (t2==null) {
+                LOG.warn("Unknown transformation '"+t1+"' for "+this+"; will use default transformation");
+            }
+        }
         
-        this.transformation = (Function<? super Collection<T>, ? extends U>) config().get(TRANSFORMATION);
         if (this.transformation==null) {
-            this.transformation = (Function<? super Collection<T>, ? extends U>) t1;
-        } else if (t1!=null && !t1.equals(this.transformation)) {
+            this.transformation = (Function<? super Collection<T>, ? extends U>) t2;
+        } else if (t1!=null && !Objects.equals(t2, this.transformation)) {
             throw new IllegalStateException("Cannot supply both "+TRANSFORMATION_UNTYPED+" and "+TRANSFORMATION+" unless they are equal.");
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e5f93cc8/core/src/main/java/brooklyn/enricher/basic/Combiner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Combiner.java b/core/src/main/java/brooklyn/enricher/basic/Combiner.java
index cc37d8c..74a400c 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Combiner.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Combiner.java
@@ -30,7 +30,6 @@ import java.util.Set;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.catalog.Catalog;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ConfigKeys;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e5f93cc8/core/src/main/java/brooklyn/enricher/basic/Transformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Transformer.java b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
index 2fa85fe..0f6c409 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Transformer.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
@@ -37,6 +37,7 @@ import com.google.common.reflect.TypeToken;
 @SuppressWarnings("serial")
 public class Transformer<T,U> extends AbstractTransformer<T,U> {
 
+    @SuppressWarnings("unused")
     private static final Logger LOG = LoggerFactory.getLogger(Transformer.class);
 
     // exactly one of these should be supplied to set a value

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e5f93cc8/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java b/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
index cfabf1b..75bf9a6 100644
--- a/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
+++ b/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
@@ -402,7 +402,7 @@ public class ServiceStateLogic {
             fromMembers = true;
             // above sets default
             super.setEntityLoadingConfig();
-            if (fromMembers && (!(entity instanceof Group))) {
+            if (isAggregatingMembers() && (!(entity instanceof Group))) {
                 if (fromChildren) fromMembers=false;
                 else throw new IllegalStateException("Cannot monitor only members for non-group entity "+entity+": "+this);
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e5f93cc8/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
index 52bb943..b693955 100644
--- a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
@@ -684,7 +684,7 @@ public class AutoScalerPolicy extends AbstractPolicy {
     @Override
     public void setEntity(EntityLocal entity) {
         if (!config().getRaw(RESIZE_OPERATOR).isPresentAndNonNull()) {
-            Preconditions.checkArgument(entity instanceof Resizable, "Provided entity must be an instance of Resizable, because no custom-resizer operator supplied");
+            Preconditions.checkArgument(entity instanceof Resizable, "Provided entity "+entity+" must be an instance of Resizable, because no custom-resizer operator supplied");
         }
         super.setEntity(entity);
         this.poolEntity = entity;


[05/22] incubator-brooklyn git commit: merge the two assembly xml files in the dist (DRY)

Posted by he...@apache.org.
merge the two assembly xml files in the dist (DRY)


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

Branch: refs/heads/master
Commit: b12ebb40fa0d3c580489c4e0fd93d1537b3c401f
Parents: 1744fbf
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jun 15 11:48:59 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:32 2015 -0700

----------------------------------------------------------------------
 usage/dist/pom.xml                              | 12 ++-
 .../main/config/build-distribution-archive.xml  | 90 --------------------
 .../src/main/config/build-distribution-dir.xml  | 90 --------------------
 .../dist/src/main/config/build-distribution.xml | 87 +++++++++++++++++++
 4 files changed, 97 insertions(+), 182 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b12ebb40/usage/dist/pom.xml
----------------------------------------------------------------------
diff --git a/usage/dist/pom.xml b/usage/dist/pom.xml
index 2fc5268..173dda4 100644
--- a/usage/dist/pom.xml
+++ b/usage/dist/pom.xml
@@ -84,9 +84,13 @@
                         <configuration>
                             <appendAssemblyId>true</appendAssemblyId>
                             <descriptors>
-                                <descriptor>src/main/config/build-distribution-dir.xml</descriptor>
+                                <descriptor>src/main/config/build-distribution.xml</descriptor>
                             </descriptors>
                             <finalName>brooklyn</finalName>
+                            <includeBaseDirectory>false</includeBaseDirectory>
+                            <formats>
+                                <format>dir</format>
+                            </formats>
                         </configuration>
                     </execution>
                     <execution>
@@ -98,9 +102,13 @@
                         <configuration>
                             <appendAssemblyId>true</appendAssemblyId>
                             <descriptors>
-                                <descriptor>src/main/config/build-distribution-archive.xml</descriptor>
+                                <descriptor>src/main/config/build-distribution.xml</descriptor>
                             </descriptors>
                             <finalName>brooklyn-${project.version}</finalName>
+                            <formats>
+                                <format>tar.gz</format>
+                                <format>zip</format>
+                            </formats>
                         </configuration>
                     </execution>
                 </executions>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b12ebb40/usage/dist/src/main/config/build-distribution-archive.xml
----------------------------------------------------------------------
diff --git a/usage/dist/src/main/config/build-distribution-archive.xml b/usage/dist/src/main/config/build-distribution-archive.xml
deleted file mode 100644
index e02cc44..0000000
--- a/usage/dist/src/main/config/build-distribution-archive.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-    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.
--->
-<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
-    <id>dist</id>
-    <formats>
-        <format>tar.gz</format>
-        <format>zip</format>
-    </formats>
-    <fileSets>
-        <fileSet>
-            <directory>${project.basedir}/../..</directory>
-            <outputDirectory>/</outputDirectory>
-            <fileMode>0644</fileMode>
-            <directoryMode>0755</directoryMode>
-            <includes>
-                <include>README*</include>
-                <include>DISCLAIMER*</include>
-            </includes>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/src/main/license</directory>
-            <outputDirectory>/</outputDirectory>
-            <fileMode>0644</fileMode>
-            <directoryMode>0755</directoryMode>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/src/main/dist/bin</directory>
-            <outputDirectory>/bin</outputDirectory>
-            <fileMode>0755</fileMode>
-            <directoryMode>0755</directoryMode>
-        </fileSet>
-        <fileSet>
-            <!-- Add an empty dropins folder (so need to reference an existing dir, and exclude everything) -->
-            <directory>${project.basedir}/src/main/dist</directory>
-            <outputDirectory>/lib/dropins</outputDirectory>
-            <directoryMode>0755</directoryMode>
-            <excludes>
-                <exclude>**/*</exclude>
-            </excludes>
-        </fileSet>
-        <fileSet>
-            <!-- Add an empty patch folder (so need to reference an existing dir, and exclude everything) -->
-            <directory>${project.basedir}/src/main/dist</directory>
-            <outputDirectory>/lib/patch</outputDirectory>
-            <directoryMode>0755</directoryMode>
-            <excludes>
-                <exclude>**/*</exclude>
-            </excludes>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/src/main/dist</directory>
-            <outputDirectory>/</outputDirectory>
-            <fileMode>0644</fileMode>
-            <directoryMode>0755</directoryMode>
-            <excludes>
-                <exclude>bin/*</exclude>
-            </excludes>
-        </fileSet>
-    </fileSets>
-    <!-- TODO include documentation -->
-    <!-- TODO include examples -->
-    <dependencySets>
-        <dependencySet>
-            <useProjectArtifact>false</useProjectArtifact>
-            <outputDirectory>/lib/brooklyn</outputDirectory>
-            <fileMode>0644</fileMode>
-            <directoryMode>0755</directoryMode>
-            <outputFileNameMapping>${artifact.groupId}-${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
-        </dependencySet>
-    </dependencySets>
-</assembly>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b12ebb40/usage/dist/src/main/config/build-distribution-dir.xml
----------------------------------------------------------------------
diff --git a/usage/dist/src/main/config/build-distribution-dir.xml b/usage/dist/src/main/config/build-distribution-dir.xml
deleted file mode 100644
index c8c238f..0000000
--- a/usage/dist/src/main/config/build-distribution-dir.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-    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.
--->
-<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
-        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
-    <id>dist</id>
-    <includeBaseDirectory>false</includeBaseDirectory>
-    <formats>
-        <format>dir</format>
-    </formats>
-    <fileSets>
-        <fileSet>
-            <directory>${project.basedir}/../..</directory>
-            <outputDirectory>/</outputDirectory>
-            <fileMode>0644</fileMode>
-            <directoryMode>0755</directoryMode>
-            <includes>
-                <include>README*</include>
-                <include>DISCLAIMER*</include>
-            </includes>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/src/main/license</directory>
-            <outputDirectory>/</outputDirectory>
-            <fileMode>0644</fileMode>
-            <directoryMode>0755</directoryMode>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/src/main/dist/bin</directory>
-            <outputDirectory>/bin</outputDirectory>
-            <fileMode>0755</fileMode>
-            <directoryMode>0755</directoryMode>
-        </fileSet>
-        <fileSet>
-            <!-- Add an empty dropins folder (so need to reference an existing dir, and exclude everything) -->
-            <directory>${project.basedir}/src/main/dist</directory>
-            <outputDirectory>/lib/dropins</outputDirectory>
-            <directoryMode>0755</directoryMode>
-            <excludes>
-                <exclude>**/*</exclude>
-            </excludes>
-        </fileSet>
-        <fileSet>
-            <!-- Add an empty patch folder (so need to reference an existing dir, and exclude everything) -->
-            <directory>${project.basedir}/src/main/dist</directory>
-            <outputDirectory>/lib/patch</outputDirectory>
-            <directoryMode>0755</directoryMode>
-            <excludes>
-                <exclude>**/*</exclude>
-            </excludes>
-        </fileSet>
-        <fileSet>
-            <directory>${project.basedir}/src/main/dist</directory>
-            <outputDirectory>/</outputDirectory>
-            <fileMode>0644</fileMode>
-            <directoryMode>0755</directoryMode>
-            <excludes>
-                <exclude>bin/*</exclude>
-            </excludes>
-        </fileSet>
-    </fileSets>
-    <!-- TODO include documentation -->
-    <!-- TODO include examples -->
-    <dependencySets>
-        <dependencySet>
-            <useProjectArtifact>false</useProjectArtifact>
-            <outputDirectory>/lib/brooklyn</outputDirectory>
-            <fileMode>0644</fileMode>
-            <directoryMode>0755</directoryMode>
-            <outputFileNameMapping>${artifact.groupId}-${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
-        </dependencySet>
-    </dependencySets>
-</assembly>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b12ebb40/usage/dist/src/main/config/build-distribution.xml
----------------------------------------------------------------------
diff --git a/usage/dist/src/main/config/build-distribution.xml b/usage/dist/src/main/config/build-distribution.xml
new file mode 100644
index 0000000..9398150
--- /dev/null
+++ b/usage/dist/src/main/config/build-distribution.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+    <id>dist</id>
+    <formats><!-- empty, intended for caller to specify --></formats>
+    <fileSets>
+        <fileSet>
+            <directory>${project.basedir}/../..</directory>
+            <outputDirectory>/</outputDirectory>
+            <fileMode>0644</fileMode>
+            <directoryMode>0755</directoryMode>
+            <includes>
+                <include>README*</include>
+                <include>DISCLAIMER*</include>
+            </includes>
+        </fileSet>
+        <fileSet>
+            <directory>${project.basedir}/src/main/license</directory>
+            <outputDirectory>/</outputDirectory>
+            <fileMode>0644</fileMode>
+            <directoryMode>0755</directoryMode>
+        </fileSet>
+        <fileSet>
+            <directory>${project.basedir}/src/main/dist/bin</directory>
+            <outputDirectory>/bin</outputDirectory>
+            <fileMode>0755</fileMode>
+            <directoryMode>0755</directoryMode>
+        </fileSet>
+        <fileSet>
+            <!-- Add an empty dropins folder (so need to reference an existing dir, and exclude everything) -->
+            <directory>${project.basedir}/src/main/dist</directory>
+            <outputDirectory>/lib/dropins</outputDirectory>
+            <directoryMode>0755</directoryMode>
+            <excludes>
+                <exclude>**/*</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <!-- Add an empty patch folder (so need to reference an existing dir, and exclude everything) -->
+            <directory>${project.basedir}/src/main/dist</directory>
+            <outputDirectory>/lib/patch</outputDirectory>
+            <directoryMode>0755</directoryMode>
+            <excludes>
+                <exclude>**/*</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>${project.basedir}/src/main/dist</directory>
+            <outputDirectory>/</outputDirectory>
+            <fileMode>0644</fileMode>
+            <directoryMode>0755</directoryMode>
+            <excludes>
+                <exclude>bin/*</exclude>
+            </excludes>
+        </fileSet>
+    </fileSets>
+    <!-- TODO include documentation -->
+    <!-- TODO include examples -->
+    <dependencySets>
+        <dependencySet>
+            <useProjectArtifact>false</useProjectArtifact>
+            <outputDirectory>/lib/brooklyn</outputDirectory>
+            <fileMode>0644</fileMode>
+            <directoryMode>0755</directoryMode>
+            <outputFileNameMapping>${artifact.groupId}-${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
+        </dependencySet>
+    </dependencySets>
+</assembly>


[11/22] incubator-brooklyn git commit: treat tasks submitted by transient tasks as transient by default

Posted by he...@apache.org.
treat tasks submitted by transient tasks as transient by default


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

Branch: refs/heads/master
Commit: 63e8c061634bb19f0cfe3f253b436aaa7cb0668e
Parents: 61d4821
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Jun 20 16:33:41 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:33 2015 -0700

----------------------------------------------------------------------
 .../src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java | 7 ++++++-
 .../main/java/brooklyn/util/task/BasicExecutionContext.java   | 5 +++++
 2 files changed, 11 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63e8c061/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java b/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java
index 41b2371..e90a014 100644
--- a/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java
+++ b/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java
@@ -267,7 +267,12 @@ public class BrooklynTaskTags extends TaskTags {
     
     public static void setInessential(Task<?> task) { addTagDynamically(task, INESSENTIAL_TASK); }
     public static void setTransient(Task<?> task) { addTagDynamically(task, TRANSIENT_TASK_TAG); }
-    public static boolean isTransient(Task<?> task) { return hasTag(task, TRANSIENT_TASK_TAG); }
+    public static boolean isTransient(Task<?> task) { 
+        if (hasTag(task, TRANSIENT_TASK_TAG)) return true;
+        if (hasTag(task, NON_TRANSIENT_TASK_TAG)) return true;
+        if (task.getSubmittedByTask()!=null) return isTransient(task.getSubmittedByTask());
+        return false;
+    }
     public static boolean isSubTask(Task<?> task) { return hasTag(task, SUB_TASK_TAG); }
     public static boolean isEffectorTask(Task<?> task) { return hasTag(task, EFFECTOR_TAG); }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/63e8c061/core/src/main/java/brooklyn/util/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicExecutionContext.java b/core/src/main/java/brooklyn/util/task/BasicExecutionContext.java
index bff6e2d..6346ecd 100644
--- a/core/src/main/java/brooklyn/util/task/BasicExecutionContext.java
+++ b/core/src/main/java/brooklyn/util/task/BasicExecutionContext.java
@@ -169,6 +169,11 @@ public class BasicExecutionContext extends AbstractExecutionContext {
 
         taskTags.addAll(tags);
         
+        if (Tasks.current()!=null && BrooklynTaskTags.isTransient(Tasks.current()) && !taskTags.contains(BrooklynTaskTags.NON_TRANSIENT_TASK_TAG)) {
+            // tag as transient if submitter is transient, unless explicitly tagged as non-transient
+            taskTags.add(BrooklynTaskTags.TRANSIENT_TASK_TAG);
+        }
+        
         final Object startCallback = properties.get("newTaskStartCallback");
         properties.put("newTaskStartCallback", new Function<Object,Void>() {
             public Void apply(Object it) {


[07/22] incubator-brooklyn git commit: copy the brooklyn/default.catalog.bom from the usage/cli project into the dist

Posted by he...@apache.org.
copy the brooklyn/default.catalog.bom from the usage/cli project into the dist

this allows the same default bom to be used from the IDE as included in the dist,
and changes only need to be made in a single place (in the cli project)


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

Branch: refs/heads/master
Commit: e3db4f20455302f6e9cb316f876bd628119ad4cf
Parents: 7b9d0e0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jun 15 17:34:16 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:32 2015 -0700

----------------------------------------------------------------------
 usage/cli/pom.xml                               | 23 ++++++++
 .../main/resources/brooklyn/default.catalog.bom | 58 +++++++++++++-------
 usage/dist/pom.xml                              | 29 ++++++++++
 .../dist/src/main/config/build-distribution.xml |  9 +++
 .../main/dist/conf/brooklyn/default.catalog.bom | 41 --------------
 5 files changed, 99 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e3db4f20/usage/cli/pom.xml
----------------------------------------------------------------------
diff --git a/usage/cli/pom.xml b/usage/cli/pom.xml
index ac4f0fc..91894f1 100644
--- a/usage/cli/pom.xml
+++ b/usage/cli/pom.xml
@@ -133,6 +133,29 @@
                     </execution>
                 </executions>
             </plugin>
+            
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-catalog</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/classes/brooklyn/default.catalog.bom</file>
+                                    <type>bom</type>
+                                    <classifier>dist</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
 
             <!-- Disable the automatic LICENSE/NOTICE placement from the upstream pom, because we need to include
                  bloodhound.js. See "resources" section below for where we include the new LICENSE/NOTICE -->

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e3db4f20/usage/cli/src/main/resources/brooklyn/default.catalog.bom
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/resources/brooklyn/default.catalog.bom b/usage/cli/src/main/resources/brooklyn/default.catalog.bom
index 0db2f20..42672ae 100644
--- a/usage/cli/src/main/resources/brooklyn/default.catalog.bom
+++ b/usage/cli/src/main/resources/brooklyn/default.catalog.bom
@@ -1,23 +1,41 @@
-# 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.
-#
 
-# this catalog bom simply scans.
-# in a dist a default.catalog.bom from the conf/ dir takes precedence.
+# this catalog bom is an illustration supplying a few useful sample items
+# and templates to get started using Brooklyn
 
 brooklyn.catalog:
-  scanJavaAnnotations: true
+  version: 0.7.0-SNAPSHOT  # BROOKLYN_VERSION
+  items:
+
+  # load everything in the classpath with a @Catalog annotation
+  - scanJavaAnnotations: true
+
+  - id: server
+    description: |
+      Provision a server, with customizable provisioning.properties and credentials installed, 
+      but no other special software process or scripts executed.
+    item:
+      type: brooklyn.entity.basic.EmptySoftwareProcess
+      name: Server
+
+  - id: server-template
+    itemType: template
+    name: Server Template
+    description: |
+      Sample YAML to provision a server in a cloud with illustrative VM properties
+    item:
+      name: My App with a single VM
+      services:
+      - type: server
+        name: My VM
+      location:
+        jclouds:aws-ec2:
+          identity: <REPLACE>
+          credential: <REPLACE>
+          region: eu-west-1
+          # we want Ubuntu, with a lot of RAM
+          osFamily: ubuntu
+          minRam: 8gb
+          # set up this user and password (default is to authorize a public key)
+          user: sample
+          password: s4mpl3
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e3db4f20/usage/dist/pom.xml
----------------------------------------------------------------------
diff --git a/usage/dist/pom.xml b/usage/dist/pom.xml
index 401433d..f884372 100644
--- a/usage/dist/pom.xml
+++ b/usage/dist/pom.xml
@@ -63,6 +63,35 @@
     <build>
         <plugins>
             <plugin>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <!-- copy the config file from the CLI project -->
+                <executions>
+                    <execution>
+                        <id>copy</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>copy</goal>
+                        </goals>
+                        <configuration>
+                            <artifactItems>
+                                <artifactItem>
+                                    <!-- this can fail in eclipse trying to copy _from_ target/classes.
+                                         see http://jira.codehaus.org/browse/MDEP-259 -->
+                                    <groupId>${project.groupId}</groupId>
+                                    <artifactId>brooklyn-cli</artifactId>
+                                    <version>${project.version}</version>
+                                    <type>bom</type>
+                                    <classifier>dist</classifier>
+                                    <overWrite>true</overWrite>
+                                    <outputDirectory>target</outputDirectory>
+                                    <destFileName>default.catalog.bom</destFileName>
+                                </artifactItem>
+                            </artifactItems>
+                        </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/e3db4f20/usage/dist/src/main/config/build-distribution.xml
----------------------------------------------------------------------
diff --git a/usage/dist/src/main/config/build-distribution.xml b/usage/dist/src/main/config/build-distribution.xml
index d3792bc..78569e8 100644
--- a/usage/dist/src/main/config/build-distribution.xml
+++ b/usage/dist/src/main/config/build-distribution.xml
@@ -55,6 +55,15 @@
             </excludes>
         </fileSet>
         <fileSet>
+            <directory>${project.basedir}/target</directory>
+            <outputDirectory>conf/brooklyn</outputDirectory>
+            <fileMode>0644</fileMode>
+            <directoryMode>0755</directoryMode>
+            <includes>
+                <include>default.catalog.bom</include>
+            </includes>
+        </fileSet>
+        <fileSet>
             <!-- Add an empty patch folder (so need to reference an existing dir, and exclude everything) -->
             <directory>${project.basedir}/src/main/dist</directory>
             <outputDirectory>lib/patch</outputDirectory>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e3db4f20/usage/dist/src/main/dist/conf/brooklyn/default.catalog.bom
----------------------------------------------------------------------
diff --git a/usage/dist/src/main/dist/conf/brooklyn/default.catalog.bom b/usage/dist/src/main/dist/conf/brooklyn/default.catalog.bom
deleted file mode 100644
index 42672ae..0000000
--- a/usage/dist/src/main/dist/conf/brooklyn/default.catalog.bom
+++ /dev/null
@@ -1,41 +0,0 @@
-
-# this catalog bom is an illustration supplying a few useful sample items
-# and templates to get started using Brooklyn
-
-brooklyn.catalog:
-  version: 0.7.0-SNAPSHOT  # BROOKLYN_VERSION
-  items:
-
-  # load everything in the classpath with a @Catalog annotation
-  - scanJavaAnnotations: true
-
-  - id: server
-    description: |
-      Provision a server, with customizable provisioning.properties and credentials installed, 
-      but no other special software process or scripts executed.
-    item:
-      type: brooklyn.entity.basic.EmptySoftwareProcess
-      name: Server
-
-  - id: server-template
-    itemType: template
-    name: Server Template
-    description: |
-      Sample YAML to provision a server in a cloud with illustrative VM properties
-    item:
-      name: My App with a single VM
-      services:
-      - type: server
-        name: My VM
-      location:
-        jclouds:aws-ec2:
-          identity: <REPLACE>
-          credential: <REPLACE>
-          region: eu-west-1
-          # we want Ubuntu, with a lot of RAM
-          osFamily: ubuntu
-          minRam: 8gb
-          # set up this user and password (default is to authorize a public key)
-          user: sample
-          password: s4mpl3
-


[13/22] incubator-brooklyn git commit: expand string-to-sensor coercion to make sensors easier to write in yaml

Posted by he...@apache.org.
expand string-to-sensor coercion to make sensors easier to write in yaml


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

Branch: refs/heads/master
Commit: e9daca7d0c311732d4c83cf9c6e52e2e2f9c3bc3
Parents: 0818fd2
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sun Jun 21 11:58:50 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:33 2015 -0700

----------------------------------------------------------------------
 .../brooklyn/enricher/basic/Propagator.java     |  5 ++-
 .../java/brooklyn/util/flags/TypeCoercions.java | 32 ++++++++++++++++++--
 2 files changed, 34 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e9daca7d/core/src/main/java/brooklyn/enricher/basic/Propagator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Propagator.java b/core/src/main/java/brooklyn/enricher/basic/Propagator.java
index 7d6e383..86795c6 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Propagator.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Propagator.java
@@ -36,6 +36,8 @@ import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.flags.SetFromFlag;
+import brooklyn.util.task.Tasks;
+import brooklyn.util.time.Duration;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
@@ -93,7 +95,8 @@ public class Propagator extends AbstractEnricher implements SensorEventListener<
                 throw new IllegalStateException("Propagator enricher "+this+" must not have 'propagating' set at same time as either 'propagatingAll' or 'propagatingAllBut'");
             }
             
-            for (Sensor<?> sensor : getConfig(PROPAGATING)) {
+            for (Object sensorO : getConfig(PROPAGATING)) {
+                Sensor<?> sensor = Tasks.resolving(sensorO).as(Sensor.class).timeout(Duration.millis(50)).context(producer).get();
                 if (!sensorMappingTemp.containsKey(sensor)) {
                     sensorMappingTemp.put(sensor, sensor);
                 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e9daca7d/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
index 55649e8..c2876bd 100644
--- a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
+++ b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
@@ -45,11 +45,14 @@ import javax.annotation.concurrent.GuardedBy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.ClosureEntityFactory;
 import brooklyn.entity.basic.ConfigurableEntityFactory;
 import brooklyn.entity.basic.ConfigurableEntityFactoryFromEntityFactory;
 import brooklyn.event.AttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensor;
+import brooklyn.event.Sensor;
+import brooklyn.event.basic.Sensors;
 import brooklyn.internal.BrooklynInitialization;
 import brooklyn.util.JavaGroovyEquivalents;
 import brooklyn.util.collections.MutableSet;
@@ -61,6 +64,7 @@ import brooklyn.util.javalang.Enums;
 import brooklyn.util.net.Cidr;
 import brooklyn.util.net.Networking;
 import brooklyn.util.net.UserAndHostAndPort;
+import brooklyn.util.task.Tasks;
 import brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
@@ -723,7 +727,31 @@ public class TypeCoercions {
         registerAdapter(String.class, AttributeSensor.class, new Function<String,AttributeSensor>() {
             @Override
             public AttributeSensor apply(final String input) {
-                return new BasicAttributeSensor<Object>(Object.class, input);
+                Entity entity = BrooklynTaskTags.getContextEntity(Tasks.current());
+                if (entity!=null) {
+                    Sensor<?> result = null;
+                    if (entity!=null) {
+                        result = entity.getEntityType().getSensor(input);
+                        if (result instanceof AttributeSensor) 
+                            return (AttributeSensor) result;
+                    }
+                }
+                return Sensors.newSensor(Object.class, input);
+            }
+        });
+        registerAdapter(String.class, Sensor.class, new Function<String,Sensor>() {
+            @Override
+            public AttributeSensor apply(final String input) {
+                Entity entity = BrooklynTaskTags.getContextEntity(Tasks.current());
+                if (entity!=null) {
+                    Sensor<?> result = null;
+                    if (entity!=null) {
+                        result = entity.getEntityType().getSensor(input);
+                        if (result != null) 
+                            return (AttributeSensor) result;
+                    }
+                }
+                return Sensors.newSensor(Object.class, input);
             }
         });
         registerAdapter(String.class, List.class, new Function<String,List>() {


[21/22] incubator-brooklyn git commit: tidy dist pom how things are attached and the phase so it only runs once

Posted by he...@apache.org.
tidy dist pom how things are attached and the phase so it only runs once


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

Branch: refs/heads/master
Commit: 56285ad89cc2ba7b9ea540cfb0de25f411d14e29
Parents: 622e03f
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jun 24 00:13:59 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 01:04:24 2015 -0700

----------------------------------------------------------------------
 usage/dist/pom.xml | 38 +++++++-------------------------------
 1 file changed, 7 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/56285ad8/usage/dist/pom.xml
----------------------------------------------------------------------
diff --git a/usage/dist/pom.xml b/usage/dist/pom.xml
index f4c863c..e226237 100644
--- a/usage/dist/pom.xml
+++ b/usage/dist/pom.xml
@@ -106,7 +106,7 @@
                 <executions>
                     <execution>
                         <id>build-distribution-dir</id>
-                        <phase>process-resources</phase>
+                        <phase>package</phase>
                         <goals>
                             <goal>single</goal>
                         </goals>
@@ -125,7 +125,7 @@
                     </execution>
                     <execution>
                         <id>build-distribution-archive</id>
-                        <phase>process-resources</phase>
+                        <phase>package</phase>
                         <goals>
                             <goal>single</goal>
                         </goals>
@@ -134,39 +134,15 @@
                             <descriptors>
                                 <descriptor>src/main/config/build-distribution.xml</descriptor>
                             </descriptors>
-                            <finalName>brooklyn-${project.version}</finalName>
+                          <!-- finalName affects name in `target/` but we cannot influence name when it is attached/installed,
+                               so `apache-` prefix would be lost there. to keep it consistent this is commented out, 
+                               but would be nice to have if there is a way!
+                            <finalName>apache-brooklyn-${project.version}</finalName>
+                          -->
                             <formats>
                                 <format>tar.gz</format>
                                 <format>zip</format>
                             </formats>
-                            <attach>false</attach>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>attach-distribution</id>
-                        <phase>process-resources</phase>
-                        <goals>
-                            <goal>attach-artifact</goal>
-                        </goals>
-                        <configuration>
-                            <artifacts>
-                                <artifact>
-                                    <file>${project.build.directory}/apache-brooklyn-${project.version}-dist.tar.gz</file>
-                                    <type>tar.gz</type>
-                                    <classifier>dist</classifier>
-                                </artifact>
-                                <artifact>
-                                    <file>${project.build.directory}/apache-brooklyn-${project.version}-dist.zip</file>
-                                    <type>zip</type>
-                                    <classifier>dist</classifier>
-                                </artifact>
-                            </artifacts>
                         </configuration>
                     </execution>
                 </executions>


[20/22] incubator-brooklyn git commit: better warnings and comments on use of `networkName` in JcloudsLocation

Posted by he...@apache.org.
better warnings and comments on use of `networkName` in JcloudsLocation


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

Branch: refs/heads/master
Commit: 8e9967413913a3982a6e6d6e57735a13fdbc696d
Parents: 56285ad
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jun 23 23:12:07 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 01:04:24 2015 -0700

----------------------------------------------------------------------
 .../brooklyn/location/jclouds/JcloudsLocation.java  | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8e996741/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
index 969d41d..7797138 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
@@ -1257,14 +1257,20 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                             ((AWSEC2TemplateOptions)t).subnetId((String)v);
                             
                         } else {
-                            if (t instanceof SoftLayerTemplateOptions) {
-                                LOG.warn("networkName may not be supported in SoftLayer; use `templateOptions` with `primaryNetworkComponentNetworkVlanId` or `primaryNetworkBackendComponentNetworkVlanId`");
+                            if (t instanceof GoogleComputeEngineTemplateOptions) {
+                                // no warning needed
+                                // we think this is the only jclouds endpoint which supports this option
+                                
+                            } else if (t instanceof SoftLayerTemplateOptions) {
+                                LOG.warn("networkName is not be supported in SoftLayer; use `templateOptions` with `primaryNetworkComponentNetworkVlanId` or `primaryNetworkBackendComponentNetworkVlanId`");
                             } else if (!(t instanceof CloudStackTemplateOptions) && !(t instanceof NovaTemplateOptions)) {
-                                LOG.warn("networkName may not be supported in this cloud; only known to work in CloudStack and OpenStack");
+                                LOG.warn("networkName is experimental in many jclouds endpoints may not be supported in this cloud");
+                                // NB, from @andreaturli
+//                                Cloudstack uses custom securityGroupIds and networkIds not the generic networks
+//                                Openstack Nova uses securityGroupNames which is marked as @deprecated (suggests to use groups which is maybe even more confusing)
+//                                Azure supports the custom networkSecurityGroupName
                             }
                             
-                            // looks like this is only supported in Cloudstack and Openstack
-                            // should we log warning if using another cloud?
                             t.networks((String)v);
                         }
                     }})


[16/22] incubator-brooklyn git commit: fixes for AWS VPC issues

Posted by he...@apache.org.
fixes for AWS VPC issues

* give a detailed message if we hit the classic/vpc problem
* treat `networkName` as `subnetId` in AWS
* longer timeout for AWS security group creation
* use `eu-central-1` in the default catalog as it gives a default VPC which works best


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

Branch: refs/heads/master
Commit: b77ef941a9d6ef8b57cc18e47adb259dc4f97c18
Parents: 4897470
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jun 22 23:11:20 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:34 2015 -0700

----------------------------------------------------------------------
 .../jclouds/ComputeServiceRegistryImpl.java     |  7 +++++
 .../location/jclouds/JcloudsLocation.java       | 29 ++++++++++++++++++--
 .../location/jclouds/JcloudsLocationConfig.java |  2 +-
 .../main/resources/brooklyn/default.catalog.bom | 12 ++++----
 4 files changed, 41 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b77ef941/locations/jclouds/src/main/java/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
index b3da5a6..a1786ec 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
@@ -31,6 +31,7 @@ import org.jclouds.Constants;
 import org.jclouds.ContextBuilder;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.ComputeServiceContext;
+import org.jclouds.ec2.reference.EC2Constants;
 import org.jclouds.encryption.bouncycastle.config.BouncyCastleCryptoModule;
 import org.jclouds.logging.slf4j.config.SLF4JLoggingModule;
 import org.jclouds.sshj.config.SshjSshClientModule;
@@ -40,6 +41,7 @@ import org.slf4j.LoggerFactory;
 import brooklyn.entity.basic.Sanitizer;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;
+import brooklyn.util.time.Duration;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableSet;
@@ -96,6 +98,11 @@ public class ComputeServiceRegistryImpl implements ComputeServiceRegistry, Jclou
                  * Filter.3.Name=image-type&Filter.3.Value.1=machine&
                  */
             }
+            
+            // occasionally can get com.google.common.util.concurrent.UncheckedExecutionException: java.lang.RuntimeException: 
+            //     security group eu-central-1/jclouds#brooklyn-bxza-alex-eu-central-shoul-u2jy-nginx-ielm is not available after creating
+            // the default timeout was 500ms so let's raise it in case that helps
+            properties.setProperty(EC2Constants.PROPERTY_EC2_TIMEOUT_SECURITYGROUP_PRESENT, ""+Duration.seconds(30).toMilliseconds());
         }
 
         // FIXME Deprecated mechanism, should have a ConfigKey for overrides

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b77ef941/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
index a0d30d4..969d41d 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocation.java
@@ -53,6 +53,7 @@ import java.util.regex.Pattern;
 
 import javax.annotation.Nullable;
 
+import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
 import org.jclouds.cloudstack.compute.options.CloudStackTemplateOptions;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.RunNodesException;
@@ -979,10 +980,20 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
             // sometimes AWS nodes come up busted (eg ssh not allowed); just throw it back (and maybe try for another one)
             boolean destroyNode = (node != null) && Boolean.TRUE.equals(setup.get(DESTROY_ON_FAILURE));
 
+            if (e.toString().contains("VPCResourceNotSpecified")) {
+                LOG.error("Detected that your EC2 account is a legacy 'classic' account, but the recommended instance type requires VPC. "
+                    + "You can specify the 'eu-central-1' region to avoid this problem, or you can specify a classic-compatible instance type, "
+                    + "or you can specify a subnet to use with 'networkName' "
+                    + "(taking care that the subnet auto-assigns public IP's and allows ingress on all ports, "
+                    + "as Brooklyn does not currently configure security groups for non-default VPC's; "
+                    + "or setting up Brooklyn to be in the subnet or have a jump host or other subnet access configuration). "
+                    + "For more information on VPC vs classic see http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-vpc.html.");
+            }
+            
             LOG.error("Failed to start VM for {}{}: {}",
                     new Object[] {setup.getDescription(), (destroyNode ? " (destroying "+node+")" : ""), e.getMessage()});
             LOG.debug(Throwables.getStackTraceAsString(e));
-
+            
             if (destroyNode) {
                 if (machineLocation != null) {
                     releaseSafely(machineLocation);
@@ -1241,7 +1252,21 @@ public class JcloudsLocation extends AbstractCloudMachineProvisioningLocation im
                     }})
             .put(NETWORK_NAME, new CustomizeTemplateOptions() {
                     public void apply(TemplateOptions t, ConfigBag props, Object v) {
-                        t.networks((String)v);
+                        if (t instanceof AWSEC2TemplateOptions) {
+                            // subnet ID is the sensible interpretation of network name in EC2
+                            ((AWSEC2TemplateOptions)t).subnetId((String)v);
+                            
+                        } else {
+                            if (t instanceof SoftLayerTemplateOptions) {
+                                LOG.warn("networkName may not be supported in SoftLayer; use `templateOptions` with `primaryNetworkComponentNetworkVlanId` or `primaryNetworkBackendComponentNetworkVlanId`");
+                            } else if (!(t instanceof CloudStackTemplateOptions) && !(t instanceof NovaTemplateOptions)) {
+                                LOG.warn("networkName may not be supported in this cloud; only known to work in CloudStack and OpenStack");
+                            }
+                            
+                            // looks like this is only supported in Cloudstack and Openstack
+                            // should we log warning if using another cloud?
+                            t.networks((String)v);
+                        }
                     }})
             .put(DOMAIN_NAME, new CustomizeTemplateOptions() {
                     public void apply(TemplateOptions t, ConfigBag props, Object v) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b77ef941/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
index ab0007a..c37d915 100644
--- a/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
+++ b/locations/jclouds/src/main/java/brooklyn/location/jclouds/JcloudsLocationConfig.java
@@ -193,7 +193,7 @@ public interface JcloudsLocationConfig extends CloudLocationConfig {
     public static final ConfigKey<Integer> OVERRIDE_RAM = ConfigKeys.newIntegerConfigKey("overrideRam", "Custom ram value");    
     
     public static final ConfigKey<String> NETWORK_NAME = ConfigKeys.newStringConfigKey(
-        "networkName", "Network name to specify as template option (e.g. GCE)");
+        "networkName", "Network name or ID where the instance should be created (e.g. the subnet ID in AWS");
 
     /**
      * CUSTOM_MACHINE_SETUP_SCRIPT_URL accepts a URL location that points to a shell script. 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b77ef941/usage/cli/src/main/resources/brooklyn/default.catalog.bom
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/resources/brooklyn/default.catalog.bom b/usage/cli/src/main/resources/brooklyn/default.catalog.bom
index 4da8319..70c7d57 100644
--- a/usage/cli/src/main/resources/brooklyn/default.catalog.bom
+++ b/usage/cli/src/main/resources/brooklyn/default.catalog.bom
@@ -59,15 +59,15 @@ brooklyn.catalog:
       - type:           server
         name:           My VM
       
-      # location can be `softlayer` or `jclouds:openstack-nova:https://9.9.9.9:9999/v2.0/`,
+      # location can be e.g. `softlayer` or `jclouds:openstack-nova:https://9.9.9.9:9999/v2.0/`,
       # or `localhost` or `byon: { nodes: [ 10.0.0.1, 10.0.0.2, 10.0.1.{1,2} ] }` 
       location:
         jclouds:aws-ec2:
-          # edit these to use your credential(or delete if credentials specified in brooklyn.properties)      
+          # edit these to use your credential (or delete if credentials specified in brooklyn.properties)      
           identity:     <REPLACE>
           credential:   <REPLACE>
           
-          region:       eu-west-1
+          region:       eu-central-1
           
           # we want Ubuntu, with a lot of RAM
           osFamily:     ubuntu
@@ -156,7 +156,7 @@ brooklyn.catalog:
       
       location:
         jclouds:aws-ec2:
-          region:       eu-west-1
+          region:       eu-central-1
           # edit these (or delete if credentials specified in brooklyn.properties)      
           identity:     <REPLACE>
           credential:   <REPLACE>
@@ -202,7 +202,7 @@ brooklyn.catalog:
           
       location:
         jclouds:aws-ec2:
-          region:       eu-west-1
+          region:       eu-central-1
           # edit these (or delete if credentials specified in brooklyn.properties)      
           identity:     <REPLACE>
           credential:   <REPLACE>
@@ -355,5 +355,5 @@ brooklyn.catalog:
           identity:     <REPLACE>
           credential:   <REPLACE>
           
-          region:       eu-west-1
+          region:       eu-central-1
           minRam:       2gb


[22/22] incubator-brooklyn git commit: This closes #705

Posted by he...@apache.org.
This closes #705


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

Branch: refs/heads/master
Commit: 45dd54940eda03abbfae1a356345fd4b52cca213
Parents: b08fe4e 8df4cdf
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jun 24 01:04:52 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 01:04:52 2015 -0700

----------------------------------------------------------------------
 api/src/main/java/brooklyn/event/Sensor.java    |   4 +-
 .../catalog/internal/BasicBrooklynCatalog.java  |   3 +-
 .../main/java/brooklyn/enricher/Enrichers.java  |   5 +-
 .../enricher/basic/AbstractAggregator.java      |  32 +-
 .../enricher/basic/AbstractTransformer.java     | 101 +++++
 .../brooklyn/enricher/basic/Aggregator.java     |  18 +-
 .../java/brooklyn/enricher/basic/Combiner.java  |   1 -
 .../brooklyn/enricher/basic/Propagator.java     |   5 +-
 .../brooklyn/enricher/basic/Transformer.java    |  71 +---
 .../YamlRollingTimeWindowMeanEnricher.java      | 178 +++++++++
 .../basic/YamlTimeWeightedDeltaEnricher.java    |  81 ++++
 .../brooklyn/entity/basic/BrooklynTaskTags.java |   7 +-
 .../entity/basic/ServiceStateLogic.java         |   5 +-
 .../drivers/downloads/DownloadSubstituters.java |   4 +-
 .../rebind/PeriodicDeltaChangeListener.java     |   3 +-
 .../event/basic/DependentConfiguration.java     |  10 +-
 .../internal/LocalSubscriptionManager.java      |   4 +-
 .../java/brooklyn/util/flags/TypeCoercions.java |  34 +-
 .../util/task/BasicExecutionContext.java        |   5 +
 .../src/main/java/brooklyn/util/task/Tasks.java |   2 +-
 .../java/brooklyn/util/task/ValueResolver.java  |  85 ++++-
 .../YamlRollingTimeWindowMeanEnricherTest.java  | 178 +++++++++
 .../YamlTimeWeightedDeltaEnricherTest.java      | 107 ++++++
 .../util/internal/TypeCoercionsTest.java        |   2 +-
 .../jclouds/ComputeServiceRegistryImpl.java     |   7 +
 .../location/jclouds/JcloudsLocation.java       |  35 +-
 .../location/jclouds/JcloudsLocationConfig.java |   2 +-
 .../enricher/RollingTimeWindowMeanEnricher.java |   4 +-
 .../enricher/TimeWeightedDeltaEnricher.java     |   3 +
 .../policy/autoscaling/AutoScalerPolicy.java    |  26 +-
 .../policy/ha/AbstractFailureDetector.java      |   4 +-
 .../brooklyn/policy/ha/ServiceRestarter.java    |   3 +-
 .../policy/ha/SshMachineFailureDetector.java    |   1 -
 .../basic/AbstractSoftwareProcessSshDriver.java |   2 +-
 .../basic/VanillaSoftwareProcessSshDriver.java  |   3 +-
 .../effector/SelectMasterEffectorBody.java      |   2 +-
 .../brooklyn/entity/software/StaticSensor.java  |  33 +-
 .../entity/software/ssh/SshCommandEffector.java |   2 +-
 .../entity/software/ssh/SshCommandSensor.java   |   2 +-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |   2 +-
 .../entity/proxy/AbstractControllerImpl.java    | 141 +++----
 .../entity/proxy/nginx/NginxControllerImpl.java |   2 +-
 .../BrooklynAssemblyTemplateInstantiator.java   |   2 +-
 .../spi/creation/BrooklynEntityMatcher.java     |   6 +-
 .../spi/dsl/methods/BrooklynDslCommon.java      |  31 +-
 .../brooklyn/spi/dsl/methods/DslComponent.java  |  25 +-
 usage/cli/pom.xml                               |  27 ++
 usage/cli/src/main/java/brooklyn/cli/Main.java  |  15 +-
 .../main/resources/brooklyn/default.catalog.bom | 378 +++++++++++++++++--
 usage/dist/pom.xml                              |  79 ++--
 .../main/config/build-distribution-archive.xml  |  90 -----
 .../src/main/config/build-distribution-dir.xml  |  90 -----
 .../dist/src/main/config/build-distribution.xml |  96 +++++
 .../main/dist/conf/brooklyn/default.catalog.bom |  41 --
 .../rest/resources/EntityConfigResource.java    |   3 +-
 .../brooklyn/rest/resources/SensorResource.java |   3 +-
 .../rest/transform/CatalogTransformer.java      |  27 +-
 .../rest/transform/EffectorTransformer.java     |   5 +-
 .../java/brooklyn/util/repeat/Repeater.java     |   7 +
 .../java/brooklyn/util/text/StringEscapes.java  |  20 +-
 .../main/java/brooklyn/util/text/Strings.java   |  28 +-
 .../main/java/brooklyn/util/time/Durations.java |   3 +
 .../src/main/java/brooklyn/util/yaml/Yamls.java |  10 +-
 .../test/java/brooklyn/util/yaml/YamlsTest.java |  20 +
 64 files changed, 1690 insertions(+), 535 deletions(-)
----------------------------------------------------------------------



[12/22] incubator-brooklyn git commit: change how freemarker logging is set to remove warning about "logging libraray"

Posted by he...@apache.org.
change how freemarker logging is set to remove warning about "logging libraray"


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

Branch: refs/heads/master
Commit: 1e29ad982453f6a7fe4e5a4d8b5abc14dd17838a
Parents: d2ac273
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Jun 20 14:30:55 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:33 2015 -0700

----------------------------------------------------------------------
 .../brooklyn/entity/drivers/downloads/DownloadSubstituters.java  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1e29ad98/core/src/main/java/brooklyn/entity/drivers/downloads/DownloadSubstituters.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/drivers/downloads/DownloadSubstituters.java b/core/src/main/java/brooklyn/entity/drivers/downloads/DownloadSubstituters.java
index 4e44bc7..7ff520a 100644
--- a/core/src/main/java/brooklyn/entity/drivers/downloads/DownloadSubstituters.java
+++ b/core/src/main/java/brooklyn/entity/drivers/downloads/DownloadSubstituters.java
@@ -55,7 +55,7 @@ public class DownloadSubstituters {
         // since this is the main place it is used, let's do it here
         try {
             LOG.debug("Configuring Freemarker logging for Brooklyn to use SLF4J");
-            freemarker.log.Logger.selectLoggerLibrary(freemarker.log.Logger.LIBRARY_SLF4J);
+            System.setProperty(freemarker.log.Logger.SYSTEM_PROPERTY_NAME_LOGGER_LIBRARY, freemarker.log.Logger.LIBRARY_NAME_SLF4J);
         } catch (Exception e) {
             LOG.warn("Error setting Freemarker logging: "+e, e);
         }
@@ -124,7 +124,7 @@ public class DownloadSubstituters {
 
     public static String substitute(String basevalue, Map<String,?> substitutions) {
         try {
-            Configuration cfg = new Configuration();
+            Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
             StringTemplateLoader templateLoader = new StringTemplateLoader();
             templateLoader.putTemplate("config", basevalue);
             cfg.setTemplateLoader(templateLoader);


[08/22] incubator-brooklyn git commit: in VanillaSoftware, look at shell.env for custom install and customize scripts

Posted by he...@apache.org.
in VanillaSoftware, look at shell.env for custom install and customize scripts


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

Branch: refs/heads/master
Commit: d2ac2738bfd732c61c2220c37c4f297f87342ef0
Parents: 63e8c06
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Jun 20 14:30:33 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:33 2015 -0700

----------------------------------------------------------------------
 .../brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java    | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d2ac2738/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java b/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java
index 004daa1..ac29a87 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java
@@ -85,6 +85,7 @@ public class VanillaSoftwareProcessSshDriver extends AbstractSoftwareProcessSshD
         if (Strings.isNonBlank(installCommand)) {
             newScript(INSTALLING)
                 .failOnNonZeroResultCode()
+                .environmentVariablesReset(getShellEnvironment())
                 .body.append(installCommand)
                 .execute();
         }
@@ -106,8 +107,6 @@ public class VanillaSoftwareProcessSshDriver extends AbstractSoftwareProcessSshD
         if (Strings.isNonBlank(customizeCommand)) {
             newScript(CUSTOMIZING)
                 .failOnNonZeroResultCode()
-                // don't set vars yet -- it resolves dependencies (e.g. DB) which we don't want until we start
-                .environmentVariablesReset()
                 .body.append(customizeCommand)
                 .execute();
         }


[09/22] incubator-brooklyn git commit: skip validation for "template" catalog items as that isn't always supported

Posted by he...@apache.org.
skip validation for "template" catalog items as that isn't always supported

prevents errors on startup and in log for catalog rest api calls


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

Branch: refs/heads/master
Commit: 61d4821cdcf157076e485c62ed72aab2f2a1fa8a
Parents: e5f93cc
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Jun 20 11:13:49 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:33 2015 -0700

----------------------------------------------------------------------
 .../catalog/internal/BasicBrooklynCatalog.java  |  3 ++-
 .../BrooklynAssemblyTemplateInstantiator.java   |  2 +-
 .../spi/creation/BrooklynEntityMatcher.java     |  6 ++---
 usage/cli/src/main/java/brooklyn/cli/Main.java  | 15 ++++++++---
 .../rest/transform/CatalogTransformer.java      | 27 ++++++++++++--------
 .../src/main/java/brooklyn/util/yaml/Yamls.java | 10 +++++++-
 .../test/java/brooklyn/util/yaml/YamlsTest.java | 20 +++++++++++++++
 7 files changed, 62 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/61d4821c/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
index 31458f5..37af858 100644
--- a/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/brooklyn/catalog/internal/BasicBrooklynCatalog.java
@@ -325,8 +325,9 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
     @SuppressWarnings("unchecked")
     @Override
     public <T, SpecT> SpecT createSpec(CatalogItem<T, SpecT> item) {
+        if (item == null) return null;
         CatalogItemDo<T,SpecT> loadedItem = (CatalogItemDo<T, SpecT>) getCatalogItemDo(item.getSymbolicName(), item.getVersion());
-        if (loadedItem == null) return null;
+        if (loadedItem == null) throw new RuntimeException(item+" not in catalog; cannot create spec");
         Class<SpecT> specType = loadedItem.getSpecType();
         if (specType==null) return null;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/61d4821c/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
index 1519326..68136f2 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
@@ -183,7 +183,7 @@ public class BrooklynAssemblyTemplateInstantiator implements AssemblyTemplateSpe
                 // TODO support https above
                 // TODO this will probably be logged if we refer to  chef:cookbook  or other service types which BCTR accepts;
                 // better would be to have BCTR supporting the calls above
-                log.warn("The reference " + brooklynType + " looks like an URL but the protocol " +
+                log.debug("The reference " + brooklynType + " looks like a URL (running the CAMP Brooklyn assembly-template instantiator) but the protocol " +
                         protocol + " isn't white listed (" + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + "). " +
                         "Will try to load it as catalog item or java type.");
             }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/61d4821c/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
index aae2b19..50b57e9 100644
--- a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
+++ b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityMatcher.java
@@ -80,7 +80,7 @@ public class BrooklynEntityMatcher implements PdpMatcher {
                 if (BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST.contains(protocol)) {
                     return serviceType;
                 } else {
-                    log.warn("The reference '" + serviceType + "' looks like an URL but the protocol '" + 
+                    log.debug("The reference '" + serviceType + "' looks like a URL (running the CAMP Brooklyn entity-matcher) but the protocol '" + 
                             protocol + "' isn't white listed " + BrooklynCampConstants.YAML_URL_PROTOCOL_WHITELIST + ". " +
                             "Not recognized as catalog item or java item as well!");
                 }
@@ -229,9 +229,7 @@ public class BrooklynEntityMatcher implements PdpMatcher {
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
             if (e.toString().contains("Could not find")) {
-                // TODO currently we get this error if a catalog item is passed, giving stack trace is too scary;
-                // when we are doing catalog.createSpec let's remove this block
-                log.warn("Ignoring configuration attributes on "+typeName+", item probably loaded from catalog and flags are not yet supported here");
+                // normal for catalog items, there will be no java type
                 log.debug("Ignoring configuration attributes on "+typeName+", details: "+e);
             } else {
                 log.warn("Ignoring configuration attributes on "+typeName+" due to "+e, e);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/61d4821c/usage/cli/src/main/java/brooklyn/cli/Main.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/java/brooklyn/cli/Main.java b/usage/cli/src/main/java/brooklyn/cli/Main.java
index 0f93057..80d2b05 100644
--- a/usage/cli/src/main/java/brooklyn/cli/Main.java
+++ b/usage/cli/src/main/java/brooklyn/cli/Main.java
@@ -41,6 +41,7 @@ import brooklyn.BrooklynVersion;
 import brooklyn.basic.BrooklynTypes;
 import brooklyn.catalog.BrooklynCatalog;
 import brooklyn.catalog.CatalogItem;
+import brooklyn.catalog.CatalogItem.CatalogItemType;
 import brooklyn.catalog.internal.CatalogInitialization;
 import brooklyn.cli.CloudExplorer.BlobstoreGetBlobCommand;
 import brooklyn.cli.CloudExplorer.BlobstoreListContainerCommand;
@@ -633,11 +634,17 @@ public class Main extends AbstractMain {
             Iterable<CatalogItem<Object, Object>> items = catalog.getCatalogItems();
             for (CatalogItem<Object, Object> item: items) {
                 try {
-                    Object spec = catalog.createSpec(item);
-                    if (spec instanceof EntitySpec) {
-                        BrooklynTypes.getDefinedEntityType(((EntitySpec<?>)spec).getType());
+                    if (item.getCatalogItemType()==CatalogItemType.TEMPLATE) {
+                        // skip validation of templates, they might contain instructions,
+                        // and additionally they might contain multiple items in which case
+                        // the validation below won't work anyway (you need to go via a deployment plan)
+                    } else {
+                        Object spec = catalog.createSpec(item);
+                        if (spec instanceof EntitySpec) {
+                            BrooklynTypes.getDefinedEntityType(((EntitySpec<?>)spec).getType());
+                        }
+                        log.debug("Catalog loaded spec "+spec+" for item "+item);
                     }
-                    log.debug("Catalog loaded spec "+spec+" for item "+item);                      
                 } catch (Throwable throwable) {
                     catInit.handleException(throwable, item);
                 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/61d4821c/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java b/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
index 053a9c3..a9f9baf 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/transform/CatalogTransformer.java
@@ -59,21 +59,28 @@ public class CatalogTransformer {
     private static final org.slf4j.Logger log = LoggerFactory.getLogger(CatalogTransformer.class);
     
     public static CatalogEntitySummary catalogEntitySummary(BrooklynRestResourceUtils b, CatalogItem<? extends Entity,EntitySpec<?>> item) {
-        EntitySpec<?> spec = b.getCatalog().createSpec(item);
-        EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType());
-        EntityType type = typeMap.getSnapshot();
-
         Set<EntityConfigSummary> config = Sets.newTreeSet(SummaryComparators.nameComparator());
         Set<SensorSummary> sensors = Sets.newTreeSet(SummaryComparators.nameComparator());
         Set<EffectorSummary> effectors = Sets.newTreeSet(SummaryComparators.nameComparator());
 
-        for (ConfigKey<?> x: type.getConfigKeys())
-            config.add(EntityTransformer.entityConfigSummary(x, typeMap.getConfigKeyField(x.getName())));
-        for (Sensor<?> x: type.getSensors())
-            sensors.add(SensorTransformer.sensorSummaryForCatalog(x));
-        for (Effector<?> x: type.getEffectors())
-            effectors.add(EffectorTransformer.effectorSummaryForCatalog(x));
+        try {
+            EntitySpec<?> spec = b.getCatalog().createSpec(item);
+            EntityDynamicType typeMap = BrooklynTypes.getDefinedEntityType(spec.getType());
+            EntityType type = typeMap.getSnapshot();
 
+            for (ConfigKey<?> x: type.getConfigKeys())
+                config.add(EntityTransformer.entityConfigSummary(x, typeMap.getConfigKeyField(x.getName())));
+            for (Sensor<?> x: type.getSensors())
+                sensors.add(SensorTransformer.sensorSummaryForCatalog(x));
+            for (Effector<?> x: type.getEffectors())
+                effectors.add(EffectorTransformer.effectorSummaryForCatalog(x));
+            
+        } catch (Exception e) {
+            // templates with multiple entities can't have spec created in the manner above; just ignore
+            if (log.isTraceEnabled())
+                log.trace("Unable to create spec for "+item+": "+e, e);
+        }
+        
         return new CatalogEntitySummary(item.getSymbolicName(), item.getVersion(), item.getDisplayName(),
             item.getJavaType(), item.getPlanYaml(),
             item.getDescription(), tidyIconLink(b, item, item.getIconUrl()),

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/61d4821c/utils/common/src/main/java/brooklyn/util/yaml/Yamls.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/yaml/Yamls.java b/utils/common/src/main/java/brooklyn/util/yaml/Yamls.java
index 2ad9eee..b46e9d1 100644
--- a/utils/common/src/main/java/brooklyn/util/yaml/Yamls.java
+++ b/utils/common/src/main/java/brooklyn/util/yaml/Yamls.java
@@ -44,6 +44,7 @@ import org.yaml.snakeyaml.nodes.SequenceNode;
 import brooklyn.util.collections.Jsonya;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.UserFacingException;
 import brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;
@@ -350,7 +351,11 @@ public class Yamls {
                 if (e instanceof KnownClassVersionException) {
                     log.debug("Known class version exception; no yaml text being matched for "+this+": "+e);
                 } else {
-                    log.warn("Unable to match yaml text in "+this+": "+e, e);
+                    if (e instanceof UserFacingException) {
+                        log.warn("Unable to match yaml text in "+this+": "+e.getMessage());
+                    } else {
+                        log.warn("Unable to match yaml text in "+this+": "+e, e);
+                    }
                 }
                 return null;
             }
@@ -402,6 +407,9 @@ b: 1
  */
             List<String> result = MutableList.of();
             if (includePrecedingComments) {
+                if (getEndOfPrevious() > getStartOfThis()) {
+                    throw new UserFacingException("YAML not in expected format; when scanning, previous end "+getEndOfPrevious()+" exceeds this start "+getStartOfThis());
+                }
                 String[] preceding = yaml.substring(getEndOfPrevious(), getStartOfThis()).split("\n");
                 // suppress comments which are on the same line as the previous item or indented more than firstLineIndentation,
                 // ensuring appropriate whitespace is added to preceding[0] if it starts mid-line

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/61d4821c/utils/common/src/test/java/brooklyn/util/yaml/YamlsTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/brooklyn/util/yaml/YamlsTest.java b/utils/common/src/test/java/brooklyn/util/yaml/YamlsTest.java
index 36c146b..6cd90f8 100644
--- a/utils/common/src/test/java/brooklyn/util/yaml/YamlsTest.java
+++ b/utils/common/src/test/java/brooklyn/util/yaml/YamlsTest.java
@@ -28,6 +28,8 @@ import org.testng.TestNG;
 import org.testng.annotations.Test;
 
 import brooklyn.util.collections.MutableList;
+import brooklyn.util.exceptions.UserFacingException;
+import brooklyn.util.yaml.Yamls.YamlExtract;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -162,6 +164,24 @@ public class YamlsTest {
             "x: \n   c: 1\n   d: 2");
     }
 
+    @Test
+    public void testExtractNoOOBE() {
+        // this might log a warning, as item not found, but won't throw
+        YamlExtract r1 = Yamls.getTextOfYamlAtPath(
+            "items:\n- id: sample2\n  itemType: location\n  item:\n    type: jclouds:aws-ec2\n    brooklyn.config:\n      key2: value2\n\n",
+            "item");
+        
+        // won't throw
+        r1.getMatchedYamlTextOrWarn();
+        // will throw
+        try {
+            r1.getMatchedYamlText();
+            Assert.fail();
+        } catch (UserFacingException e) {
+            // expected, it should give a vaguely explanatory exception and no trace
+        }
+    }
+    
     // convenience, since running with older TestNG IDE plugin will fail (older snakeyaml dependency);
     // if you run as a java app it doesn't bring in the IDE TestNG jar version, and it works
     public static void main(String[] args) {


[15/22] incubator-brooklyn git commit: set AutoScalerPolicy to have min size default of 1 not 0

Posted by he...@apache.org.
set AutoScalerPolicy to have min size default of 1 not 0

else it might scale to 0 if the metric hits 0, and then it won't usually scale back out as nothing is generating load!


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

Branch: refs/heads/master
Commit: 48974708b40d73fc4b901268974eaf8c5bf2a4f0
Parents: 7ba5833
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jun 22 23:11:09 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:34 2015 -0700

----------------------------------------------------------------------
 .../policy/autoscaling/AutoScalerPolicy.java    | 24 ++++++++++++++++----
 1 file changed, 19 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/48974708/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
index b693955..f453aa5 100644
--- a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
@@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 import groovy.lang.Closure;
 
 import java.util.Map;
+import java.util.concurrent.Callable;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ThreadFactory;
@@ -35,6 +36,8 @@ import org.slf4j.LoggerFactory;
 import brooklyn.catalog.Catalog;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.Entity;
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.trait.Resizable;
 import brooklyn.entity.trait.Startable;
@@ -51,6 +54,7 @@ import brooklyn.policy.loadbalancing.LoadBalancingPolicy;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.flags.TypeCoercions;
+import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;
@@ -88,7 +92,7 @@ public class AutoScalerPolicy extends AbstractPolicy {
         private Entity entityWithMetric;
         private Number metricUpperBound;
         private Number metricLowerBound;
-        private int minPoolSize = 0;
+        private int minPoolSize = 1;
         private int maxPoolSize = Integer.MAX_VALUE;
         private Integer resizeDownIterationIncrement;
         private Integer resizeDownIterationMax;
@@ -357,7 +361,7 @@ public class AutoScalerPolicy extends AbstractPolicy {
     @SetFromFlag("minPoolSize")
     public static final ConfigKey<Integer> MIN_POOL_SIZE = BasicConfigKey.builder(Integer.class)
             .name("autoscaler.minPoolSize")
-            .defaultValue(0)
+            .defaultValue(1)
             .reconfigurable(true)
             .build();
     
@@ -1034,7 +1038,7 @@ public class AutoScalerPolicy extends AbstractPolicy {
     private void resizeNow() {
         long currentPoolSize = getCurrentSizeOperator().apply(poolEntity);
         CalculatedDesiredPoolSize calculatedDesiredPoolSize = calculateDesiredPoolSize(currentPoolSize);
-        long desiredPoolSize = calculatedDesiredPoolSize.size;
+        final long desiredPoolSize = calculatedDesiredPoolSize.size;
         boolean stable = calculatedDesiredPoolSize.stable;
         
         if (!stable) {
@@ -1054,8 +1058,18 @@ public class AutoScalerPolicy extends AbstractPolicy {
         if (LOG.isDebugEnabled()) LOG.debug("{} requesting resize to {}; current {}, min {}, max {}", 
                 new Object[] {this, desiredPoolSize, currentPoolSize, getMinPoolSize(), getMaxPoolSize()});
         
-        // TODO Should we use int throughout, rather than casting here?
-        getResizeOperator().resize(poolEntity, (int) desiredPoolSize);
+        Entities.submit(entity, Tasks.<Void>builder().name("Auto-scaler")
+            .description("Auto-scaler recommending resize from "+currentPoolSize+" to "+desiredPoolSize)
+            .tag(BrooklynTaskTags.NON_TRANSIENT_TASK_TAG)
+            .body(new Callable<Void>() {
+                @Override
+                public Void call() throws Exception {
+                    // TODO Should we use int throughout, rather than casting here?
+                    getResizeOperator().resize(poolEntity, (int) desiredPoolSize);
+                    return null;
+                }
+            }).build())
+            .blockUntilEnded();
     }
     
     /**


[14/22] incubator-brooklyn git commit: remove unnecessary (jboss) parameters in nginx health-check

Posted by he...@apache.org.
remove unnecessary (jboss) parameters in nginx health-check


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

Branch: refs/heads/master
Commit: 0818fd2df1536a0525a55090c26f502f778df835
Parents: 1e29ad9
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sun Jun 21 10:49:30 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:33 2015 -0700

----------------------------------------------------------------------
 .../main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/0818fd2d/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
index 811d091..dd34e69 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/nginx/NginxControllerImpl.java
@@ -113,7 +113,7 @@ public class NginxControllerImpl extends AbstractControllerImpl implements Nginx
                 .uniqueTag("nginx-poll")
                 .entity(this)
                 .period(getConfig(HTTP_POLL_PERIOD))
-                .baseUri(new UrlInferencer(ImmutableMap.of("include-runtime", "true")))
+                .baseUri(new UrlInferencer(null))
                 .poll(new HttpPollConfig<Boolean>(NGINX_URL_ANSWERS_NICELY)
                         // Any response from Nginx is good.
                         .checkSuccess(Predicates.alwaysTrue())


[19/22] incubator-brooklyn git commit: use constants for wait periods/limits in code

Posted by he...@apache.org.
use constants for wait periods/limits in 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/8df4cdfd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/8df4cdfd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/8df4cdfd

Branch: refs/heads/master
Commit: 8df4cdfd130103776a0abfbb77ddc10177fd004c
Parents: 8e99674
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Jun 23 23:36:06 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 01:04:24 2015 -0700

----------------------------------------------------------------------
 .../brooklyn/enricher/basic/Propagator.java     |  4 ++--
 .../brooklyn/enricher/basic/Transformer.java    |  6 +++---
 .../entity/basic/ServiceStateLogic.java         |  3 ++-
 .../rebind/PeriodicDeltaChangeListener.java     |  3 ++-
 .../event/basic/DependentConfiguration.java     | 10 ++++++----
 .../src/main/java/brooklyn/util/task/Tasks.java |  2 +-
 .../java/brooklyn/util/task/ValueResolver.java  | 20 ++++++++++++++++++++
 .../effector/SelectMasterEffectorBody.java      |  2 +-
 .../brooklyn/entity/software/StaticSensor.java  | 18 ++++++++++++++++--
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |  2 +-
 .../rest/resources/EntityConfigResource.java    |  3 ++-
 .../brooklyn/rest/resources/SensorResource.java |  3 ++-
 .../rest/transform/EffectorTransformer.java     |  5 ++---
 .../java/brooklyn/util/repeat/Repeater.java     |  7 +++++++
 14 files changed, 67 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/core/src/main/java/brooklyn/enricher/basic/Propagator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Propagator.java b/core/src/main/java/brooklyn/enricher/basic/Propagator.java
index 86795c6..06f63c4 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Propagator.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Propagator.java
@@ -37,7 +37,7 @@ import brooklyn.event.SensorEventListener;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.task.Tasks;
-import brooklyn.util.time.Duration;
+import brooklyn.util.task.ValueResolver;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
@@ -96,7 +96,7 @@ public class Propagator extends AbstractEnricher implements SensorEventListener<
             }
             
             for (Object sensorO : getConfig(PROPAGATING)) {
-                Sensor<?> sensor = Tasks.resolving(sensorO).as(Sensor.class).timeout(Duration.millis(50)).context(producer).get();
+                Sensor<?> sensor = Tasks.resolving(sensorO).as(Sensor.class).timeout(ValueResolver.REAL_QUICK_WAIT).context(producer).get();
                 if (!sensorMappingTemp.containsKey(sensor)) {
                     sensorMappingTemp.put(sensor, sensor);
                 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/core/src/main/java/brooklyn/enricher/basic/Transformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Transformer.java b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
index 0f6c409..6b2f7a8 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Transformer.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
@@ -28,7 +28,7 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.SensorEvent;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.task.Tasks;
-import brooklyn.util.time.Duration;
+import brooklyn.util.task.ValueResolver;
 
 import com.google.common.base.Function;
 import com.google.common.reflect.TypeToken;
@@ -84,7 +84,7 @@ public class Transformer<T,U> extends AbstractTransformer<T,U> {
         return new Function<SensorEvent<T>, U>() {
             @Override public U apply(SensorEvent<T> input) {
                 // evaluate immediately, or return null
-                // 200ms seems a reasonable compromise for tasks which require BG evaluation
+                // PRETTY_QUICK/200ms seems a reasonable compromise for tasks which require BG evaluation
                 // but which are non-blocking
                 // TODO better would be to have a mode in which tasks are not permitted to block on
                 // external events; they can submit tasks and block on them (or even better, have a callback architecture);
@@ -92,7 +92,7 @@ public class Transformer<T,U> extends AbstractTransformer<T,U> {
                 return (U) Tasks.resolving(targetValueRaw).as(targetSensor.getType())
                     .context(entity)
                     .description("Computing sensor "+targetSensor+" from "+targetValueRaw)
-                    .timeout(Duration.millis(200))
+                    .timeout(ValueResolver.PRETTY_QUICK_WAIT)
                     .getMaybe().orNull();
             }
             public String toString() {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java b/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
index 75bf9a6..eff8e2d 100644
--- a/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
+++ b/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
@@ -56,6 +56,7 @@ import brooklyn.util.collections.QuorumCheck;
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.repeat.Repeater;
+import brooklyn.util.task.ValueResolver;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 
@@ -148,7 +149,7 @@ public class ServiceStateLogic {
             if (!Boolean.TRUE.equals(up) && !Boolean.TRUE.equals(Entities.isReadOnly(entity))) {
                 // pause briefly to allow any recent problem-clearing processing to complete
                 Stopwatch timer = Stopwatch.createStarted();
-                boolean nowUp = Repeater.create().every(Duration.millis(10)).limitTimeTo(Duration.millis(200)).until(entity, 
+                boolean nowUp = Repeater.create().every(ValueResolver.REAL_QUICK_PERIOD).limitTimeTo(ValueResolver.PRETTY_QUICK_WAIT).until(entity, 
                     EntityPredicates.attributeEqualTo(Attributes.SERVICE_UP, true)).run();
                 if (nowUp) {
                     log.debug("Had to wait "+Duration.of(timer)+" for "+entity+" "+Attributes.SERVICE_UP+" to be true before setting "+state);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
index 2c3271d..0d88330 100644
--- a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
+++ b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
@@ -50,6 +50,7 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
+import brooklyn.util.repeat.Repeater;
 import brooklyn.util.task.ScheduledTask;
 import brooklyn.util.task.Tasks;
 import brooklyn.util.time.CountdownTimer;
@@ -279,7 +280,7 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
                     Duration left = timer.getDurationRemaining();
                     if (left.isPositive()) {
                         synchronized(writeCount) {
-                            writeCount.wait(left.lowerBound(Duration.millis(10)).toMilliseconds());
+                            writeCount.wait(left.lowerBound(Repeater.DEFAULT_REAL_QUICK_PERIOD).toMilliseconds());
                         }
                     } else {
                         throw new TimeoutException("Timeout waiting for independent write of rebind-periodic-delta, after "+timer.getDurationElapsed());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java b/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
index b462107..14a159d 100644
--- a/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
+++ b/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
@@ -70,6 +70,7 @@ import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.task.ParallelTask;
 import brooklyn.util.task.TaskInternal;
 import brooklyn.util.task.Tasks;
+import brooklyn.util.task.ValueResolver;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;
@@ -297,8 +298,8 @@ public class DependentConfiguration {
                 }
 
                 CountdownTimer timer = timeout!=null ? timeout.countdownTimer() : null;
-                Duration maxPeriod = Duration.millis(200);
-                Duration nextPeriod = Duration.millis(10);
+                Duration maxPeriod = ValueResolver.PRETTY_QUICK_WAIT;
+                Duration nextPeriod = ValueResolver.REAL_QUICK_PERIOD;
                 while (true) {
                     // check the source on initial run (could be done outside the loop) 
                     // and also (optionally) on each iteration in case it is more recent 
@@ -407,7 +408,7 @@ public class DependentConfiguration {
     /** Returns a task which waits for multiple other tasks (submitting if necessary)
      * and performs arbitrary computation over the List of results.
      * @see #transform(Task, Function) but note argument order is reversed (counterintuitive) to allow for varargs */
-    public static <U,T> Task<T> transformMultiple(Function<List<U>,T> transformer, TaskAdaptable<U> ...tasks) {
+    public static <U,T> Task<T> transformMultiple(Function<List<U>,T> transformer, @SuppressWarnings("unchecked") TaskAdaptable<U> ...tasks) {
         return transformMultiple(MutableMap.of("displayName", "transforming multiple"), transformer, tasks);
     }
 
@@ -425,7 +426,7 @@ public class DependentConfiguration {
     
     /** @see #transformMultiple(Function, TaskAdaptable...) */
     @SuppressWarnings({ "rawtypes" })
-    public static <U,T> Task<T> transformMultiple(Map flags, final Function<List<U>,T> transformer, TaskAdaptable<U> ...tasks) {
+    public static <U,T> Task<T> transformMultiple(Map flags, final Function<List<U>,T> transformer, @SuppressWarnings("unchecked") TaskAdaptable<U> ...tasks) {
         return transformMultiple(flags, transformer, Arrays.asList(tasks));
     }
     @SuppressWarnings({ "rawtypes" })
@@ -687,6 +688,7 @@ public class DependentConfiguration {
             validate();
             return new WaitInTaskForAttributeReady<T,V>(this).call();
         }
+        @SuppressWarnings({ "unchecked", "rawtypes" })
         private void validate() {
             checkNotNull(source, "Entity source");
             checkNotNull(sensor, "Sensor");

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/core/src/main/java/brooklyn/util/task/Tasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/Tasks.java b/core/src/main/java/brooklyn/util/task/Tasks.java
index 573b342..f59e2d1 100644
--- a/core/src/main/java/brooklyn/util/task/Tasks.java
+++ b/core/src/main/java/brooklyn/util/task/Tasks.java
@@ -421,7 +421,7 @@ public class Tasks {
             }
             if (timer.isExpired())
                 return false;
-            Time.sleep(Duration.millis(10));
+            Time.sleep(Repeater.DEFAULT_REAL_QUICK_PERIOD);
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/core/src/main/java/brooklyn/util/task/ValueResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ValueResolver.java b/core/src/main/java/brooklyn/util/task/ValueResolver.java
index 71b34a0..0670ad6 100644
--- a/core/src/main/java/brooklyn/util/task/ValueResolver.java
+++ b/core/src/main/java/brooklyn/util/task/ValueResolver.java
@@ -38,6 +38,7 @@ import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.JavaClassNames;
+import brooklyn.util.repeat.Repeater;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Durations;
@@ -57,6 +58,25 @@ import com.google.common.reflect.TypeToken;
  */
 public class ValueResolver<T> implements DeferredSupplier<T> {
 
+    /** 
+     * Period to wait if we're expected to return real quick 
+     * but we want fast things to have time to finish.
+     * <p>
+     * Timings are always somewhat arbitrary but this at least
+     * allows some intention to be captured in code rather than arbitrary values. */
+    public static Duration REAL_QUICK_WAIT = Duration.millis(50);
+    /** 
+     * Period to wait if we're expected to return quickly 
+     * but we want to be a bit more generous for things to finish,
+     * without letting a caller get annoyed. 
+     * <p>
+     * See {@link #REAL_QUICK_WAIT}. */
+    public static Duration PRETTY_QUICK_WAIT = Duration.millis(200);
+    
+    /** Period to wait when we have to poll but want to give the illusion of no wait.
+     * See {@link Repeater#DEFAULT_REAL_QUICK_PERIOD} */ 
+    public static Duration REAL_QUICK_PERIOD = Repeater.DEFAULT_REAL_QUICK_PERIOD;
+    
     private static final Logger log = LoggerFactory.getLogger(ValueResolver.class);
     
     final Object value;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
index 7ed3cb8..af07f3a 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
@@ -107,7 +107,7 @@ public class SelectMasterEffectorBody extends EffectorBody<Void> implements Sele
 
     private void waitMasterHandover(final Entity oldMaster, final Entity newMaster) {
         boolean masterChanged = Repeater.create()
-            .backoff(Duration.millis(50), 1.5, Duration.FIVE_SECONDS)
+            .backoff(Repeater.DEFAULT_REAL_QUICK_PERIOD, 1.5, Duration.FIVE_SECONDS)
             .limitTimeTo(Duration.ONE_MINUTE)
             .until(new Callable<Boolean>() {
                 @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
index 8688ec8..4b7c9d6 100644
--- a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
@@ -22,14 +22,28 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
+import brooklyn.enricher.basic.Propagator;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.effector.AddSensor;
+import brooklyn.management.Task;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.Tasks;
-import brooklyn.util.time.Duration;
+import brooklyn.util.task.ValueResolver;
 
+import com.google.common.base.Supplier;
+
+/** 
+ * Provides an initializer/feed which simply sets a given value.
+ * <p>
+ * {@link Task}/{@link Supplier} values are resolved when written,
+ * unlike config values which are resolved on each read.
+ * <p>
+ * This supports a {@link StaticSensor#SENSOR_PERIOD} 
+ * which can be useful if the supplied value is such a function.
+ * However when the source is another sensor,
+ * consider using {@link Propagator} which listens for changes instead. */
 public class StaticSensor<T> extends AddSensor<T> {
 
     private static final Logger log = LoggerFactory.getLogger(StaticSensor.class);
@@ -48,7 +62,7 @@ public class StaticSensor<T> extends AddSensor<T> {
     public void apply(EntityLocal entity) {
         super.apply(entity);
         
-        Maybe<T> v = Tasks.resolving(value).as((Class<T>)sensor.getType()).timeout(Duration.millis(200)).getMaybe();
+        Maybe<T> v = Tasks.resolving(value).as((Class<T>)sensor.getType()).timeout(ValueResolver.PRETTY_QUICK_WAIT).getMaybe();
         if (v.isPresent()) {
             log.debug(this+" setting sensor "+sensor+" to "+v.get());
             entity.setAttribute(sensor, v.get());

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
index 129bf3d..6dd97d6 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/couchbase/CouchbaseNodeSshDriver.java
@@ -344,7 +344,7 @@ public class CouchbaseNodeSshDriver extends AbstractSoftwareProcessSshDriver imp
         // wait until the re-balance is started
         // (if it's quick, this might miss it, but it will only block for 30s if so)
         Repeater.create()
-                .backoff(Duration.millis(10), 2, Duration.millis(500))
+                .backoff(Repeater.DEFAULT_REAL_QUICK_PERIOD, 2, Duration.millis(500))
                 .limitTimeTo(Duration.THIRTY_SECONDS)
                 .until(new Callable<Boolean>() {
                            @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java
index 219d67a..e7104c9 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/EntityConfigResource.java
@@ -39,6 +39,7 @@ import brooklyn.rest.filter.HaHotStateRequired;
 import brooklyn.rest.transform.EntityTransformer;
 import brooklyn.rest.util.WebResourceUtils;
 import brooklyn.util.flags.TypeCoercions;
+import brooklyn.util.task.ValueResolver;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 
@@ -96,7 +97,7 @@ public class EntityConfigResource extends AbstractBrooklynRestResource implement
         EntityLocal entity = brooklyn().getEntity(application, entityToken);
         ConfigKey<?> ck = findConfig(entity, configKeyName);
         Object value = ((EntityInternal)entity).config().getRaw(ck).orNull();
-        return resolving(value).preferJson(preferJson).asJerseyOutermostReturnValue(true).raw(raw).context(entity).timeout(Duration.millis(100)).renderAs(ck).resolve();
+        return resolving(value).preferJson(preferJson).asJerseyOutermostReturnValue(true).raw(raw).context(entity).timeout(ValueResolver.PRETTY_QUICK_WAIT).renderAs(ck).resolve();
     }
 
     private ConfigKey<?> findConfig(EntityLocal entity, String configKeyName) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java b/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
index 6e49acc..05bf73e 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/resources/SensorResource.java
@@ -38,6 +38,7 @@ import brooklyn.rest.domain.SensorSummary;
 import brooklyn.rest.filter.HaHotStateRequired;
 import brooklyn.rest.transform.SensorTransformer;
 import brooklyn.rest.util.WebResourceUtils;
+import brooklyn.util.task.ValueResolver;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 
@@ -83,7 +84,7 @@ public class SensorResource extends AbstractBrooklynRestResource implements Sens
         final EntityLocal entity = brooklyn().getEntity(application, entityToken);
         AttributeSensor<?> sensor = findSensor(entity, sensorName);
         Object value = entity.getAttribute(sensor);
-        return resolving(value).preferJson(preferJson).asJerseyOutermostReturnValue(true).raw(raw).context(entity).timeout(Duration.millis(100)).renderAs(sensor).resolve();
+        return resolving(value).preferJson(preferJson).asJerseyOutermostReturnValue(true).raw(raw).context(entity).timeout(ValueResolver.PRETTY_QUICK_WAIT).renderAs(sensor).resolve();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java b/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
index 925ed8f..c71680a 100644
--- a/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
+++ b/usage/rest-server/src/main/java/brooklyn/rest/transform/EffectorTransformer.java
@@ -26,7 +26,6 @@ import javax.annotation.Nullable;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
 import brooklyn.entity.ParameterType;
-import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.rest.domain.EffectorSummary;
 import brooklyn.rest.domain.EffectorSummary.ParameterSummary;
@@ -34,7 +33,7 @@ import brooklyn.rest.util.WebResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.Tasks;
-import brooklyn.util.time.Duration;
+import brooklyn.util.task.ValueResolver;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMap;
@@ -76,7 +75,7 @@ public class EffectorTransformer {
     protected static EffectorSummary.ParameterSummary<?> parameterSummary(Entity entity, ParameterType<?> parameterType) {
         try {
             Maybe<?> defaultValue = Tasks.resolving(parameterType.getDefaultValue()).as(parameterType.getParameterClass())
-                .context(entity).timeout(Duration.millis(50)).getMaybe();
+                .context(entity).timeout(ValueResolver.REAL_QUICK_WAIT).getMaybe();
             return new ParameterSummary(parameterType.getName(), parameterType.getParameterClassName(), 
                 parameterType.getDescription(), 
                 WebResourceUtils.getValueForDisplay(defaultValue.orNull(), true, false));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/8df4cdfd/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java b/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
index bd76ea8..a80bb27 100644
--- a/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
+++ b/utils/common/src/main/java/brooklyn/util/repeat/Repeater.java
@@ -83,6 +83,13 @@ public class Repeater {
 
     private static final Logger log = LoggerFactory.getLogger(Repeater.class);
 
+    /** A small initial duration that something should wait between repeats, 
+     * e.g. when doing {@link #backoffTo(Duration)}.
+     * <p>
+     * Chosen to be small enough that a user won't notice at all,
+     * but we're not going to be chewing up CPU while waiting. */  
+    public static final Duration DEFAULT_REAL_QUICK_PERIOD = Duration.millis(10);
+    
     private final String description;
     private Callable<?> body = Callables.returning(null);
     private Callable<Boolean> exitCondition;


[18/22] incubator-brooklyn git commit: expand the default catalog to have several nice example templates

Posted by he...@apache.org.
expand the default catalog to have several nice example templates


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

Branch: refs/heads/master
Commit: 7ba5833c3700581048e42db8e1547289bd1b2299
Parents: e9daca7
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jun 19 05:04:12 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:34 2015 -0700

----------------------------------------------------------------------
 .../main/resources/brooklyn/default.catalog.bom | 342 ++++++++++++++++++-
 1 file changed, 330 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7ba5833c/usage/cli/src/main/resources/brooklyn/default.catalog.bom
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/resources/brooklyn/default.catalog.bom b/usage/cli/src/main/resources/brooklyn/default.catalog.bom
index 42672ae..4da8319 100644
--- a/usage/cli/src/main/resources/brooklyn/default.catalog.bom
+++ b/usage/cli/src/main/resources/brooklyn/default.catalog.bom
@@ -17,25 +17,343 @@ brooklyn.catalog:
       type: brooklyn.entity.basic.EmptySoftwareProcess
       name: Server
 
-  - id: server-template
+  - id: vanilla-bash-server
+    description: |
+      Provision a server, with customizable provisioning.properties and credentials installed, 
+      but no other special software process or scripts executed.
+      The script should be supplied in "launch.command" as per docs on
+      brooklyn.entity.basic.VanillaSoftwareProcess.
+    item:
+      type: brooklyn.entity.basic.VanillaSoftwareProcess
+      name: Server with Launch Script (bash)
+
+  - id: load-balancer
+    description: |
+      Create a load balancer which will point at members in the group entity
+      referred to by the config key "serverPool". 
+      The sensor advertising the port can be configured with the "member.sensor.portNumber" config key,
+      defaulting to `http.port`; all member entities which have published "service.up" will then be picked up.
+    item:
+      type: brooklyn.entity.proxy.nginx.NginxController
+      name: Load Balancer (nginx)
+
+  - id: cluster
+    description: |
+      Create a cluster of entities, resizable, with starting size "initialSize",
+      and using a spec supplied in the "memberSpec" key.
+    item:
+      type: brooklyn.entity.group.DynamicCluster
+
+  - id: 1-server-template
     itemType: template
-    name: Server Template
+    name: "Template 1: Server"
     description: |
       Sample YAML to provision a server in a cloud with illustrative VM properties
     item:
-      name: My App with a single VM
+      name: Server (Brooklyn Example)
+      
+      # this basic example shows how Brooklyn can provision a single raw VM
+      # in the cloud or location of your choice
+      
       services:
-      - type: server
-        name: My VM
+      - type:           server
+        name:           My VM
+      
+      # location can be `softlayer` or `jclouds:openstack-nova:https://9.9.9.9:9999/v2.0/`,
+      # or `localhost` or `byon: { nodes: [ 10.0.0.1, 10.0.0.2, 10.0.1.{1,2} ] }` 
       location:
         jclouds:aws-ec2:
-          identity: <REPLACE>
-          credential: <REPLACE>
-          region: eu-west-1
+          # edit these to use your credential(or delete if credentials specified in brooklyn.properties)      
+          identity:     <REPLACE>
+          credential:   <REPLACE>
+          
+          region:       eu-west-1
+          
           # we want Ubuntu, with a lot of RAM
-          osFamily: ubuntu
-          minRam: 8gb
+          osFamily:     ubuntu
+          minRam:       8gb
+          
           # set up this user and password (default is to authorize a public key)
-          user: sample
-          password: s4mpl3
+          user:         sample
+          password:     s4mpl3
+
+  - id: 2-bash-web-server-template
+    itemType: template
+    name: "Template 2: Bash Web Server"
+    description: |
+      Sample YAML building on Template 1, 
+      adding bash commands to launch a Python-based web server
+      on port 8020
+    item:
+      name: Python Web Server (Brooklyn Example)
+      
+      # this example builds on the previous one, 
+      # adding some scripts to initialize the VM
+      
+      services:
+      - type:           vanilla-bash-server
+        name:           My Bash Web Server VM
+        brooklyn.config:
+          install.command: |
+            # install python if not present
+            which python || \
+              { apt-get update && apt-get install python ; } || \
+              { yum update && yum install python ; } || \
+              { echo WARNING: cannot install python && exit 1 ; }
 
+          customize.command: |
+            # create the web page to serve
+            cat > index.html << EOF
+            
+            Hello world.
+            <p>
+            I am ${ENTITY_INFO}, ${MESSAGE:-a Brooklyn sample}.
+            <p>
+            Created at: `date`
+            <p>
+            I am running at ${HOSTNAME}, with on-box IP configuration:
+            <pre>
+            `ifconfig | grep inet`
+            </pre>
+            
+            EOF
+
+          launch.command: |
+            # launch in background (ensuring no streams open), and record PID to file
+            nohup python -m SimpleHTTPServer ${PORT:-8020} < /dev/null > output.txt 2>&1 &
+            echo $! > ${PID_FILE:-pid.txt}
+            sleep 5
+            ps -p `cat ${PID_FILE:-pid.txt}`
+            if [ $? -ne 0 ] ; then
+              cat output.txt
+              echo WARNING: python web server not running
+              exit 1
+            fi
+            
+          shell.env:
+            HOSTNAME:     $brooklyn:attributeWhenReady("host.name")
+            PORT:         $brooklyn:config("my.app.port")
+            ENTITY_INFO:  $brooklyn:component("this", "")
+            MESSAGE:      $brooklyn:config("my.message")
+            
+          # custom 
+          my.app.port:  8020
+          my.message:   "good to meet you"
+        
+        brooklyn.enrichers:
+        # publish the URL as a sensor; the GUI will pick this up (main.uri)
+        - type: brooklyn.enricher.basic.Transformer
+          brooklyn.config:
+            uniqueTag: url-generator
+            enricher.sourceSensor: host.subnet.hostname
+            # use the definition from Attributes class, as it has a RendererHint so GUI makes it a link
+            enricher.targetSensor: $brooklyn:sensor("brooklyn.entity.basic.Attributes", "main.uri")
+            enricher.targetValue: 
+              $brooklyn:formatString:
+              - "http://%s:%s/" 
+              - $brooklyn:attributeWhenReady("host.subnet.hostname")
+              - $brooklyn:config("my.app.port")
+      
+      location:
+        jclouds:aws-ec2:
+          region:       eu-west-1
+          # edit these (or delete if credentials specified in brooklyn.properties)      
+          identity:     <REPLACE>
+          credential:   <REPLACE>
+        
+  - id: 3-bash-web-and-riak-template
+    itemType: template
+    name: "Template 3: Bash Web Server and Scaling Riak Cluster"
+    description: |
+      Sample YAML building on Template 2, 
+      composing that blueprint with a Riak cluster and injecting the URL
+    item:
+      name: Bash Web Server and Riak Cluster (Brooklyn Example)
+    
+      # this example *references* the previous one, 
+      # combining it with a stock blueprint for a Riak cluster,
+      # and shows how a sensor from the latter can be injected
+      
+      services:
+      
+      # reference template 2, overriding message to point at riak 
+      - type:           2-bash-web-server-template
+        brooklyn.config:
+          my.message:   $brooklyn:formatString("connected to Riak at %s",
+                            $brooklyn:entity("riak-cluster").attributeWhenReady("main.uri"))
+                            
+      # use the off-the-shelf Riak cluster
+      - type:           brooklyn.entity.nosql.riak.RiakCluster
+        id:             riak-cluster
+        initialSize:    3
+        # and add a policy to scale based on ops per minute
+        brooklyn.policies:
+        - type: brooklyn.policy.autoscaling.AutoScalerPolicy
+          brooklyn.config:
+            metric: riak.node.ops.1m.perNode
+            # more than 100 ops per second (6k/min) scales out, less than 50 scales back
+            # up to a max of 8 riak nodes here (can be changed in GUI / REST API afterwards)
+            metricLowerBound: 3000
+            metricUpperBound: 6000
+            minPoolSize: 3
+            maxPoolSize: 8
+            resizeUpStabilizationDelay: 30s
+            resizeDownStabilizationDelay: 5m
+          
+      location:
+        jclouds:aws-ec2:
+          region:       eu-west-1
+          # edit these (or delete if credentials specified in brooklyn.properties)      
+          identity:     <REPLACE>
+          credential:   <REPLACE>
+
+  - id: 4-resilient-bash-web-cluster-template
+    itemType: template
+    name: "Template 4: Resilient Load-Balanced Bash Web Cluster with Sensors"
+    description: |
+      Sample YAML to provision a cluster of the bash/python web server nodes,
+      with sensors configured, and a load balancer pointing at them,
+      and resilience policies for node replacement and scaling
+    item:
+      name: Resilient Load-Balanced Bash Web Cluster (Brooklyn Example)
+      
+      # this final example shows some of the advanced functionality:
+      # defining custom sensors, and a cluster with a "spec", 
+      # policies for resilience and scaling based on that sensor,
+      # and wiring a load balancer in front of the cluster
+      
+      # combining this with the riak cluster in the previous example
+      # is left as a suggested exercise for the user
+      
+      services:
+      
+      # define a cluster of the web nodes
+      - type:           cluster
+        name:           Cluster of Bash Web Nodes
+        id:             my-web-cluster
+        brooklyn.config:
+          initialSize:  1
+          memberSpec:
+            $brooklyn:entitySpec:
+              # template 2 is used as the spec for items in this cluster
+              # with a new message overwriting the previous,
+              # and a lot of sensors defined
+              type:           2-bash-web-server-template
+              name:           My Bash Web Server VM with Sensors
+              
+              brooklyn.config:
+                my.message:   "part of the cluster"
+              
+              brooklyn.initializers:
+              # make a simple request-count sensor, by counting the number of 200 responses in output.txt
+              - type: brooklyn.entity.software.ssh.SshCommandSensor
+                brooklyn.config:
+                  name: reqs.count
+                  targetType: int
+                  period: 5s
+                  command: "cat output.txt | grep HTTP | grep 200 | wc | awk '{print $1}'"
+              # and publish the port as a sensor so the load-balancer can pick it up
+              - type:           brooklyn.entity.software.StaticSensor
+                brooklyn.config:
+                  name:         app.port
+                  targetType:   int
+                  static.value: $brooklyn:config("my.app.port")
+              
+              brooklyn.enrichers:
+              # derive reqs.per_sec from reqs.count
+              - type: brooklyn.enricher.basic.YamlTimeWeightedDeltaEnricher
+                brooklyn.config:
+                  enricher.sourceSensor: reqs.count
+                  enricher.targetSensor: reqs.per_sec
+                  enricher.delta.period: 1s
+              # and take an average over 30s for reqs.per_sec into reqs.per_sec.windowed_30s
+              - type: brooklyn.enricher.basic.YamlRollingTimeWindowMeanEnricher
+                brooklyn.config:
+                  enricher.sourceSensor: reqs.per_sec
+                  enricher.targetSensor: reqs.per_sec.windowed_30s
+                  enricher.window.duration: 30s
+              
+              # emit failure sensor if a failure connecting to the service is sustained for 30s
+              - type: brooklyn.policy.ha.ServiceFailureDetector
+                brooklyn.config:
+                  entityFailed.stabilizationDelay: 30s
+            
+              brooklyn.policies:
+              # restart if a failure is detected (with a max of one restart in 2m, sensor will propagate otherwise) 
+              - type: brooklyn.policy.ha.ServiceRestarter
+                brooklyn.config:
+                  failOnRecurringFailuresInThisDuration: 2m
+        
+        # back at the cluster, create a total per-sec and some per-node average
+        brooklyn.enrichers:
+        - type: brooklyn.enricher.basic.Aggregator
+          brooklyn.config:
+            enricher.sourceSensor: reqs.per_sec
+            enricher.targetSensor: reqs.per_sec
+            transformation: sum
+        - type: brooklyn.enricher.basic.Aggregator
+          brooklyn.config:
+            enricher.sourceSensor: reqs.per_sec
+            enricher.targetSensor: reqs.per_sec.per_node
+            transformation: average
+        - type: brooklyn.enricher.basic.Aggregator
+          brooklyn.config:
+            enricher.sourceSensor: reqs.per_sec.windowed_30s
+            enricher.targetSensor: reqs.per_sec.windowed_30s.per_node
+            transformation: average
+              
+        brooklyn.policies:
+        # resilience: if a per-node restart policy fails,
+        # just throw that node away and create a new one
+        - type: brooklyn.policy.ha.ServiceReplacer
+        
+        # and scale based on reqs/sec
+        - type: brooklyn.policy.autoscaling.AutoScalerPolicy
+          brooklyn.config:
+            # scale based on reqs/sec (though in a real-world situation, 
+            # reqs.per_sec.windowed_30s.per_node might be a better choice) 
+            metric: reqs.per_sec.per_node
+            
+            # really low numbers, so you can trigger a scale-out just by hitting reload a lot
+            metricUpperBound: 3
+            metricLowerBound: 1
+            
+            # sustain 3 reqs/sec for 2s and it will scale out
+            resizeUpStabilizationDelay: 2s
+            # only scale down when sustained for 1m
+            resizeDownStabilizationDelay: 1m
+      
+            maxPoolSize: 10
+            
+      # and add a load-balancer pointing at the cluster
+      - type:           load-balancer
+        id:             load-bal
+        brooklyn.config:
+          # point this load balancer at the cluster, specifying port to forward to
+          loadbalancer.serverpool:  $brooklyn:entity("my-web-cluster")
+          member.sensor.portNumber: app.port
+      
+      brooklyn.enrichers:
+      # publish a few useful info sensors and KPI's to the root of the app
+      - type: brooklyn.enricher.basic.Propagator
+        brooklyn.config:
+          uniqueTag:    propagate-load-balancer-url
+          producer:     $brooklyn:entity("load-bal")
+          propagating:
+          - main.uri
+      - type: brooklyn.enricher.basic.Propagator
+        brooklyn.config:
+          uniqueTag:    propagate-reqs-per-sec
+          producer:     $brooklyn:entity("my-web-cluster")
+          propagating:
+          - reqs.per_sec
+          - reqs.per_sec.windowed_30s.per_node
+      
+      location:
+        jclouds:aws-ec2:
+          # edit these (or delete if credentials specified in brooklyn.properties)      
+          identity:     <REPLACE>
+          credential:   <REPLACE>
+          
+          region:       eu-west-1
+          minRam:       2gb


[03/22] incubator-brooklyn git commit: fix warnings in dist build

Posted by he...@apache.org.
fix warnings in dist build


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

Branch: refs/heads/master
Commit: 7b9d0e05aa7387954c0bd63cc7dad6aad36e5886
Parents: b12ebb4
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Jun 15 11:54:27 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:32 2015 -0700

----------------------------------------------------------------------
 usage/dist/pom.xml                                |  2 ++
 usage/dist/src/main/config/build-distribution.xml | 14 +++++++-------
 2 files changed, 9 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7b9d0e05/usage/dist/pom.xml
----------------------------------------------------------------------
diff --git a/usage/dist/pom.xml b/usage/dist/pom.xml
index 173dda4..401433d 100644
--- a/usage/dist/pom.xml
+++ b/usage/dist/pom.xml
@@ -91,6 +91,7 @@
                             <formats>
                                 <format>dir</format>
                             </formats>
+                            <attach>false</attach>
                         </configuration>
                     </execution>
                     <execution>
@@ -109,6 +110,7 @@
                                 <format>tar.gz</format>
                                 <format>zip</format>
                             </formats>
+                            <attach>false</attach>
                         </configuration>
                     </execution>
                 </executions>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/7b9d0e05/usage/dist/src/main/config/build-distribution.xml
----------------------------------------------------------------------
diff --git a/usage/dist/src/main/config/build-distribution.xml b/usage/dist/src/main/config/build-distribution.xml
index 9398150..d3792bc 100644
--- a/usage/dist/src/main/config/build-distribution.xml
+++ b/usage/dist/src/main/config/build-distribution.xml
@@ -25,7 +25,7 @@
     <fileSets>
         <fileSet>
             <directory>${project.basedir}/../..</directory>
-            <outputDirectory>/</outputDirectory>
+            <outputDirectory></outputDirectory>
             <fileMode>0644</fileMode>
             <directoryMode>0755</directoryMode>
             <includes>
@@ -35,20 +35,20 @@
         </fileSet>
         <fileSet>
             <directory>${project.basedir}/src/main/license</directory>
-            <outputDirectory>/</outputDirectory>
+            <outputDirectory></outputDirectory>
             <fileMode>0644</fileMode>
             <directoryMode>0755</directoryMode>
         </fileSet>
         <fileSet>
             <directory>${project.basedir}/src/main/dist/bin</directory>
-            <outputDirectory>/bin</outputDirectory>
+            <outputDirectory>bin</outputDirectory>
             <fileMode>0755</fileMode>
             <directoryMode>0755</directoryMode>
         </fileSet>
         <fileSet>
             <!-- Add an empty dropins folder (so need to reference an existing dir, and exclude everything) -->
             <directory>${project.basedir}/src/main/dist</directory>
-            <outputDirectory>/lib/dropins</outputDirectory>
+            <outputDirectory>lib/dropins</outputDirectory>
             <directoryMode>0755</directoryMode>
             <excludes>
                 <exclude>**/*</exclude>
@@ -57,7 +57,7 @@
         <fileSet>
             <!-- Add an empty patch folder (so need to reference an existing dir, and exclude everything) -->
             <directory>${project.basedir}/src/main/dist</directory>
-            <outputDirectory>/lib/patch</outputDirectory>
+            <outputDirectory>lib/patch</outputDirectory>
             <directoryMode>0755</directoryMode>
             <excludes>
                 <exclude>**/*</exclude>
@@ -65,7 +65,7 @@
         </fileSet>
         <fileSet>
             <directory>${project.basedir}/src/main/dist</directory>
-            <outputDirectory>/</outputDirectory>
+            <outputDirectory></outputDirectory>
             <fileMode>0644</fileMode>
             <directoryMode>0755</directoryMode>
             <excludes>
@@ -78,7 +78,7 @@
     <dependencySets>
         <dependencySet>
             <useProjectArtifact>false</useProjectArtifact>
-            <outputDirectory>/lib/brooklyn</outputDirectory>
+            <outputDirectory>lib/brooklyn</outputDirectory>
             <fileMode>0644</fileMode>
             <directoryMode>0755</directoryMode>
             <outputFileNameMapping>${artifact.groupId}-${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>


[04/22] incubator-brooklyn git commit: exclude bom files from rat check, where these are intended for the user to modify

Posted by he...@apache.org.
exclude bom files from rat check, where these are intended for the user to modify


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

Branch: refs/heads/master
Commit: 1744fbfdbc9832c7903990bc3902e1ebda17024d
Parents: b08fe4e
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Jun 10 19:00:21 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:32 2015 -0700

----------------------------------------------------------------------
 usage/cli/pom.xml | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/1744fbfd/usage/cli/pom.xml
----------------------------------------------------------------------
diff --git a/usage/cli/pom.xml b/usage/cli/pom.xml
index 451b0ed..ac4f0fc 100644
--- a/usage/cli/pom.xml
+++ b/usage/cli/pom.xml
@@ -165,6 +165,7 @@
                                 i.e. by brooklyn.cli.itemlister.ItemLister
                             -->
                             <exclude>**/src/main/resources/brooklyn/item-lister/statics/style/js/**</exclude>
+                            <exclude>**/*.bom</exclude>
                         </excludes>
                     </configuration>
                 </plugin>


[06/22] incubator-brooklyn git commit: adjust synch model for controller

Posted by he...@apache.org.
adjust synch model for controller

should not synch on class as that is used for things like getExecutionContext (and so can deadlock)


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

Branch: refs/heads/master
Commit: ceee1c0dbb4f9d38e253e88abd78f0952b6f42c9
Parents: e3db4f2
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jun 18 08:55:16 2015 -0700
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Wed Jun 24 00:40:32 2015 -0700

----------------------------------------------------------------------
 .../entity/proxy/AbstractControllerImpl.java    | 141 ++++++++++---------
 1 file changed, 76 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ceee1c0d/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java b/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java
index 297364f..a79b98b 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java
@@ -68,7 +68,7 @@ import com.google.common.net.HostAndPort;
 public abstract class AbstractControllerImpl extends SoftwareProcessImpl implements AbstractController {
     
     // TODO Should review synchronization model. Currently, all changes to the serverPoolTargets
-    // (and checking for potential changes) is done while synchronized on this. That means it 
+    // (and checking for potential changes) is done while synchronized on serverPoolAddresses. That means it 
     // will also call update/reload while holding the lock. This is "conservative", but means
     // sub-classes need to be extremely careful about any additional synchronization and of
     // their implementations of update/reconfigureService/reload.
@@ -79,7 +79,8 @@ public abstract class AbstractControllerImpl extends SoftwareProcessImpl impleme
     protected volatile boolean updateNeeded = true;
 
     protected AbstractMembershipTrackingPolicy serverPoolMemberTrackerPolicy;
-    protected Set<String> serverPoolAddresses = Sets.newLinkedHashSet();
+    // final because this is the synch target
+    final protected Set<String> serverPoolAddresses = Sets.newLinkedHashSet();
     protected Map<Entity,String> serverPoolTargets = Maps.newLinkedHashMap();
     
     public AbstractControllerImpl() {
@@ -356,17 +357,19 @@ public abstract class AbstractControllerImpl extends SoftwareProcessImpl impleme
      */
     protected abstract void reconfigureService();
     
-    public synchronized void updateNeeded() {
-        if (updateNeeded) return;
-        updateNeeded = true;
-        LOG.debug("queueing an update-needed task for "+this+"; update will occur shortly");
-        Entities.submit(this, Tasks.builder().name("update-needed").body(new Runnable() {
-            @Override
-            public void run() {
-                if (updateNeeded)
-                    AbstractControllerImpl.this.update();
-            } 
-        }).build());
+    public void updateNeeded() {
+        synchronized (serverPoolAddresses) {
+            if (updateNeeded) return;
+            updateNeeded = true;
+            LOG.debug("queueing an update-needed task for "+this+"; update will occur shortly");
+            Entities.submit(this, Tasks.builder().name("update-needed").body(new Runnable() {
+                @Override
+                public void run() {
+                    if (updateNeeded)
+                        AbstractControllerImpl.this.update();
+                } 
+            }).build());
+        }
     }
     
     @Override
@@ -381,30 +384,34 @@ public abstract class AbstractControllerImpl extends SoftwareProcessImpl impleme
         }
     }
     
-    public synchronized Task<?> updateAsync() {
-        Task<?> result = null;
-        if (!isActive()) updateNeeded = true;
-        else {
-            updateNeeded = false;
-            LOG.debug("Updating {} in response to changes", this);
-            LOG.info("Updating {}, server pool targets {}", new Object[] {this, getAttribute(SERVER_POOL_TARGETS)});
-            reconfigureService();
-            LOG.debug("Reloading {} in response to changes", this);
-            // reload should happen synchronously
-            result = invoke(RELOAD);
+    public Task<?> updateAsync() {
+        synchronized (serverPoolAddresses) {
+            Task<?> result = null;
+            if (!isActive()) updateNeeded = true;
+            else {
+                updateNeeded = false;
+                LOG.debug("Updating {} in response to changes", this);
+                LOG.info("Updating {}, server pool targets {}", new Object[] {this, getAttribute(SERVER_POOL_TARGETS)});
+                reconfigureService();
+                LOG.debug("Reloading {} in response to changes", this);
+                // reload should happen synchronously
+                result = invoke(RELOAD);
+            }
+            return result;
         }
-        return result;
     }
 
-    protected synchronized void onServerPoolMemberChanged(Entity member) {
-        if (LOG.isTraceEnabled()) LOG.trace("For {}, considering membership of {} which is in locations {}", 
+    protected void onServerPoolMemberChanged(Entity member) {
+        synchronized (serverPoolAddresses) {
+            if (LOG.isTraceEnabled()) LOG.trace("For {}, considering membership of {} which is in locations {}", 
                 new Object[] {this, member, member.getLocations()});
-        if (belongsInServerPool(member)) {
-            addServerPoolMember(member);
-        } else {
-            removeServerPoolMember(member);
+            if (belongsInServerPool(member)) {
+                addServerPoolMember(member);
+            } else {
+                removeServerPoolMember(member);
+            }
+            if (LOG.isTraceEnabled()) LOG.trace("Done {} checkEntity {}", this, member);
         }
-        if (LOG.isTraceEnabled()) LOG.trace("Done {} checkEntity {}", this, member);
     }
     
     protected boolean belongsInServerPool(Entity member) {
@@ -420,45 +427,49 @@ public abstract class AbstractControllerImpl extends SoftwareProcessImpl impleme
         return true;
     }
     
-    protected synchronized void addServerPoolMember(Entity member) {
-        String oldAddress = getAttribute(SERVER_POOL_TARGETS).get(member);
-        String newAddress = getAddressOfEntity(member);
-        if (Objects.equal(newAddress, oldAddress)) {
-            if (LOG.isTraceEnabled())
-                if (LOG.isTraceEnabled()) LOG.trace("Ignoring unchanged address {}", oldAddress);
-            return;
-        } else if (newAddress == null) {
-            LOG.info("Removing from {}, member {} with old address {}, because inferred address is now null", new Object[] {this, member, oldAddress});
-        } else {
-            if (oldAddress != null) {
-                LOG.info("Replacing in {}, member {} with old address {}, new address {}", new Object[] {this, member, oldAddress, newAddress});
+    protected void addServerPoolMember(Entity member) {
+        synchronized (serverPoolAddresses) {
+            String oldAddress = getAttribute(SERVER_POOL_TARGETS).get(member);
+            String newAddress = getAddressOfEntity(member);
+            if (Objects.equal(newAddress, oldAddress)) {
+                if (LOG.isTraceEnabled())
+                    if (LOG.isTraceEnabled()) LOG.trace("Ignoring unchanged address {}", oldAddress);
+                return;
+            } else if (newAddress == null) {
+                LOG.info("Removing from {}, member {} with old address {}, because inferred address is now null", new Object[] {this, member, oldAddress});
             } else {
-                LOG.info("Adding to {}, new member {} with address {}", new Object[] {this, member, newAddress});
+                if (oldAddress != null) {
+                    LOG.info("Replacing in {}, member {} with old address {}, new address {}", new Object[] {this, member, oldAddress, newAddress});
+                } else {
+                    LOG.info("Adding to {}, new member {} with address {}", new Object[] {this, member, newAddress});
+                }
             }
+
+            if (Objects.equal(oldAddress, newAddress)) {
+                if (LOG.isTraceEnabled()) LOG.trace("For {}, ignoring change in member {} because address still {}", new Object[] {this, member, newAddress});
+                return;
+            }
+
+            // TODO this does it synchronously; an async method leaning on `updateNeeded` and `update` might
+            // be more appropriate, especially when this is used in a listener
+            MapAttribute.put(this, SERVER_POOL_TARGETS, member, newAddress);
+            updateAsync();
         }
-        
-        if (Objects.equal(oldAddress, newAddress)) {
-            if (LOG.isTraceEnabled()) LOG.trace("For {}, ignoring change in member {} because address still {}", new Object[] {this, member, newAddress});
-            return;
-        }
-        
-        // TODO this does it synchronously; an async method leaning on `updateNeeded` and `update` might
-        // be more appropriate, especially when this is used in a listener
-        MapAttribute.put(this, SERVER_POOL_TARGETS, member, newAddress);
-        updateAsync();
     }
     
-    protected synchronized void removeServerPoolMember(Entity member) {
-        if (!getAttribute(SERVER_POOL_TARGETS).containsKey(member)) {
-            if (LOG.isTraceEnabled()) LOG.trace("For {}, not removing as don't have member {}", new Object[] {this, member});
-            return;
+    protected void removeServerPoolMember(Entity member) {
+        synchronized (serverPoolAddresses) {
+            if (!getAttribute(SERVER_POOL_TARGETS).containsKey(member)) {
+                if (LOG.isTraceEnabled()) LOG.trace("For {}, not removing as don't have member {}", new Object[] {this, member});
+                return;
+            }
+
+            String address = MapAttribute.remove(this, SERVER_POOL_TARGETS, member);
+
+            LOG.info("Removing from {}, member {} with address {}", new Object[] {this, member, address});
+
+            updateAsync();
         }
-        
-        String address = MapAttribute.remove(this, SERVER_POOL_TARGETS, member);
-        
-        LOG.info("Removing from {}, member {} with address {}", new Object[] {this, member, address});
-        
-        updateAsync();
     }
     
     protected String getAddressOfEntity(Entity member) {