http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java
new file mode 100644
index 0000000..347a212
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java
@@ -0,0 +1,284 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.exceptions;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.base.Throwables.getCausalChain;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.UndeclaredThrowableException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.brooklyn.util.text.Strings;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+public class Exceptions {
+
+    private static final List<Class<? extends Throwable>> 
BORING_THROWABLE_SUPERTYPES = ImmutableList.<Class<? extends Throwable>>of(
+        ExecutionException.class, InvocationTargetException.class, 
PropagatedRuntimeException.class, UndeclaredThrowableException.class);
+
+    private static boolean isBoring(Throwable t) {
+        for (Class<? extends Throwable> type: BORING_THROWABLE_SUPERTYPES)
+            if (type.isInstance(t)) return true;
+        return false;
+    }
+
+    private static final Predicate<Throwable> IS_THROWABLE_BORING = new 
Predicate<Throwable>() {
+        @Override
+        public boolean apply(Throwable input) {
+            return isBoring(input);
+        }
+    };
+
+    private static List<Class<? extends Throwable>> 
BORING_PREFIX_THROWABLE_EXACT_TYPES = ImmutableList.<Class<? extends 
Throwable>>of(
+        IllegalStateException.class, RuntimeException.class, 
CompoundRuntimeException.class);
+
+    /** Returns whether this is throwable either known to be boring or to have 
an unuseful prefix;
+     * null is *not* boring. */
+    public static boolean isPrefixBoring(Throwable t) {
+        if (t==null) return false;
+        if (isBoring(t))
+            return true;
+        for (Class<? extends Throwable> type: 
BORING_PREFIX_THROWABLE_EXACT_TYPES)
+            if (t.getClass().equals(type)) return true;
+        return false;
+    }
+
+    private static String stripBoringPrefixes(String s) {
+        ArrayList<String> prefixes = Lists.newArrayListWithCapacity(2 + 
BORING_PREFIX_THROWABLE_EXACT_TYPES.size() * 3);
+        for (Class<? extends Throwable> type : 
BORING_PREFIX_THROWABLE_EXACT_TYPES) {
+            prefixes.add(type.getCanonicalName());
+            prefixes.add(type.getName());
+            prefixes.add(type.getSimpleName());
+        }
+        prefixes.add(":");
+        prefixes.add(" ");
+        String[] ps = prefixes.toArray(new String[prefixes.size()]);
+        return Strings.removeAllFromStart(s, ps);
+    }
+
+    /**
+     * Propagate a {@link Throwable} as a {@link RuntimeException}.
+     * <p>
+     * Like Guava {@link Throwables#propagate(Throwable)} but:
+     * <li> throws {@link RuntimeInterruptedException} to handle {@link 
InterruptedException}s; and
+     * <li> wraps as PropagatedRuntimeException for easier filtering
+     */
+    public static RuntimeException propagate(Throwable throwable) {
+        if (throwable instanceof InterruptedException)
+            throw new RuntimeInterruptedException((InterruptedException) 
throwable);
+        Throwables.propagateIfPossible(checkNotNull(throwable));
+        throw new PropagatedRuntimeException(throwable);
+    }
+
+    /** 
+     * Propagate exceptions which are fatal.
+     * <p>
+     * Propagates only those exceptions which one rarely (if ever) wants to 
capture,
+     * such as {@link InterruptedException} and {@link Error}s.
+     */
+    public static void propagateIfFatal(Throwable throwable) {
+        if (throwable instanceof InterruptedException)
+            throw new RuntimeInterruptedException((InterruptedException) 
throwable);
+        if (throwable instanceof RuntimeInterruptedException)
+            throw (RuntimeInterruptedException) throwable;
+        if (throwable instanceof Error)
+            throw (Error) throwable;
+    }
+
+    /** returns the first exception of the given type, or null */
+    @SuppressWarnings("unchecked")
+    public static <T extends Throwable> T getFirstThrowableOfType(Throwable 
from, Class<T> clazz) {
+        return (T) Iterables.tryFind(getCausalChain(from), 
instanceOf(clazz)).orNull();
+    }
+
+    /** returns the first exception in the call chain which is not of common 
uninteresting types
+     * (ie excluding ExecutionException and PropagatedRuntimeExceptions); 
+     * or the original throwable if all are uninteresting 
+     */
+    public static Throwable getFirstInteresting(Throwable throwable) {
+        return Iterables.tryFind(getCausalChain(throwable), 
Predicates.not(IS_THROWABLE_BORING)).or(throwable);
+    }
+
+    /** creates (but does not throw) a new {@link PropagatedRuntimeException} 
whose 
+     * message and cause are taken from the first _interesting_ element in the 
source */
+    public static Throwable collapse(Throwable source) {
+        return collapse(source, true);
+    }
+    
+    /** as {@link #collapse(Throwable)} but includes causal messages in the 
message as per {@link #collapseTextIncludingAllCausalMessages(Throwable)};
+     * use with care (limit once) as repeated usage can result in multiple 
copies of the same message */ 
+    public static Throwable collapseIncludingAllCausalMessages(Throwable 
source) {
+        return collapse(source, true, true);
+    }
+    
+    /** creates (but does not throw) a new {@link PropagatedRuntimeException} 
whose 
+     * message is taken from the first _interesting_ element in the source,
+     * and optionally also the causal chain */
+    public static Throwable collapse(Throwable source, boolean 
collapseCausalChain) {
+        return collapse(source, collapseCausalChain, false);
+    }
+    
+    private static Throwable collapse(Throwable source, boolean 
collapseCausalChain, boolean includeAllCausalMessages) {
+        String message = "";
+        Throwable collapsed = source;
+        int collapseCount = 0;
+        boolean messageIsFinal = false;
+        // remove boring stack traces at the head
+        while (isBoring(collapsed)  && !messageIsFinal) {
+            collapseCount++;
+            Throwable cause = collapsed.getCause();
+            if (cause==null)
+                // everything in the tree is boring...
+                return source;
+            String collapsedS = collapsed.getMessage();
+            if (collapsed instanceof PropagatedRuntimeException && 
((PropagatedRuntimeException)collapsed).isCauseEmbeddedInMessage()) {
+                message = collapsed.getMessage();
+                messageIsFinal = true;
+            } else if (Strings.isNonBlank(collapsedS)) {
+                collapsedS = Strings.removeAllFromEnd(collapsedS, 
cause.toString(), stripBoringPrefixes(cause.toString()), cause.getMessage());
+                collapsedS = stripBoringPrefixes(collapsedS);
+                if (Strings.isNonBlank(collapsedS))
+                    message = appendSeparator(message, collapsedS);
+            }
+            collapsed = cause;
+        }
+        // if no messages so far (ie we will be the toString) then remove 
boring prefixes from the message
+        Throwable messagesCause = collapsed;
+        while (messagesCause!=null && isPrefixBoring(messagesCause) && 
Strings.isBlank(message)) {
+            collapseCount++;
+            if (Strings.isNonBlank(messagesCause.getMessage())) {
+                message = messagesCause.getMessage();
+                messagesCause = messagesCause.getCause();
+                break;
+            }
+            messagesCause = messagesCause.getCause();
+        }
+        
+        if (collapseCount==0 && !includeAllCausalMessages)
+            return source;
+        
+        if (collapseCount==0 && messagesCause!=null) {
+            message = messagesCause.toString();
+            messagesCause = messagesCause.getCause();
+        }
+        
+        if (Strings.isBlank(message)) {
+            return new PropagatedRuntimeException(collapseCausalChain ? 
collapsed : source);
+        } else {
+            if (messagesCause!=null && !messageIsFinal) {
+                String extraMessage = collapseText(messagesCause, 
includeAllCausalMessages);
+                message = appendSeparator(message, extraMessage);
+            }
+            return new PropagatedRuntimeException(message, collapseCausalChain 
? collapsed : source, true);
+        }
+    }
+    
+    static String appendSeparator(String message, String next) {
+        if (Strings.isBlank(message))
+            return next;
+        if (Strings.isBlank(next))
+            return message;
+        if (message.endsWith(next))
+            return message;
+        if (message.trim().endsWith(":") || message.trim().endsWith(";"))
+            return message.trim()+" "+next;
+        return message + ": " + next;
+    }
+
+    /** removes uninteresting items from the top of the call stack (but keeps 
interesting messages), and throws 
+     * @deprecated since 0.7.0 same as {@link #propagate(Throwable)} */
+    public static RuntimeException propagateCollapsed(Throwable source) {
+        throw propagate(source);
+    }
+
+    /** like {@link #collapse(Throwable)} but returning a one-line message 
suitable for logging without traces */
+    public static String collapseText(Throwable t) {
+        return collapseText(t, false);
+    }
+
+    /** normally {@link #collapseText(Throwable)} will stop following causal 
chains when encountering an interesting exception
+     * with a message; this variant will continue to follow such causal 
chains, showing all messages. 
+     * for use e.g. when verbose is desired in the single-line message. */
+    public static String collapseTextIncludingAllCausalMessages(Throwable t) {
+        return collapseText(t, true);
+    }
+    
+    private static String collapseText(Throwable t, boolean 
includeAllCausalMessages) {
+        if (t == null) return null;
+        Throwable t2 = collapse(t, true, includeAllCausalMessages);
+        if (t2 instanceof PropagatedRuntimeException) {
+            if (((PropagatedRuntimeException)t2).isCauseEmbeddedInMessage())
+                // normally
+                return t2.getMessage();
+            else if (t2.getCause()!=null)
+                return ""+t2.getCause();
+            return ""+t2.getClass();
+        }
+        String result = t2.toString();
+        if (!includeAllCausalMessages) {
+            return result;
+        }
+        Throwable cause = t2.getCause();
+        if (cause != null) {
+            String causeResult = collapseText(new 
PropagatedRuntimeException(cause));
+            if (result.indexOf(causeResult)>=0)
+                return result;
+            return result + "; caused by "+causeResult;
+        }
+        return result;
+    }
+
+    public static RuntimeException propagate(Collection<? extends Throwable> 
exceptions) {
+        throw propagate(create(exceptions));
+    }
+    public static RuntimeException propagate(String prefix, Collection<? 
extends Throwable> exceptions) {
+        throw propagate(create(prefix, exceptions));
+    }
+
+    /** creates the given exception, but without propagating it, for use when 
caller will be wrapping */
+    public static Throwable create(Collection<? extends Throwable> exceptions) 
{
+        return create(null, exceptions);
+    }
+    /** creates the given exception, but without propagating it, for use when 
caller will be wrapping */
+    public static RuntimeException create(String prefix, Collection<? extends 
Throwable> exceptions) {
+        if (exceptions.size()==1) {
+            Throwable e = exceptions.iterator().next();
+            if (Strings.isBlank(prefix)) return new 
PropagatedRuntimeException(e);
+            return new PropagatedRuntimeException(prefix + ": " + 
Exceptions.collapseText(e), e);
+        }
+        if (exceptions.isEmpty()) {
+            if (Strings.isBlank(prefix)) return new 
CompoundRuntimeException("(empty compound exception)", exceptions);
+            return new CompoundRuntimeException(prefix, exceptions);
+        }
+        if (Strings.isBlank(prefix)) return new 
CompoundRuntimeException(exceptions.size()+" errors, including: " + 
Exceptions.collapseText(exceptions.iterator().next()), exceptions);
+        return new CompoundRuntimeException(prefix+", "+exceptions.size()+" 
errors including: " + Exceptions.collapseText(exceptions.iterator().next()), 
exceptions);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/FatalConfigurationRuntimeException.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/FatalConfigurationRuntimeException.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/FatalConfigurationRuntimeException.java
new file mode 100644
index 0000000..de425ed
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/FatalConfigurationRuntimeException.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.exceptions;
+
+/** As {@link FatalRuntimeException} super, specialized for configuration 
errors. */
+public class FatalConfigurationRuntimeException extends FatalRuntimeException {
+
+    private static final long serialVersionUID = -5361951925760434821L;
+
+    public FatalConfigurationRuntimeException(String message) {
+        super(message);
+    }
+    
+    public FatalConfigurationRuntimeException(String message, Throwable cause) 
{
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/FatalRuntimeException.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/FatalRuntimeException.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/FatalRuntimeException.java
new file mode 100644
index 0000000..6c16497
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/FatalRuntimeException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.exceptions;
+
+/** Exception indicating a fatal error, typically used in CLI routines.
+ * The message supplied here should be suitable for display in a CLI response 
(without stack trace / exception class). */
+public class FatalRuntimeException extends UserFacingException {
+
+    private static final long serialVersionUID = -3359163414517503809L;
+
+    public FatalRuntimeException(String message) {
+        super(message);
+    }
+    
+    public FatalRuntimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/NotManagedException.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/NotManagedException.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/NotManagedException.java
new file mode 100644
index 0000000..3bf4fa0
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/NotManagedException.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.exceptions;
+
+public class NotManagedException extends IllegalStateException {
+
+    private static final long serialVersionUID = -3359163414517503809L;
+
+    public NotManagedException(Object object) {
+        super(object+" is not managed");
+    }
+    
+    public NotManagedException(String message) {
+        super(message);
+    }
+    
+    public NotManagedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/PropagatedRuntimeException.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/PropagatedRuntimeException.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/PropagatedRuntimeException.java
new file mode 100644
index 0000000..1b1aa5a
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/PropagatedRuntimeException.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.exceptions;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Indicates a runtime exception which has been propagated via {@link 
Exceptions#propagate} */
+public class PropagatedRuntimeException extends RuntimeException {
+
+    private static final long serialVersionUID = 3959054308510077172L;
+    private static final Logger LOG = 
LoggerFactory.getLogger(PropagatedRuntimeException.class);
+
+    private final boolean causeEmbeddedInMessage;
+    
+    /** Callers should typically *not* attempt to summarise the cause in the 
message here; use toString() to get extended information */
+    public PropagatedRuntimeException(String message, Throwable cause) {
+        super(message, cause);
+        warnIfWrapping(cause);
+        causeEmbeddedInMessage = 
message.endsWith(Exceptions.collapseText(getCause()));
+    }
+
+    public PropagatedRuntimeException(String message, Throwable cause, boolean 
causeEmbeddedInMessage) {
+        super(message, cause);
+        warnIfWrapping(cause);
+        this.causeEmbeddedInMessage = causeEmbeddedInMessage;
+    }
+
+    public PropagatedRuntimeException(Throwable cause) {
+        super("" /* do not use default message as that destroys the toString 
*/, cause);
+        warnIfWrapping(cause);
+        causeEmbeddedInMessage = false;
+    }
+
+    private void warnIfWrapping(Throwable cause) {
+        if (LOG.isTraceEnabled() && cause instanceof 
PropagatedRuntimeException) {
+            LOG.trace("Wrapping a PropagatedRuntimeException in another 
PropagatedRuntimeException. Call chain:", new Exception());
+        }
+    }
+
+    @Override
+    public String toString() {
+        if (causeEmbeddedInMessage) {
+            return super.toString();
+        } else {
+            return Exceptions.appendSeparator(super.toString(), 
Exceptions.collapseText(getCause()));
+        }
+    }
+
+    public boolean isCauseEmbeddedInMessage() {
+        return causeEmbeddedInMessage;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/ReferenceWithError.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/ReferenceWithError.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/ReferenceWithError.java
new file mode 100644
index 0000000..87fa3f2
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/ReferenceWithError.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.exceptions;
+
+import javax.annotation.Nullable;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Supplier;
+
+/** A reference to an object which can carry an object alongside it. */
+@Beta
+public class ReferenceWithError<T> implements Supplier<T> {
+
+    private final T object;
+    private final Throwable error;
+    private final boolean maskError;
+
+    /** returns a reference which includes an error, and where attempts to get 
the content cause the error to throw */
+    public static <T> ReferenceWithError<T> newInstanceThrowingError(T object, 
Throwable error) {
+        return new ReferenceWithError<T>(object, error, false);
+    }
+    
+    /** returns a reference which includes an error, but attempts to get the 
content do not cause the error to throw */
+    public static <T> ReferenceWithError<T> newInstanceMaskingError(T object, 
Throwable error) {
+        return new ReferenceWithError<T>(object, error, true);
+    }
+    
+    /** returns a reference which includes an error, but attempts to get the 
content do not cause the error to throw */
+    public static <T> ReferenceWithError<T> newInstanceWithoutError(T object) {
+        return new ReferenceWithError<T>(object, null, false);
+    }
+    
+    protected ReferenceWithError(@Nullable T object, @Nullable Throwable 
error, boolean maskError) {
+        this.object = object;
+        this.error = error;
+        this.maskError = maskError;
+    }
+
+    /** whether this will mask any error on an attempt to {@link #get()};
+     * if false (if created with {@link #newInstanceThrowingError(Object, 
Throwable)}) a call to {@link #get()} will throw if there is an error;
+     * true if created with {@link #newInstanceMaskingError(Object, 
Throwable)} and {@link #get()} will not throw */
+    public boolean masksErrorIfPresent() {
+        return maskError;
+    }
+
+    /** returns the underlying value, throwing if there is an error which is 
not masked (ie {@link #throwsErrorOnAccess()} is set) */
+    public T get() {
+        if (masksErrorIfPresent()) {
+            return getWithoutError();
+        }
+        return getWithError();
+    }
+
+    /** returns the object, ignoring any error (even non-masked) */
+    public T getWithoutError() {
+        return object;
+    }
+
+    /** throws error, even if there is one (even if masked), else returns the 
object */
+    public T getWithError() {
+        checkNoError();
+        return object;
+    }
+
+    /** throws if there is an error (even if masked) */
+    public void checkNoError() {
+        if (hasError())
+            Exceptions.propagate(error);
+    }
+
+    /** returns the error (not throwing) */
+    public Throwable getError() {
+        return error;
+    }
+    
+    /** true if there is an error (whether masked or not) */
+    public boolean hasError() {
+        return error!=null;
+    }
+
+    @Override
+    public String toString() {
+        return 
getClass().getSimpleName()+"["+object+(error!=null?"/"+(maskError?"masking:":"throwing:")+error:"")+"]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/RuntimeInterruptedException.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/RuntimeInterruptedException.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/RuntimeInterruptedException.java
new file mode 100644
index 0000000..7ebb581
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/RuntimeInterruptedException.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.exceptions;
+
+/**
+ * A {@link RuntimeException} that is thrown when a Thread is interrupted.
+ * <p>
+ * This exception is useful if a Thread needs to be interrupted, but the 
{@link InterruptedException} can't be thrown
+ * because it is checked.
+ * <p>
+ * When the {@link RuntimeInterruptedException} is created, it will 
automatically set the interrupt status on the calling
+ * thread.
+ *
+ * @author Peter Veentjer.
+ */
+public class RuntimeInterruptedException extends RuntimeException {
+
+    private static final long serialVersionUID = 915050245927866175L;
+
+    public RuntimeInterruptedException(InterruptedException cause) {
+        super(cause);
+        Thread.currentThread().interrupt();
+    }
+
+    public RuntimeInterruptedException(String msg, InterruptedException cause) 
{
+        super(msg, cause);
+        Thread.currentThread().interrupt();
+    }
+
+    @Override
+    public InterruptedException getCause() {
+        return (InterruptedException) super.getCause();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/RuntimeTimeoutException.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/RuntimeTimeoutException.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/RuntimeTimeoutException.java
new file mode 100644
index 0000000..b13e0cf
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/RuntimeTimeoutException.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.exceptions;
+
+public class RuntimeTimeoutException extends IllegalStateException {
+
+    private static final long serialVersionUID = -3359163414517503809L;
+
+    public RuntimeTimeoutException() {
+        super("timeout");
+    }
+    
+    public RuntimeTimeoutException(String message) {
+        super(message);
+    }
+    
+    public RuntimeTimeoutException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/UserFacingException.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/UserFacingException.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/UserFacingException.java
new file mode 100644
index 0000000..34673e6
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/UserFacingException.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.exceptions;
+
+/** marker interface, to show that an exception is suitable for 
pretty-printing to an end-user,
+ * without including a stack trace */
+public class UserFacingException extends RuntimeException {
+
+    private static final long serialVersionUID = 2216885527195571323L;
+
+    public UserFacingException(String message) {
+        super(message);
+    }
+
+    public UserFacingException(Throwable cause) {
+        super(cause.getMessage(), cause);
+    }
+
+    public UserFacingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/git/GithubUrls.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/git/GithubUrls.java 
b/utils/common/src/main/java/org/apache/brooklyn/util/git/GithubUrls.java
new file mode 100644
index 0000000..067bee9
--- /dev/null
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/git/GithubUrls.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.git;
+
+import org.apache.brooklyn.util.net.Urls;
+
+public class GithubUrls {
+
+    public static String BASE_URL = "https://github.com/";;
+    
+    /** returns URL for the root of the given repo */
+    public static String root(String owner, String repo) {
+        return Urls.mergePaths(BASE_URL, owner, repo);
+    }
+    
+    /** returns URL for downloading a .tar.gz version of a tag of a repository 
*/
+    public static String tgz(String owner, String repo, String tag) {
+        return Urls.mergePaths(root(owner, repo), "archive", tag+".tar.gz");
+    }
+
+    /** returns URL for downloading a .zip version of a tag of a repository */
+    public static String zip(String owner, String repo, String tag) {
+        return Urls.mergePaths(root(owner, repo), "archive", tag+".zip");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/guava/Functionals.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Functionals.java 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Functionals.java
new file mode 100644
index 0000000..4a9a8c4
--- /dev/null
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Functionals.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.guava;
+
+import java.util.concurrent.Callable;
+
+import 
org.apache.brooklyn.util.guava.IfFunctions.IfFunctionBuilderApplyingFirst;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+
+public class Functionals {
+
+    /** applies f1 to the input, then the result of that is passed to f2 (note 
opposite semantics to {@link Functions#compose(Function, Function)} */ 
+    public static <A,B,C> Function<A,C> chain(final Function<A,? extends B> 
f1, final Function<B,C> f2) {
+        return Functions.compose(f2, f1);
+    }
+    
+    /** applies f1 to the input, then f2 to that result, then f3 to that 
result */
+    public static <A,B,C,D> Function<A,D> chain(final Function<A,? extends B> 
f1, final Function<B,? extends C> f2, final Function<C,D> f3) {
+        return chain(f1, chain(f2, f3));
+    }
+    
+    /** applies f1 to the input, then f2 to that result, then f3 to that 
result, then f4 to that result */
+    public static <A,B,C,D,E> Function<A,E> chain(final Function<A,? extends 
B> f1, final Function<B,? extends C> f2, final Function<C,? extends D> f3, 
final Function<D,E> f4) {
+        return chain(f1, chain(f2, chain(f3, f4)));
+    }
+
+    /** @see IfFunctions */
+    public static <I> IfFunctionBuilderApplyingFirst<I> ifEquals(I test) {
+        return IfFunctions.ifEquals(test);
+    }
+
+    /** @see IfFunctions */
+    public static <I> IfFunctionBuilderApplyingFirst<I> ifNotEquals(I test) {
+        return IfFunctions.ifNotEquals(test);
+    }
+    
+    /** @see IfFunctions */
+    public static <I> IfFunctionBuilderApplyingFirst<I> 
ifPredicate(Predicate<I> test) {
+        return IfFunctions.ifPredicate(test);
+    }
+
+    /** like guava equivalent but parametrises the input generic type, and 
allows tostring to be customised */
+    public static final class ConstantFunction<I, O> implements Function<I, O> 
{
+        private final O constant;
+        private Object toStringDescription;
+
+        public ConstantFunction(O constant) {
+            this(constant, null);
+        }
+        public ConstantFunction(O constant, Object toStringDescription) {
+            this.constant = constant;
+            this.toStringDescription = toStringDescription;
+        }
+
+        @Override
+        public O apply(I input) {
+            return constant;
+        }
+        
+        @Override
+        public String toString() {
+            return toStringDescription==null ? "constant("+constant+")" : 
toStringDescription.toString();
+        }
+    }
+
+    /** like guava {@link Functions#forSupplier(Supplier)} but parametrises 
the input generic type */
+    public static <I,O> Function<I,O> function(final Supplier<O> supplier) {
+        class SupplierAsFunction implements Function<I,O> {
+            @Override public O apply(I input) {
+                return supplier.get();
+            }
+            @Override public String toString() {
+                return "function("+supplier+")";
+            }
+        }
+        return new SupplierAsFunction();
+    }
+
+    public static <I> Function<I,Void> function(final Runnable runnable) {
+        class RunnableAsFunction implements Function<I,Void> {
+            @Override public Void apply(I input) {
+                runnable.run();
+                return null;
+            }
+        }
+        return new RunnableAsFunction();
+    }
+
+    public static Runnable runnable(final Supplier<?> supplier) {
+        class SupplierAsRunnable implements Runnable {
+            @Override
+            public void run() {
+                supplier.get();
+            }
+        }
+        return new SupplierAsRunnable();
+    }
+
+    public static <T> Callable<T> callable(final Supplier<T> supplier) {
+        class SupplierAsCallable implements Callable<T> {
+            @Override
+            public T call() {
+                return supplier.get();
+            }
+            @Override
+            public String toString() {
+                return "callable("+supplier+")";
+            }
+        }
+        return new SupplierAsCallable();
+    }
+    public static <T,U> Callable<U> callable(Function<T,U> f, T x) {
+        return callable(Suppliers.compose(f, Suppliers.ofInstance(x)));
+    }
+
+    public static <T> Predicate<T> predicate(final Function<T,Boolean> f) {
+        class FunctionAsPredicate implements Predicate<T> {
+            @Override
+            public boolean apply(T input) {
+                return f.apply(input);
+            }
+            @Override
+            public String toString() {
+                return "predicate("+f+")";
+            }
+        }
+        return new FunctionAsPredicate();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/guava/IfFunctions.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/guava/IfFunctions.java 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/IfFunctions.java
new file mode 100644
index 0000000..440c7e5
--- /dev/null
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/IfFunctions.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.guava;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+
+/** Utilities for building {@link Function} instances which return specific 
values
+ * (or {@link Supplier} or {@link Function} instances) when certain predicates 
are satisfied,
+ * tested in order and returning the first matching,
+ * with support for an "else" default value if none are satisfied (null by 
default). */
+public class IfFunctions {
+
+    public static <I,O> IfFunctionBuilder<I,O> newInstance(Class<I> testType, 
Class<O> returnType) {
+        return new IfFunctionBuilder<I,O>();
+    }
+    
+    public static <I> IfFunctionBuilderApplyingFirst<I> 
ifPredicate(Predicate<? super I> test) {
+        return new IfFunctionBuilderApplyingFirst<I>(test);
+    }
+    public static <I> IfFunctionBuilderApplyingFirst<I> ifEquals(I test) {
+        return ifPredicate(Predicates.equalTo(test));
+    }
+    public static <I> IfFunctionBuilderApplyingFirst<I> ifNotEquals(I test) {
+        return ifPredicate(Predicates.not(Predicates.equalTo(test)));
+    }
+    
+    @Beta
+    public static class IfFunction<I,O> implements Function<I,O> {
+        protected final Map<Predicate<? super I>,Function<? super I,? extends 
O>> tests = new LinkedHashMap<Predicate<? super I>,Function<? super I,? extends 
O>>();
+        protected Function<? super I,? extends O> defaultFunction = null;
+        
+        protected IfFunction(IfFunction<I,O> input) {
+            this.tests.putAll(input.tests);
+            this.defaultFunction = input.defaultFunction;
+        }
+
+        protected IfFunction() {
+        }
+        
+        @Override
+        public O apply(I input) {
+            for (Map.Entry<Predicate<? super I>,Function<? super I,? extends 
O>> test: tests.entrySet()) {
+                if (test.getKey().apply(input)) 
+                    return test.getValue().apply(input);
+            }
+            return defaultFunction==null ? null : defaultFunction.apply(input);
+        }
+        
+        @Override
+        public String toString() {
+            return "if["+tests+"]"+(defaultFunction!=null ? 
"-else["+defaultFunction+"]" : "");
+        }
+    }
+    
+    @Beta
+    public static class IfFunctionBuilder<I,O> extends IfFunction<I,O> {
+        protected IfFunctionBuilder() { super(); }
+        protected IfFunctionBuilder(IfFunction<I,O> input) { super(input); }
+        
+        public IfFunction<I,O> build() {
+            return new IfFunction<I,O>(this);
+        }
+        
+        public IfFunctionBuilderApplying<I,O> ifPredicate(Predicate<I> test) {
+            return new IfFunctionBuilderApplying<I,O>(this, 
(Predicate<I>)test);
+        }
+        public IfFunctionBuilderApplying<I,O> ifEquals(I test) {
+            return ifPredicate(Predicates.equalTo(test));
+        }
+        public IfFunctionBuilderApplying<I,O> ifNotEquals(I test) {
+            return ifPredicate(Predicates.not(Predicates.equalTo(test)));
+        }
+
+        public IfFunctionBuilder<I,O> defaultValue(O defaultValue) {
+            return defaultApply(new 
Functionals.ConstantFunction<I,O>(defaultValue, defaultValue));
+        }
+        @SuppressWarnings("unchecked")
+        public IfFunctionBuilder<I,O> defaultGet(Supplier<? extends O> 
defaultSupplier) {
+            return 
defaultApply((Function<I,O>)Functions.forSupplier(defaultSupplier));
+        }
+        public IfFunctionBuilder<I,O> defaultApply(Function<? super I,? 
extends O> defaultFunction) {
+            IfFunctionBuilder<I, O> result = new IfFunctionBuilder<I,O>(this);
+            result.defaultFunction = defaultFunction;
+            return result;
+        }
+    }
+
+    @Beta
+    public static class IfFunctionBuilderApplying<I,O> {
+        private IfFunction<I, O> input;
+        private Predicate<? super I> test;
+        
+        private IfFunctionBuilderApplying(IfFunction<I,O> input, Predicate<? 
super I> test) {
+            this.input = input;
+            this.test = test;
+        }
+        
+        public IfFunctionBuilder<I,O> value(O value) {
+            return apply(new Functionals.ConstantFunction<I,O>(value, value));
+        }
+        @SuppressWarnings("unchecked")
+        public IfFunctionBuilder<I,O> get(Supplier<? extends O> supplier) {
+            return apply((Function<I,O>)Functions.forSupplier(supplier));
+        }
+        public IfFunctionBuilder<I,O> apply(Function<? super I,? extends O> 
function) {
+            IfFunctionBuilder<I, O> result = new IfFunctionBuilder<I,O>(input);
+            result.tests.put(test, function);
+            return result;
+        }
+    }
+
+    @Beta
+    public static class IfFunctionBuilderApplyingFirst<I> {
+        private Predicate<? super I> test;
+        
+        private IfFunctionBuilderApplyingFirst(Predicate<? super I> test) {
+            this.test = test;
+        }
+        
+        public <O> IfFunctionBuilder<I,O> value(O value) {
+            return apply(new Functionals.ConstantFunction<I,O>(value, value));
+        }
+        @SuppressWarnings("unchecked")
+        public <O> IfFunctionBuilder<I,O> get(Supplier<? extends O> supplier) {
+            return apply((Function<I,O>)Functions.forSupplier(supplier));
+        }
+        public <O> IfFunctionBuilder<I,O> apply(Function<? super I,? extends 
O> function) {
+            IfFunctionBuilder<I, O> result = new IfFunctionBuilder<I,O>();
+            result.tests.put(test, function);
+            return result;
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/guava/IllegalStateExceptionSupplier.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/guava/IllegalStateExceptionSupplier.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/IllegalStateExceptionSupplier.java
new file mode 100644
index 0000000..deaba53
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/IllegalStateExceptionSupplier.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.guava;
+
+import com.google.common.base.Supplier;
+
+public class IllegalStateExceptionSupplier implements 
Supplier<RuntimeException> {
+
+    public static final IllegalStateExceptionSupplier EMPTY_EXCEPTION = new 
IllegalStateExceptionSupplier();
+    
+    protected final String message;
+    protected final Throwable cause;
+    
+    public IllegalStateExceptionSupplier() { this(null, null); }
+    public IllegalStateExceptionSupplier(String message) { this(message, 
null); }
+    public IllegalStateExceptionSupplier(Throwable cause) { this(cause!=null ? 
cause.getMessage() : null, cause); }
+    public IllegalStateExceptionSupplier(String message, Throwable cause) { 
+        this.message = message;
+        this.cause = cause;
+    }
+    
+    @Override
+    public RuntimeException get() {
+        return new IllegalStateException(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/guava/KeyTransformingLoadingCache.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/guava/KeyTransformingLoadingCache.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/KeyTransformingLoadingCache.java
new file mode 100644
index 0000000..fa20fd9
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/KeyTransformingLoadingCache.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.guava;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutionException;
+
+import com.google.common.base.Function;
+import com.google.common.cache.AbstractLoadingCache;
+import com.google.common.cache.CacheStats;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * A cache that transforms its keys before deferring to a delegate {@link 
LoadingCache}.
+ */
+// Concise names welcome.
+public class KeyTransformingLoadingCache<A, B, V> extends 
AbstractLoadingCache<A, V> {
+
+    private final LoadingCache<B, V> delegate;
+    private final Function<A, B> keyTransformer;
+
+    public KeyTransformingLoadingCache(LoadingCache<B, V> delegate, 
Function<A, B> keyTransformer) {
+        this.delegate = delegate;
+        this.keyTransformer = keyTransformer;
+    }
+
+    public static <A, B, V> KeyTransformingLoadingCache<A, B, V> 
from(LoadingCache<B, V> delegate, Function<A, B> keyTransformer) {
+        return new KeyTransformingLoadingCache<A, B, V>(delegate, 
keyTransformer);
+    }
+
+    protected Function<A, B> keyTransformer() {
+        return keyTransformer;
+    }
+
+    protected LoadingCache<B, V> delegate() {
+        return delegate;
+    }
+
+    @Override
+    public V getIfPresent(Object key) {
+        try {
+            @SuppressWarnings("unchecked")
+            A cast = (A) key;
+            return delegate().getIfPresent(keyTransformer().apply(cast));
+        } catch (ClassCastException e) {
+            return null;
+        }
+    }
+
+    @Override
+    public V get(A key, Callable<? extends V> valueLoader) throws 
ExecutionException {
+        return delegate().get(keyTransformer().apply(key), valueLoader);
+    }
+
+    /**
+     * Undefined because we can't prohibit a surjective {@link 
#keyTransformer()}.
+     * @throws UnsupportedOperationException
+     */
+    @Override
+    public ImmutableMap<A, V> getAllPresent(Iterable<?> keys) {
+        throw new UnsupportedOperationException("getAllPresent in 
"+getClass().getName() + " undefined");
+    }
+
+    @Override
+    public void put(A key, V value) {
+        delegate().put(keyTransformer().apply(key), value);
+    }
+
+    @Override
+    public void invalidate(Object key) {
+        try {
+            @SuppressWarnings("unchecked")
+            A cast = (A) key;
+            delegate().invalidate(keyTransformer().apply(cast));
+        } catch (ClassCastException e) {
+            // Ignore
+        }
+    }
+
+    @Override
+    public void invalidateAll() {
+        delegate().invalidateAll();
+    }
+
+    @Override
+    public long size() {
+        return delegate().size();
+    }
+
+    @Override
+    public CacheStats stats() {
+        return delegate().stats();
+    }
+
+    @Override
+    public V get(A key) throws ExecutionException {
+        return delegate().get(keyTransformer().apply(key));
+    }
+
+    @Override
+    public void refresh(A key) {
+        delegate().refresh(keyTransformer().apply(key));
+    }
+
+    /**
+     * Undefined because input values are not tracked.
+     * @throws UnsupportedOperationException
+     */
+    @Override
+    public ConcurrentMap<A, V> asMap() {
+        throw new UnsupportedOperationException("asMap in " + 
getClass().getName() + " undefined");
+    }
+
+    @Override
+    public void cleanUp() {
+        delegate().cleanUp();
+    }
+
+    // Users can avoid middle type parameter.
+    public static class KeyTransformingSameTypeLoadingCache<A, V> extends 
KeyTransformingLoadingCache<A, A, V> {
+        public KeyTransformingSameTypeLoadingCache(LoadingCache<A, V> 
delegate, Function<A, A> keyTransformer) {
+            super(delegate, keyTransformer);
+        }
+
+        // IDE note: This was named `from` to be consistent with 
KeyTransformingLoadingCache but Intellij 13
+        // claims a name clash with the superclass `from`:
+        // java: name clash: <A,V>from(LoadingCache<A,V>, Function<A,A>) in 
KeyTransformingSameTypeLoadingCache
+        // and <A,B,V>from(LoadingCache<B,V>, Function<A,B>) in 
KeyTransformingLoadingCache have the same erasure,
+        // yet neither hides the other
+        public static <A, V> KeyTransformingSameTypeLoadingCache<A, V> 
with(LoadingCache<A, V> delegate, Function<A, A> keyTransformer) {
+            return new KeyTransformingSameTypeLoadingCache<A, V>(delegate, 
keyTransformer);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
new file mode 100644
index 0000000..2264362
--- /dev/null
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java
@@ -0,0 +1,296 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.guava;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.Serializable;
+import java.lang.ref.SoftReference;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.util.javalang.JavaClassNames;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.ImmutableSet;
+
+/** Like Guava Optional but permitting null and permitting errors to be 
thrown. */
+public abstract class Maybe<T> implements Serializable, Supplier<T> {
+
+    private static final long serialVersionUID = -6372099069863179019L;
+
+    public static <T> Maybe<T> absent() {
+        return new Absent<T>();
+    }
+
+    /** Creates an absent whose get throws an {@link IllegalStateException} 
with the indicated message.
+     * Both stack traces (the cause and the callers) are provided, which can 
be quite handy. */
+    public static <T> Maybe<T> absent(final String message) {
+        return absent(new IllegalStateExceptionSupplier(message));
+    }
+
+    /** Creates an absent whose get throws an {@link IllegalStateException} 
with the indicated cause.
+     * Both stack traces (the cause and the callers) are provided, which can 
be quite handy. */
+    public static <T> Maybe<T> absent(final Throwable cause) {
+        return absent(new IllegalStateExceptionSupplier(cause));
+    }
+    
+    /** Creates an absent whose get throws an {@link IllegalStateException} 
with the indicated message and underlying cause.
+     * Both stack traces (the cause and the callers) are provided, which can 
be quite handy. */
+    public static <T> Maybe<T> absent(final String message, final Throwable 
cause) {
+        return absent(new IllegalStateExceptionSupplier(message, cause));
+    }
+    
+    /** Creates an absent whose get throws an {@link RuntimeException} 
generated on demand from the given supplier */
+    public static <T> Maybe<T> absent(final Supplier<? extends 
RuntimeException> exceptionSupplier) {
+        return new Absent<T>(Preconditions.checkNotNull(exceptionSupplier));
+    }
+    
+    public static <T> Maybe<T> of(@Nullable T value) {
+        return new Present<T>(value);
+    }
+
+    /** creates an instance wrapping a {@link SoftReference}, so it might go 
absent later on */
+    public static <T> Maybe<T> soft(T value) {
+        return softThen(value, null);
+    }
+    /** creates an instance wrapping a {@link SoftReference}, using the second 
item given if lost */
+    public static <T> Maybe<T> softThen(T value, Maybe<T> ifEmpty) {
+        if (value==null) return of((T)null);
+        return new SoftlyPresent<T>(value).usingAfterExpiry(ifEmpty);
+    }
+
+    /** like {@link Optional#fromNullable(Object)}, returns absent if the 
argument is null */
+    public static <T> Maybe<T> fromNullable(@Nullable T value) {
+        if (value==null) return absent();
+        return new Present<T>(value);
+    }
+
+    public static <T> Maybe<T> of(final Optional<T> value) {
+        if (value.isPresent()) return new AbstractPresent<T>() {
+            private static final long serialVersionUID = -5735268814211401356L;
+            @Override
+            public T get() {
+                return value.get();
+            }
+        };
+        return absent();
+    }
+    
+    public static <T> Maybe<T> of(final Supplier<T> value) {
+        return new AbstractPresent<T>() {
+            private static final long serialVersionUID = -5735268814211401356L;
+            @Override
+            public T get() {
+                return value.get();
+            }
+        };
+    }
+    
+    /** returns a Maybe containing the next element in the iterator, or absent 
if none */ 
+    public static <T> Maybe<T> next(Iterator<T> iterator) {
+        return iterator.hasNext() ? Maybe.of(iterator.next()) : 
Maybe.<T>absent();
+    }
+
+    public abstract boolean isPresent();
+    public abstract T get();
+    
+    public boolean isAbsent() {
+        return !isPresent(); 
+    }
+    public boolean isAbsentOrNull() {
+        return !isPresentAndNonNull();
+    }
+    public boolean isPresentAndNonNull() {
+        return isPresent() && get()!=null;
+    }
+    
+    public T or(T nextValue) {
+        if (isPresent()) return get();
+        return nextValue;
+    }
+
+    public Maybe<T> or(Maybe<T> nextValue) {
+        if (isPresent()) return this;
+        return nextValue;
+    }
+
+    public T or(Supplier<T> nextValue) {
+        if (isPresent()) return get();
+        return nextValue.get();
+    }
+
+    public T orNull() {
+        if (isPresent()) return get();
+        return null;
+    }
+    
+    public Set<T> asSet() {
+        if (isPresent()) return ImmutableSet.of(get());
+        return Collections.emptySet();
+    }
+    
+    public <V> Maybe<V> transform(final Function<? super T, V> f) {
+        if (isPresent()) return new AbstractPresent<V>() {
+            private static final long serialVersionUID = 325089324325L;
+            public V get() {
+                return f.apply(Maybe.this.get());
+            }
+        };
+        return absent();
+    }
+
+    /**
+     * Returns the value of each present instance from the supplied {@code 
maybes}, in order,
+     * skipping over occurrences of {@link Maybe#absent()}. Iterators are 
unmodifiable and are
+     * evaluated lazily.
+     *
+     * @see Optional#presentInstances(Iterable)
+     */
+    @Beta
+    public static <T> Iterable<T> presentInstances(final Iterable<? extends 
Maybe<? extends T>> maybes) {
+        checkNotNull(maybes);
+        return new Iterable<T>() {
+            @Override
+            public Iterator<T> iterator() {
+                return new AbstractIterator<T>() {
+                    private final Iterator<? extends Maybe<? extends T>> 
iterator = checkNotNull(maybes.iterator());
+
+                    @Override
+                    protected T computeNext() {
+                        while (iterator.hasNext()) {
+                            Maybe<? extends T> maybe = iterator.next();
+                            if (maybe.isPresent()) { return maybe.get(); }
+                        }
+                        return endOfData();
+                    }
+                };
+            }
+        };
+    }
+    
+    public static class Absent<T> extends Maybe<T> {
+        private static final long serialVersionUID = -757170462010887057L;
+        private final Supplier<? extends RuntimeException> exception;
+        public Absent() {
+            this(IllegalStateExceptionSupplier.EMPTY_EXCEPTION);
+        }
+        public Absent(Supplier<? extends RuntimeException> exception) {
+            this.exception = exception;
+        }
+        @Override
+        public boolean isPresent() {
+            return false;
+        }
+        @Override
+        public T get() {
+            throw getException();
+        }
+        public RuntimeException getException() {
+            return exception.get();
+        }
+    }
+
+    public static abstract class AbstractPresent<T> extends Maybe<T> {
+        private static final long serialVersionUID = -2266743425340870492L;
+        protected AbstractPresent() {
+        }
+        @Override
+        public boolean isPresent() {
+            return true;
+        }
+    }
+
+    public static class Present<T> extends AbstractPresent<T> {
+        private static final long serialVersionUID = 436799990500336015L;
+        private final T value;
+        protected Present(T value) {
+            this.value = value;
+        }
+        @Override
+        public T get() {
+            return value;
+        }
+    }
+
+    public static class SoftlyPresent<T> extends Maybe<T> {
+        private static final long serialVersionUID = 436799990500336015L;
+        private final SoftReference<T> value;
+        private Maybe<T> defaultValue;
+        protected SoftlyPresent(@Nonnull T value) {
+            this.value = new SoftReference<T>(value);
+        }
+        @Override
+        public T get() {
+            T result = value.get();
+            if (result!=null) return result;
+            if (defaultValue==null) throw new IllegalStateException("Softly 
present item has been GC'd");
+            return defaultValue.get();
+        }
+        @Override
+        public T orNull() {
+            T result = value.get();
+            if (result!=null) return result;
+            if (defaultValue==null) return null;
+            return defaultValue.orNull();
+        }
+        @Override
+        public boolean isPresent() {
+            return value.get()!=null || (defaultValue!=null && 
defaultValue.isPresent()); 
+        }
+        public Maybe<T> solidify() {
+            return Maybe.fromNullable(value.get());
+        }
+        SoftlyPresent<T> usingAfterExpiry(Maybe<T> defaultValue) {
+            this.defaultValue = defaultValue;
+            return this;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return 
JavaClassNames.simpleClassName(this)+"["+(isPresent()?"value="+get():"")+"]";
+    }
+
+    @Override
+    public int hashCode() {
+        if (!isPresent()) return Objects.hashCode(31, isPresent());
+        return Objects.hashCode(31, get());
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof Maybe)) return false;
+        Maybe<?> other = (Maybe<?>)obj;
+        if (!isPresent()) 
+            return !other.isPresent();
+        return Objects.equal(get(), other.get());
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/guava/MaybeFunctions.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/guava/MaybeFunctions.java 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/MaybeFunctions.java
new file mode 100644
index 0000000..905135c
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/MaybeFunctions.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.guava;
+
+import com.google.common.base.Function;
+
+public class MaybeFunctions {
+
+    public static <T> Function<T, Maybe<T>> wrap() {
+        return new Function<T, Maybe<T>>() {
+            @Override
+            public Maybe<T> apply(T input) {
+                return Maybe.fromNullable(input);
+            }
+        };
+    }
+
+    public static <T> Function<Maybe<T>, T> get() {
+        return new Function<Maybe<T>, T>() {
+            @Override
+            public T apply(Maybe<T> input) {
+                return input.get();
+            }
+        };
+    }
+
+    public static <T> Function<Maybe<T>, T> or(final T value) {
+        return new Function<Maybe<T>, T>() {
+            @Override
+            public T apply(Maybe<T> input) {
+                return input.or(value);
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/guava/SerializablePredicate.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/guava/SerializablePredicate.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/SerializablePredicate.java
new file mode 100644
index 0000000..737809f
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/SerializablePredicate.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.guava;
+
+import java.io.Serializable;
+
+import com.google.common.base.Predicate;
+
+public interface SerializablePredicate<T> extends Predicate<T>, Serializable {
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/guava/TypeTokens.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/guava/TypeTokens.java 
b/utils/common/src/main/java/org/apache/brooklyn/util/guava/TypeTokens.java
new file mode 100644
index 0000000..b37ea33
--- /dev/null
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/TypeTokens.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.guava;
+
+import javax.annotation.Nullable;
+
+import com.google.common.reflect.TypeToken;
+
+public class TypeTokens {
+
+    /** returns raw type, if it's raw, else null;
+     * used e.g. to set only one of the raw type or the type token,
+     * for instance to make serialized output nicer */
+    @Nullable
+    public static <T> Class<? super T> getRawTypeIfRaw(@Nullable TypeToken<T> 
type) {
+        if (type==null || !type.equals(TypeToken.of(type.getRawType()))) {
+            return null;
+        } else {
+            return type.getRawType();
+        }
+    }
+    
+    /** returns null if it's raw, else the type token */
+    @Nullable
+    public static <T> TypeToken<T> getTypeTokenIfNotRaw(@Nullable TypeToken<T> 
type) {
+        if (type==null || type.equals(TypeToken.of(type.getRawType()))) {
+            return null;
+        } else {
+            return type;
+        }
+    }
+    
+    /** given either a token or a raw type, returns the raw type */
+    public static <T> Class<? super T> getRawType(TypeToken<T> token, Class<? 
super T> raw) {
+        if (raw!=null) return raw;
+        if (token!=null) return token.getRawType();
+        throw new IllegalStateException("Both indicators of type are null");
+    }
+    
+    
+    /** given either a token or a raw type, returns the token */
+    @SuppressWarnings("unchecked")
+    public static <T> TypeToken<T> getTypeToken(TypeToken<T> token, Class<? 
super T> raw) {
+        if (token!=null) return token;
+        if (raw!=null) return TypeToken.of((Class<T>)raw);
+        throw new IllegalStateException("Both indicators of type are null");
+    }
+
+    /** gets the Class<T> object from a token; normal methods return Class<? 
super T> which may technically be correct 
+     * with generics but this sloppily but handily gives you Class<T> which is 
usually what you have anyway */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public static <T> Class<T> getRawRawType(TypeToken<T> token) {
+        return (Class)token.getRawType();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/internal/BasicDelegatingSystemProperty.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/internal/BasicDelegatingSystemProperty.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/BasicDelegatingSystemProperty.java
new file mode 100644
index 0000000..faa97ae
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/BasicDelegatingSystemProperty.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.internal;
+
+public class BasicDelegatingSystemProperty {
+    protected final StringSystemProperty delegate;
+
+    public BasicDelegatingSystemProperty(String name) {
+        delegate = new StringSystemProperty(name);
+    }
+    public String getPropertyName() {
+        return delegate.getPropertyName();
+    }
+    public boolean isAvailable() {
+        return delegate.isAvailable();
+    }
+    public String toString() {
+        return delegate.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/internal/BooleanSystemProperty.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/internal/BooleanSystemProperty.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/BooleanSystemProperty.java
new file mode 100644
index 0000000..6738aa1
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/BooleanSystemProperty.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.internal;
+
+public class BooleanSystemProperty extends BasicDelegatingSystemProperty {
+    public BooleanSystemProperty(String name) {
+        super(name);
+    }
+    public boolean isEnabled() {
+        // actually access system property!
+        return Boolean.getBoolean(getPropertyName());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/internal/BrooklynSystemProperties.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/internal/BrooklynSystemProperties.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/BrooklynSystemProperties.java
new file mode 100644
index 0000000..06b5a3b
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/BrooklynSystemProperties.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.internal;
+
+/** 
+ * Convenience for retrieving well-defined system properties, including 
checking if they have been set etc.
+ */
+public class BrooklynSystemProperties {
+
+    // TODO should these become ConfigKeys ?
+    
+    public static BooleanSystemProperty DEBUG = new 
BooleanSystemProperty("brooklyn.debug");
+    public static BooleanSystemProperty EXPERIMENTAL = new 
BooleanSystemProperty("brooklyn.experimental");
+    
+    /** controls how long jsch delays between commands it issues */
+    // -Dbrooklyn.jsch.exec.delay=100
+    public static IntegerSystemProperty JSCH_EXEC_DELAY = new 
IntegerSystemProperty("brooklyn.jsch.exec.delay");
+
+    /** allows specifying a particular geo lookup service (to lookup IP 
addresses), as the class FQN to use */
+    // 
-Dbrooklyn.location.geo.HostGeoLookup=brooklyn.location.geo.UtraceHostGeoLookup
+    public static StringSystemProperty HOST_GEO_LOOKUP_IMPL = new 
StringSystemProperty("brooklyn.location.geo.HostGeoLookup");
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/internal/DoubleSystemProperty.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/internal/DoubleSystemProperty.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/DoubleSystemProperty.java
new file mode 100644
index 0000000..6ee2c67
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/DoubleSystemProperty.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.internal;
+
+public class DoubleSystemProperty extends BasicDelegatingSystemProperty {
+    public DoubleSystemProperty(String name) {
+        super(name);
+    }
+    public double getValue() {
+        return Double.parseDouble(delegate.getValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/internal/IntegerSystemProperty.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/internal/IntegerSystemProperty.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/IntegerSystemProperty.java
new file mode 100644
index 0000000..db627ac
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/IntegerSystemProperty.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.internal;
+
+public class IntegerSystemProperty extends BasicDelegatingSystemProperty {
+    public IntegerSystemProperty(String name) {
+        super(name);
+    }
+    public int getValue() {
+        return Integer.parseInt(delegate.getValue());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/org/apache/brooklyn/util/internal/StringSystemProperty.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/org/apache/brooklyn/util/internal/StringSystemProperty.java
 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/StringSystemProperty.java
new file mode 100644
index 0000000..0f24580
--- /dev/null
+++ 
b/utils/common/src/main/java/org/apache/brooklyn/util/internal/StringSystemProperty.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.util.internal;
+
+public class StringSystemProperty {
+
+    // TODO replace usages of this and related items with ConfigKeys
+    
+    public StringSystemProperty(String name) {
+        this.propertyName = name;
+    }
+
+    private final String propertyName;
+
+    public String getPropertyName() {
+        return propertyName;
+    }
+
+    public boolean isAvailable() {
+        String property = System.getProperty(getPropertyName());
+        return property!=null;
+    }
+    public boolean isNonEmpty() {
+        String property = System.getProperty(getPropertyName());
+        return property!=null && !property.equals("");
+    }
+    public String getValue() {
+        return System.getProperty(getPropertyName());
+    }
+    @Override
+    public String toString() {
+        return getPropertyName()+(isAvailable()?"="+getValue():"(unset)");
+    }
+}


Reply via email to