You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sv...@apache.org on 2016/07/06 12:33:16 UTC

[4/5] brooklyn-server git commit: Centralize class loading and implement fallback bundle scanning

Centralize class loading and implement fallback bundle scanning


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

Branch: refs/heads/master
Commit: f31547645060e69bcdc1b96882d0040e9a266333
Parents: 1ecd7fe
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Tue Jul 5 21:00:53 2016 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Wed Jul 6 15:28:57 2016 +0300

----------------------------------------------------------------------
 .../spi/dsl/methods/BrooklynDslCommon.java      |  10 +-
 .../brooklyn/core/effector/AddSensor.java       |  15 +-
 .../drivers/ReflectiveEntityDriverFactory.java  |   5 +-
 .../brooklyn/core/location/geo/HostGeoInfo.java |   3 +-
 .../JavaBrooklynClassLoadingContext.java        |  18 +-
 .../core/mgmt/entitlement/Entitlements.java     |   8 +-
 .../internal/AbstractManagementContext.java     |   3 +-
 .../transformer/CompoundTransformerLoader.java  |   3 +-
 .../brooklyn/core/objs/BrooklynTypes.java       |   5 +-
 .../core/sensor/DurationSinceSensor.java        |   7 +-
 .../core/sensor/ssh/SshCommandSensor.java       |   2 +-
 .../location/byon/ByonLocationResolver.java     |   4 +-
 .../location/ssh/SshMachineLocation.java        |   3 +-
 .../brooklyn/util/core/ClassLoaderUtils.java    | 249 +++++++++++++++++++
 .../brooklyn/util/core/flags/TypeCoercions.java |   9 +-
 .../objs/BasicSpecParameterFromClassTest.java   |   5 +-
 .../brooklyn/rest/resources/PolicyResource.java |   7 +-
 .../provider/DelegatingSecurityProvider.java    |  10 +-
 .../HardcodedCatalogEntitySpecResolver.java     |  59 +++--
 .../location/winrm/WinRmMachineLocation.java    |  11 +-
 20 files changed, 366 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
index b1db078..a67d89e 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
@@ -45,6 +45,7 @@ import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.ClassCoercionException;
 import org.apache.brooklyn.util.core.flags.FlagUtils;
@@ -129,9 +130,10 @@ public class BrooklynDslCommon {
     @SuppressWarnings({ "unchecked", "rawtypes" })
     public static Sensor<?> sensor(String clazzName, String sensorName) {
         try {
-            // TODO Should use catalog's classloader, rather than Class.forName; how to get that? Should we return a future?!
+            // TODO Should use catalog's classloader, rather than ClassLoaderUtils; how to get that? Should we return a future?!
+            //      Should have the catalog's loader at this point in a thread local
             String mappedClazzName = DeserializingClassRenamesProvider.findMappedName(clazzName);
-            Class<?> clazz = Class.forName(mappedClazzName);
+            Class<?> clazz = new ClassLoaderUtils(BrooklynDslCommon.class).loadClass(mappedClazzName);
             
             Sensor<?> sensor;
             if (Entity.class.isAssignableFrom(clazz)) {
@@ -170,9 +172,9 @@ public class BrooklynDslCommon {
         Map<String,Object> objectFields = (Map<String, Object>) config.getStringKeyMaybe("object.fields").or(MutableMap.of());
         Map<String,Object> brooklynConfig = (Map<String, Object>) config.getStringKeyMaybe(BrooklynCampReservedKeys.BROOKLYN_CONFIG).or(MutableMap.of());
         try {
-            // TODO Should use catalog's classloader, rather than Class.forName; how to get that? Should we return a future?!
+            // TODO Should use catalog's classloader, rather than ClassLoaderUtils; how to get that? Should we return a future?!
             String mappedTypeName = DeserializingClassRenamesProvider.findMappedName(typeName);
-            Class<?> type = Class.forName(mappedTypeName);
+            Class<?> type = new ClassLoaderUtils(BrooklynDslCommon.class).loadClass(mappedTypeName);
             
             if (!Reflections.hasNoArgConstructor(type)) {
                 throw new IllegalStateException(String.format("Cannot construct %s bean: No public no-arg constructor available", type));

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
index d35068f..ba8d679 100644
--- a/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.core.effector;
 
 import java.util.Map;
 
+import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityInitializer;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
@@ -27,6 +28,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.javalang.Boxing;
@@ -54,7 +56,7 @@ public class AddSensor<T> implements EntityInitializer {
     protected final String name;
     protected final Duration period;
     protected final String type;
-    protected final AttributeSensor<T> sensor;
+    protected AttributeSensor<T> sensor;
 
     public AddSensor(Map<String, String> params) {
         this(ConfigBag.newInstance(params));
@@ -64,27 +66,28 @@ public class AddSensor<T> implements EntityInitializer {
         this.name = Preconditions.checkNotNull(params.get(SENSOR_NAME), "Name must be supplied when defining a sensor");
         this.period = params.get(SENSOR_PERIOD);
         this.type = params.get(SENSOR_TYPE);
-        this.sensor = newSensor();
     }
 
     @Override
     public void apply(EntityLocal entity) {
+        sensor = newSensor(entity);
         ((EntityInternal) entity).getMutableEntityType().addSensor(sensor);
     }
 
-    private AttributeSensor<T> newSensor() {
+    private AttributeSensor<T> newSensor(Entity entity) {
         String className = getFullClassName(type);
-        Class<T> clazz = getType(className);
+        Class<T> clazz = getType(entity, className);
         return Sensors.newSensor(clazz, name);
     }
 
     @SuppressWarnings("unchecked")
-    protected Class<T> getType(String className) {
+    protected Class<T> getType(Entity entity, String className) {
         try {
             // TODO use OSGi loader (low priority however); also ensure that allows primitives
             Maybe<Class<?>> primitive = Boxing.getPrimitiveType(className);
             if (primitive.isPresent()) return (Class<T>) primitive.get();
-            return (Class<T>) Class.forName(className);
+            
+            return (Class<T>) new ClassLoaderUtils(this, entity).loadClass(className);
         } catch (ClassNotFoundException e) {
             if (!className.contains(".")) {
                 // could be assuming "java.lang" package; try again with that

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java
index f9cf5a7..a2d6722 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/drivers/ReflectiveEntityDriverFactory.java
@@ -26,12 +26,14 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
 import org.apache.brooklyn.api.entity.drivers.EntityDriver;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.BrooklynVersion;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.paas.PaasLocation;
 import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.ReferenceWithError;
 import org.apache.brooklyn.util.text.Strings;
@@ -193,7 +195,8 @@ public class ReflectiveEntityDriverFactory {
             String driverInterfaceName = driverInterface.getName();
             // TODO: use a proper registry later on
             try {
-                if (!Class.forName("org.apache.brooklyn.location.winrm.WinRmMachineLocation").isInstance(location)) return null;
+                Class<?> winRmLocationClass = new ClassLoaderUtils(this, entity).loadClass("org.apache.brooklyn.software-winrm", BrooklynVersion.get(), "org.apache.brooklyn.location.winrm.WinRmMachineLocation");
+                if (!winRmLocationClass.isInstance(location)) return null;
             } catch (ClassNotFoundException ex) {
                 return null;
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java b/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java
index f99b41d..ced6b7c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java
+++ b/core/src/main/java/org/apache/brooklyn/core/location/geo/HostGeoInfo.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.location.AddressableLocation;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.location.AbstractLocation;
 import org.apache.brooklyn.core.location.LocationConfigKeys;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -164,7 +165,7 @@ public class HostGeoInfo implements Serializable {
             return new UtraceHostGeoLookup();
         }
         if (type.isEmpty()) return null;
-        return (HostGeoLookup) Class.forName(type).newInstance();
+        return (HostGeoLookup) new ClassLoaderUtils(HostGeoInfo.class).loadClass(type).newInstance();
     }
 
     public static HostGeoInfo fromEntity(Entity e) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/JavaBrooklynClassLoadingContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/JavaBrooklynClassLoadingContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/JavaBrooklynClassLoadingContext.java
index 064ba03..e89501e 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/JavaBrooklynClassLoadingContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/classloading/JavaBrooklynClassLoadingContext.java
@@ -29,6 +29,7 @@ import java.util.Enumeration;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.slf4j.Logger;
@@ -81,9 +82,24 @@ public class JavaBrooklynClassLoadingContext extends AbstractBrooklynClassLoadin
         if (mgmt!=null) return mgmt.getCatalogClassLoader();
         return JavaBrooklynClassLoadingContext.class.getClassLoader();
     }
-    
+
     @SuppressWarnings({ "rawtypes", "unchecked" })
     public Maybe<Class<?>> tryLoadClass(String className) {
+        Maybe<Class<?>> cls = tryLoadClass0(className);
+        if (cls.isPresent()) {
+            return cls;
+        }
+        try {
+            return (Maybe) Maybe.of(new ClassLoaderUtils(this, mgmt).loadClass(className));
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            // return original error
+            return cls;
+        }
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private Maybe<Class<?>> tryLoadClass0(String className) {
         try {
             className = DeserializingClassRenamesProvider.findMappedName(className);
             return (Maybe) Maybe.of(getClassLoader().loadClass(className));

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java
index 7199267..e867c76 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/entitlement/Entitlements.java
@@ -21,7 +21,6 @@ package org.apache.brooklyn.core.mgmt.entitlement;
 import java.util.Arrays;
 import java.util.List;
 
-import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.entity.Entity;
@@ -35,8 +34,8 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.Sanitizer;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.persist.DeserializingClassRenamesProvider;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.javalang.Reflections;
@@ -455,10 +454,7 @@ public class Entitlements {
         }
         if (Strings.isNonBlank(type)) {
             try {
-                ClassLoader cl = mgmt != null
-                        ? mgmt.getCatalogClassLoader()
-                        : Entitlements.class.getClassLoader();
-                Class<?> clazz = cl.loadClass(DeserializingClassRenamesProvider.findMappedName(type));
+                Class<?> clazz = new ClassLoaderUtils(Entitlements.class, mgmt).loadClass(DeserializingClassRenamesProvider.findMappedName(type));
                 return (EntitlementManager) instantiate(clazz, ImmutableList.of(
                         new Object[] {mgmt, brooklynProperties},
                         new Object[] {mgmt},

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
index da2f30c..67bcd11 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
@@ -73,6 +73,7 @@ import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
 import org.apache.brooklyn.core.typereg.BasicBrooklynTypeRegistry;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.task.BasicExecutionContext;
@@ -99,7 +100,7 @@ public abstract class AbstractManagementContext implements ManagementContextInte
         Class<?> clazz;
         try{
             //todo: which classloader should we use?
-            clazz = LocalManagementContext.class.getClassLoader().loadClass(clazzName);
+            clazz = new ClassLoaderUtils(AbstractManagementContext.class).loadClass(clazzName);
         }catch(ClassNotFoundException e){
             throw new IllegalStateException(format("Could not load class [%s]",clazzName),e);
         }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerLoader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerLoader.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerLoader.java
index 7965327..37f2cae 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerLoader.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerLoader.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 
 import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer.Builder;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.text.TemplateProcessor;
 import org.apache.brooklyn.util.exceptions.Exceptions;
@@ -89,7 +90,7 @@ public class CompoundTransformerLoader {
         } else if (name.equals("rawDataTransformer")) {
             String type = (String) args.get("type");
             try {
-                Class<?> clazz = CompoundTransformerLoader.class.getClassLoader().loadClass(type);
+                Class<?> clazz = new ClassLoaderUtils(CompoundTransformer.class).loadClass(type);
                 builder.rawDataTransformer((RawDataTransformer) clazz.newInstance());
             } catch (Exception e) {
                 throw Exceptions.propagate(e);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java
index 4170613..fa8d607 100644
--- a/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java
+++ b/core/src/main/java/org/apache/brooklyn/core/objs/BrooklynTypes.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.enricher.EnricherDynamicType;
 import org.apache.brooklyn.core.entity.EntityDynamicType;
 import org.apache.brooklyn.core.policy.PolicyDynamicType;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.collect.Maps;
@@ -110,7 +111,7 @@ public class BrooklynTypes {
     @SuppressWarnings("unchecked")
     public static Map<String, ConfigKey<?>> getDefinedConfigKeys(String brooklynTypeName) {
         try {
-            return getDefinedConfigKeys((Class<? extends BrooklynObject>) Class.forName(brooklynTypeName));
+            return getDefinedConfigKeys((Class<? extends BrooklynObject>) new ClassLoaderUtils(BrooklynTypes.class).loadClass(brooklynTypeName));
         } catch (ClassNotFoundException e) {
             throw Exceptions.propagate(e);
         }
@@ -123,7 +124,7 @@ public class BrooklynTypes {
     @SuppressWarnings("unchecked")
     public static Map<String, Sensor<?>> getDefinedSensors(String entityTypeName) {
         try {
-            return getDefinedSensors((Class<? extends Entity>) Class.forName(entityTypeName));
+            return getDefinedSensors((Class<? extends Entity>) new ClassLoaderUtils(BrooklynTypes.class).loadClass(entityTypeName));
         } catch (ClassNotFoundException e) {
             throw Exceptions.propagate(e);
         }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/sensor/DurationSinceSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/DurationSinceSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/DurationSinceSensor.java
index 4be57d8..b26af56 100644
--- a/core/src/main/java/org/apache/brooklyn/core/sensor/DurationSinceSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/DurationSinceSensor.java
@@ -39,6 +39,7 @@ public class DurationSinceSensor extends AddSensor<Duration> {
 
     private static final Supplier<Long> CURRENT_TIME_SUPPLIER = new CurrentTimeSupplier();
 
+    @SuppressWarnings("serial")
     public static final ConfigKey<Supplier<Long>> EPOCH_SUPPLIER = ConfigKeys.builder(new TypeToken<Supplier<Long>>() {})
             .name("duration.since.epochsupplier")
             .description("The source of time from which durations are measured. Defaults to System.currentTimeMillis when " +
@@ -46,6 +47,7 @@ public class DurationSinceSensor extends AddSensor<Duration> {
             .defaultValue(CURRENT_TIME_SUPPLIER)
             .build();
 
+    @SuppressWarnings("serial")
     public static final ConfigKey<Supplier<Long>> TIME_SUPPLIER = ConfigKeys.builder(new TypeToken<Supplier<Long>>() {})
             .name("duration.since.timesupplier")
             .description("The source of the current time. Defaults to System.currentTimeMillis if unconfigured or the " +
@@ -55,19 +57,20 @@ public class DurationSinceSensor extends AddSensor<Duration> {
 
     private final Supplier<Long> epochSupplier;
     private final Supplier<Long> timeSupplier;
-    private final AttributeSensor<Long> epochSensor;
+    private AttributeSensor<Long> epochSensor;
 
     public DurationSinceSensor(ConfigBag params) {
         super(params);
         epochSupplier = params.get(EPOCH_SUPPLIER);
         timeSupplier = params.get(TIME_SUPPLIER);
-        epochSensor = Sensors.newLongSensor(sensor.getName() + ".epoch");
     }
 
     @Override
     public void apply(final EntityLocal entity) {
         super.apply(entity);
 
+        epochSensor = Sensors.newLongSensor(sensor.getName() + ".epoch");
+
         if (entity.sensors().get(epochSensor) == null) {
             Long epoch = epochSupplier.get();
             if (epoch == null) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java b/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
index 839448e..25ae2b5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
@@ -105,7 +105,7 @@ public final class SshCommandSensor<T> extends AddSensor<T> {
                 .onSuccess(Functions.compose(new Function<String, T>() {
                         @Override
                         public T apply(String input) {
-                            return TypeCoercions.coerce(Strings.trimEnd(input), getType(type));
+                            return TypeCoercions.coerce(Strings.trimEnd(input), getType(entity, type));
                         }}, SshValueFunctions.stdout()));
 
         SshFeed.builder()

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
index 58b4989..ca478fd 100644
--- a/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/byon/ByonLocationResolver.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.core.config.Sanitizer;
 import org.apache.brooklyn.core.location.AbstractLocationResolver;
 import org.apache.brooklyn.core.mgmt.internal.LocalLocationManager;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
 import org.apache.brooklyn.util.net.UserAndHostAndPort;
@@ -212,7 +213,8 @@ public class ByonLocationResolver extends AbstractLocationResolver {
     private Class<? extends MachineLocation> getLocationClass(String osFamily) {
         try {
             if (osFamily != null) {
-                return Class.forName(OS_TO_MACHINE_LOCATION_TYPE.get(osFamily.toLowerCase(Locale.ENGLISH))).asSubclass(MachineLocation.class);
+                String className = OS_TO_MACHINE_LOCATION_TYPE.get(osFamily.toLowerCase(Locale.ENGLISH));
+                return new ClassLoaderUtils(this, managementContext).loadClass(className).asSubclass(MachineLocation.class);
             }
         } catch (ClassNotFoundException ex) {}
         return null;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
index b66c94c..de7b7a8 100644
--- a/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/ssh/SshMachineLocation.java
@@ -72,6 +72,7 @@ import org.apache.brooklyn.core.location.access.PortForwardManagerLocationResolv
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.internal.LocalLocationManager;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.crypto.SecureKeys;
@@ -688,7 +689,7 @@ public class SshMachineLocation extends AbstractLocation implements MachineLocat
                 }
             }
             if (sshToolClass==null) sshToolClass = SshjTool.class.getName();
-            SshTool ssh = (SshTool) Class.forName(sshToolClass).getConstructor(Map.class).newInstance(args.getAllConfig());
+            SshTool ssh = (SshTool) new ClassLoaderUtils(this, getManagementContext()).loadClass(sshToolClass).getConstructor(Map.class).newInstance(args.getAllConfig());
 
             if (LOG.isTraceEnabled()) LOG.trace("using ssh-tool {} (of type {}); props ", ssh, sshToolClass);
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
new file mode 100644
index 0000000..5bbce8d
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/util/core/ClassLoaderUtils.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2016 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.brooklyn.util.core;
+
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.BrooklynVersion;
+import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.util.core.osgi.Osgis;
+import org.apache.brooklyn.util.core.osgi.SystemFrameworkLoader;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.osgi.SystemFramework;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.launch.Framework;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+
+public class ClassLoaderUtils {
+    /**
+     * White list format should be 
+     * <bundle symbolic name regex>[:<bundle version regex in dotted format (X.X.X.SNAPSHOT, instead of X.X.X-SNAPSHOT)>]
+     */
+    private static final String WHITE_LIST_DEFAULT = "org\\.apache\\.brooklyn\\..*:" + BrooklynVersion.get().replaceFirst("-", ".");
+    private static final String WHITE_LIST_KEY = "org.apache.brooklyn.classloader.fallback.bundles";
+    private static final String CLASS_NAME_DELIMITER = ":";
+    private static final Logger log = LoggerFactory.getLogger(ClassLoaderUtils.class);
+
+    // Class.forName gets the class loader from the calling class.
+    // We don't have access to the same reflection API so need to pass it explicitly.
+    private final Class<?> callingClass;
+    private final Entity entity;
+    private final ManagementContext mgmt;
+
+    public ClassLoaderUtils(Object callingObj, Entity entity) {
+        this(callingObj.getClass(), entity);
+    }
+    public ClassLoaderUtils(Object callingObj, @Nullable ManagementContext mgmt) {
+        this(callingObj.getClass(), mgmt);
+    }
+
+    public ClassLoaderUtils(Class<?> callingClass) {
+        this.callingClass = callingClass;
+        this.entity = null;
+        this.mgmt = null;
+    }
+
+    public ClassLoaderUtils(Class<?> callingClass, Entity entity) {
+        this.callingClass = callingClass;
+        this.entity = entity;
+        this.mgmt = ((EntityInternal)entity).getManagementContext();
+    }
+
+    public ClassLoaderUtils(Class<?> callingClass, @Nullable ManagementContext mgmt) {
+        this.callingClass = callingClass;
+        this.entity = null;
+        this.mgmt = mgmt;
+    }
+
+    public Class<?> loadClass(String name) throws ClassNotFoundException {
+        if (looksLikeBundledClassName(name)) {
+            String[] arr = name.split(CLASS_NAME_DELIMITER);
+            String symbolicName;
+            String version;
+            String className;
+            if (arr.length > 3) {
+                throw new IllegalStateException("'" + name + "' doesn't look like a class name and contains too many colons to be parsed as bundle:version:class triple.");
+            } else if (arr.length == 3) {
+                symbolicName = arr[0];
+                version = arr[1];
+                className = arr[2];
+            } else if (arr.length == 2) {
+                symbolicName = arr[0];
+                version = null;
+                className = arr[1];
+            } else {
+                throw new IllegalStateException("'" + name + "' contains a bundle:version:class delimiter, but only one of those specified");
+            }
+            return loadClass(symbolicName, version, className);
+        }
+
+        if (entity != null && mgmt != null) {
+            String catalogItemId = entity.getCatalogItemId();
+            if (catalogItemId != null) {
+                CatalogItem<?, ?> item = CatalogUtils.getCatalogItemOptionalVersion(mgmt, catalogItemId);
+                if (item != null) {
+                    BrooklynClassLoadingContext loader = CatalogUtils.newClassLoadingContext(mgmt, item);
+                    try {
+                        return loader.loadClass(name);
+                    } catch (IllegalStateException e) {
+                        ClassNotFoundException cnfe = Exceptions.getFirstThrowableOfType(e, ClassNotFoundException.class);
+                        NoClassDefFoundError ncdfe = Exceptions.getFirstThrowableOfType(e, NoClassDefFoundError.class);
+                        if (cnfe == null && ncdfe == null) {
+                            throw e;
+                        } else {
+                            // ignore, fall back to Class.forName(...)
+                        }
+                    }
+                } else {
+                    log.warn("Entity " + entity + " refers to non-existent catalog item " + catalogItemId + ". Trying to load class " + name);
+                }
+            }
+        }
+
+        try {
+            // Used instead of callingClass.getClassLoader() as it could be null (only for bootstrap classes)
+            return Class.forName(name, true, callingClass.getClassLoader());
+        } catch (ClassNotFoundException e) {
+        }
+
+        if (mgmt != null) {
+            try {
+                return mgmt.getCatalogClassLoader().loadClass(name);
+            } catch (ClassNotFoundException e) {
+            }
+        }
+
+        Class<?> cls = tryLoadFromBundleWhiteList(name);
+        if (cls != null) {
+            return cls;
+        } else {
+            throw new ClassNotFoundException("Class " + name + " not found on the application class path, nor in the bundle white list.");
+        }
+    }
+
+    public Class<?> loadClass(String symbolicName, @Nullable String version, String className) throws ClassNotFoundException {
+        Framework framework = getFramework();
+        if (framework != null) {
+            Maybe<Bundle> bundle = Osgis.bundleFinder(framework)
+                .symbolicName(symbolicName)
+                .version(version)
+                .find();
+            if (bundle.isAbsent() && version != null) {
+                bundle = Osgis.bundleFinder(framework)
+                    .symbolicName(symbolicName)
+                    // Convert X.X.X-SNAPSHOT to X.X.X.SNAPSHOT. Any better way to do it?
+                    .version(version.replace("-", "."))
+                    .find();
+            }
+            if (bundle.isAbsent()) {
+                throw new IllegalStateException("Bundle " + symbolicName + ":" + (version != null ? version : "any") + " not found to load class " + className);
+            }
+            return SystemFrameworkLoader.get().loadClassFromBundle(className, bundle.get());
+        } else {
+            return Class.forName(className);
+        }
+    }
+
+    protected Framework getFramework() {
+        if (mgmt != null) {
+            Maybe<OsgiManager> osgiManager = ((ManagementContextInternal)mgmt).getOsgiManager();
+            if (osgiManager.isPresent()) {
+                OsgiManager osgi = osgiManager.get();
+                return osgi.getFramework();
+            }
+        }
+
+        // Requires that caller code is executed AFTER loading bundle brooklyn-core
+        Bundle bundle = FrameworkUtil.getBundle(ClassLoaderUtils.class);
+        if (bundle != null) {
+            BundleContext bundleContext = bundle.getBundleContext();
+            return (Framework) bundleContext.getBundle(0);
+        } else {
+            return null;
+        }
+    }
+
+    private boolean looksLikeBundledClassName(String name) {
+        return name.indexOf(CLASS_NAME_DELIMITER) != -1;
+    }
+
+
+    private static class WhiteListBundlePredicate implements Predicate<Bundle> {
+        private Pattern symbolicName;
+        private Pattern version;
+
+        private WhiteListBundlePredicate(String symbolicName, String version) {
+            this.symbolicName = Pattern.compile(symbolicName);
+            this.version = version != null ? Pattern.compile(version) : null;
+        }
+
+        @Override
+        public boolean apply(Bundle input) {
+            return symbolicName.matcher(input.getSymbolicName()).matches() &&
+                    (version == null || version.matcher(input.getVersion().toString()).matches());
+        }
+    
+    }
+
+    private Class<?> tryLoadFromBundleWhiteList(String name) {
+        Framework framework = getFramework();
+        if (framework == null) {
+            return null;
+        }
+        List<Bundle> bundles = Osgis.bundleFinder(framework)
+            .satisfying(createBundleMatchingPredicate())
+            .findAll();
+        SystemFramework bundleLoader = SystemFrameworkLoader.get();
+        for (Bundle b : bundles) {
+            try {
+                return bundleLoader.loadClassFromBundle(name, b);
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+            }
+        }
+        return null;
+    }
+
+    protected WhiteListBundlePredicate createBundleMatchingPredicate() {
+        String whiteList = System.getProperty(WHITE_LIST_KEY, WHITE_LIST_DEFAULT);
+        String[] arr = whiteList.split(":");
+        String symbolicName = arr[0];
+        String version = null;
+        if (arr.length > 2) {
+            throw new IllegalStateException("Class loading fallback bundle white list '" + whiteList + "' not in the expected format <symbolic name regex>[:<version regex>].");
+        } else if (arr.length == 2) {
+            version = arr[1];
+        }
+        return new WhiteListBundlePredicate(symbolicName, version);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java b/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
index 65f85d6..94a0991 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/flags/TypeCoercions.java
@@ -18,9 +18,6 @@
  */
 package org.apache.brooklyn.util.core.flags;
 
-import groovy.lang.Closure;
-import groovy.time.TimeDuration;
-
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -56,6 +53,7 @@ import org.apache.brooklyn.util.JavaGroovyEquivalents;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.collections.QuorumCheck;
 import org.apache.brooklyn.util.collections.QuorumCheck.QuorumChecks;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -89,6 +87,9 @@ import com.google.common.net.HostAndPort;
 import com.google.common.primitives.Primitives;
 import com.google.common.reflect.TypeToken;
 
+import groovy.lang.Closure;
+import groovy.time.TimeDuration;
+
 @SuppressWarnings("rawtypes")
 public class TypeCoercions {
 
@@ -773,7 +774,7 @@ public class TypeCoercions {
             @Override
             public Class apply(final String input) {
                 try {
-                    return Class.forName(input);
+                    return new ClassLoaderUtils(this.getClass()).loadClass(input);
                 } catch (ClassNotFoundException e) {
                     throw Exceptions.propagate(e);
                 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromClassTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromClassTest.java b/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromClassTest.java
index be91c27..13c3977 100644
--- a/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromClassTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/objs/BasicSpecParameterFromClassTest.java
@@ -23,7 +23,6 @@ import static org.testng.Assert.assertNotNull;
 
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import org.apache.brooklyn.api.catalog.CatalogConfig;
 import org.apache.brooklyn.api.entity.Entity;
@@ -35,9 +34,9 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.AbstractEntity;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
-import org.testng.collections.Sets;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;
@@ -94,7 +93,7 @@ public class BasicSpecParameterFromClassTest {
     
     @Test
     public void testDebug() throws ClassNotFoundException {
-        System.out.println(BasicSpecParameter.fromClass(mgmt,  Class.forName("org.apache.brooklyn.entity.stock.BasicApplication")));
+        System.out.println(BasicSpecParameter.fromClass(mgmt,  new ClassLoaderUtils(this.getClass()).loadClass("org.apache.brooklyn.entity.stock.BasicApplication")));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
index 2696440..0b8d2c2 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
@@ -21,7 +21,9 @@ package org.apache.brooklyn.rest.resources;
 import java.util.List;
 import java.util.Map;
 
+import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.policy.Policy;
@@ -35,6 +37,7 @@ import org.apache.brooklyn.rest.filter.HaHotStateRequired;
 import org.apache.brooklyn.rest.transform.ApplicationTransformer;
 import org.apache.brooklyn.rest.transform.PolicyTransformer;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,8 +45,6 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Function;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.Maps;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.UriInfo;
 
 @HaHotStateRequired
 public class PolicyResource extends AbstractBrooklynRestResource implements PolicyApi {
@@ -86,7 +87,7 @@ public class PolicyResource extends AbstractBrooklynRestResource implements Poli
         Entity entity = brooklyn().getEntity(application, entityToken);
         Class<? extends Policy> policyType;
         try {
-            policyType = (Class<? extends Policy>) Class.forName(policyTypeName);
+            policyType = (Class<? extends Policy>) new ClassLoaderUtils(this, mgmt()).loadClass(policyTypeName);
         } catch (ClassNotFoundException e) {
             throw WebResourceUtils.badRequest("No policy with type %s found", policyTypeName);
         } catch (ClassCastException e) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/DelegatingSecurityProvider.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/DelegatingSecurityProvider.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/DelegatingSecurityProvider.java
index ca7fdf1..b374189 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/DelegatingSecurityProvider.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/security/provider/DelegatingSecurityProvider.java
@@ -24,13 +24,14 @@ import java.util.concurrent.atomic.AtomicLong;
 
 import javax.servlet.http.HttpSession;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.config.StringConfigMap;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.rest.BrooklynWebConfig;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class DelegatingSecurityProvider implements SecurityProvider {
 
@@ -85,15 +86,16 @@ public class DelegatingSecurityProvider implements SecurityProvider {
         log.info("REST using security provider " + className);
 
         try {
+            ClassLoaderUtils clu = new ClassLoaderUtils(this, mgmt);
             Class<? extends SecurityProvider> clazz;
             try {
-                clazz = (Class<? extends SecurityProvider>) Class.forName(className);
+                clazz = (Class<? extends SecurityProvider>) clu.loadClass(className);
             } catch (Exception e) {
                 String oldPackage = "brooklyn.web.console.security.";
                 if (className.startsWith(oldPackage)) {
                     className = Strings.removeFromStart(className, oldPackage);
                     className = DelegatingSecurityProvider.class.getPackage().getName() + "." + className;
-                    clazz = (Class<? extends SecurityProvider>) Class.forName(className);
+                    clazz = (Class<? extends SecurityProvider>) clu.loadClass(className);
                     log.warn("Deprecated package " + oldPackage + " detected; please update security provider to point to " + className);
                 } else throw e;
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java
index 7d48643..e5a8b92 100644
--- a/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java
+++ b/software/base/src/main/java/org/apache/brooklyn/entity/resolve/HardcodedCatalogEntitySpecResolver.java
@@ -24,12 +24,14 @@ import java.util.Set;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.BrooklynVersion;
 import org.apache.brooklyn.core.resolve.entity.AbstractEntitySpecResolver;
 import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
 import org.apache.brooklyn.entity.group.DynamicCluster;
 import org.apache.brooklyn.entity.group.DynamicRegionsFabric;
 import org.apache.brooklyn.entity.java.VanillaJavaApp;
 import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 
 import com.google.common.base.CaseFormat;
 import com.google.common.base.Converter;
@@ -38,14 +40,17 @@ import com.google.common.collect.ImmutableMap;
 public class HardcodedCatalogEntitySpecResolver extends AbstractEntitySpecResolver {
     private static final String RESOLVER_NAME = "catalog";
 
-    private static final Map<String, String> CATALOG_TYPES = ImmutableMap.<String, String>builder()
-            .put("cluster", DynamicCluster.class.getName())
-            .put("fabric", DynamicRegionsFabric.class.getName())
-            .put("vanilla", VanillaSoftwareProcess.class.getName())
-            .put("software-process", VanillaSoftwareProcess.class.getName())
-            .put("java-app", VanillaJavaApp.class.getName())
-            .put("brooklyn-node", BrooklynNode.class.getName())
-            .put("web-app-cluster","org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster")
+    private static final Map<String, Class<? extends Entity>> CATALOG_CLASS_TYPES = ImmutableMap.<String, Class<? extends Entity>>builder()
+            .put("cluster", DynamicCluster.class)
+            .put("fabric", DynamicRegionsFabric.class)
+            .put("vanilla", VanillaSoftwareProcess.class)
+            .put("software-process", VanillaSoftwareProcess.class)
+            .put("java-app", VanillaJavaApp.class)
+            .put("brooklyn-node", BrooklynNode.class)
+            .build();
+
+    private static final Map<String, String> CATALOG_STRING_TYPES = ImmutableMap.<String, String>builder()
+            .put("web-app-cluster","org.apache.brooklyn.software-webapp:" + BrooklynVersion.get() + ":org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster")
             .build();
 
     // Allow catalog-type or CatalogType as service type string
@@ -58,39 +63,47 @@ public class HardcodedCatalogEntitySpecResolver extends AbstractEntitySpecResolv
     @Override
     protected boolean canResolve(String type, BrooklynClassLoadingContext loader) {
         String localType = getLocalType(type);
-        String specType = getImplementation(localType);
-        return specType != null;
+        return getImplementation(CATALOG_CLASS_TYPES, localType) != null ||
+                getImplementation(CATALOG_STRING_TYPES, localType) != null;
     }
 
     @Override
     public EntitySpec<?> resolve(String type, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
         String localType = getLocalType(type);
-        String specType = getImplementation(localType);
-        if (specType != null) {
-            return buildSpec(specType);
-        } else {
-            return null;
+        Class<? extends Entity> specClassType = getImplementation(CATALOG_CLASS_TYPES, localType);
+        if (specClassType != null) {
+            return buildSpec(specClassType);
         }
+        String specStringType = getImplementation(CATALOG_STRING_TYPES, localType);
+        if (specStringType != null) {
+            return buildSpec(specStringType);
+        }
+        return null;
     }
 
-    private String getImplementation(String type) {
-        String specType = CATALOG_TYPES.get(type);
+    private <T> T getImplementation(Map<String, T> types, String type) {
+        T specType = types.get(type);
         if (specType != null) {
             return specType;
         } else {
-            return CATALOG_TYPES.get(FMT.convert(type));
+            return types.get(FMT.convert(type));
         }
     }
 
-    private EntitySpec<?> buildSpec(String specType) {
+    private EntitySpec<?> buildSpec(String specTypName) {
         // TODO is this hardcoded list deprecated? If so log a warning.
         try {
-            @SuppressWarnings("unchecked")
-            Class<Entity> specClass = (Class<Entity>)mgmt.getCatalogClassLoader().loadClass(specType);
-            return EntitySpec.create(specClass);
+            Class<?> specType = new ClassLoaderUtils(this.getClass()).loadClass(specTypName);
+            return buildSpec(specType);
         } catch (ClassNotFoundException e) {
-            throw new IllegalStateException("Unable to load hardcoded catalog type " + specType, e);
+            throw new IllegalStateException("Unable to load hardcoded catalog type " + specTypName, e);
         }
     }
 
+    protected EntitySpec<?> buildSpec(Class<?> specType) {
+        @SuppressWarnings("unchecked")
+        Class<Entity> specClass = (Class<Entity>)specType;
+        return EntitySpec.create(specClass);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/f3154764/software/winrm/src/main/java/org/apache/brooklyn/location/winrm/WinRmMachineLocation.java
----------------------------------------------------------------------
diff --git a/software/winrm/src/main/java/org/apache/brooklyn/location/winrm/WinRmMachineLocation.java b/software/winrm/src/main/java/org/apache/brooklyn/location/winrm/WinRmMachineLocation.java
index 7a5b638..8d537ac 100644
--- a/software/winrm/src/main/java/org/apache/brooklyn/location/winrm/WinRmMachineLocation.java
+++ b/software/winrm/src/main/java/org/apache/brooklyn/location/winrm/WinRmMachineLocation.java
@@ -18,6 +18,9 @@
  */
 package org.apache.brooklyn.location.winrm;
 
+import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKeyWithPrefix;
+import static org.apache.brooklyn.core.config.ConfigKeys.newStringConfigKey;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -29,7 +32,6 @@ import java.util.Set;
 
 import javax.annotation.Nullable;
 
-import com.google.common.annotations.Beta;
 import org.apache.brooklyn.api.location.MachineDetails;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.OsDetails;
@@ -42,6 +44,7 @@ import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
 import org.apache.brooklyn.core.location.AbstractLocation;
 import org.apache.brooklyn.core.location.access.PortForwardManager;
 import org.apache.brooklyn.core.location.access.PortForwardManagerLocationResolver;
+import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.internal.ssh.SshTool;
 import org.apache.brooklyn.util.core.internal.winrm.WinRmTool;
@@ -55,6 +58,7 @@ import org.apache.commons.codec.binary.Base64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Charsets;
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
@@ -66,9 +70,6 @@ import com.google.common.collect.Iterables;
 import com.google.common.net.HostAndPort;
 import com.google.common.reflect.TypeToken;
 
-import static org.apache.brooklyn.core.config.ConfigKeys.newConfigKeyWithPrefix;
-import static org.apache.brooklyn.core.config.ConfigKeys.newStringConfigKey;
-
 public class WinRmMachineLocation extends AbstractLocation implements MachineLocation {
 
     private static final Logger LOG = LoggerFactory.getLogger(WinRmMachineLocation.class);
@@ -353,7 +354,7 @@ public class WinRmMachineLocation extends AbstractLocation implements MachineLoc
             // look up tool class
             String toolClass = args.get(WINRM_TOOL_CLASS);
             if (toolClass == null) toolClass = Winrm4jTool.class.getName();
-            WinRmTool tool = (WinRmTool) Class.forName(toolClass).getConstructor(Map.class).newInstance(args.getAllConfig());
+            WinRmTool tool = (WinRmTool) new ClassLoaderUtils(this, getManagementContext()).loadClass(toolClass).getConstructor(Map.class).newInstance(args.getAllConfig());
 
             if (LOG.isTraceEnabled()) LOG.trace("using ssh-tool {} (of type {}); props ", tool, toolClass);