You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ge...@apache.org on 2017/04/28 10:32:06 UTC

[05/13] brooklyn-server git commit: done the basics, bundle persistence working and with a test

done the basics, bundle persistence working and with a test

note `PersistenceObjectStore` for accessing blob store impls have been changed to handle byte streams better.
also comments on managementPlaneId updated and more logging around it, as i was getting confused debugging this.


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

Branch: refs/heads/master
Commit: abd0cb8bf79457396036d870d9f3ba3c41e6aa80
Parents: e8b5fd0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Apr 21 11:52:02 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Apr 21 14:55:53 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/api/mgmt/ManagementContext.java    |  23 +---
 .../api/mgmt/rebind/RebindExceptionHandler.java |   8 +-
 .../mgmt/rebind/mementos/BrooklynMemento.java   |   3 +
 .../mementos/BrooklynMementoPersister.java      |   2 +
 .../spi/creation/CampToSpecTransformer.java     |   8 +-
 .../camp/brooklyn/AbstractYamlRebindTest.java   |  13 ++
 .../catalog/CatalogMakeOsgiBundleTest.java      |   2 +-
 .../CatalogOsgiVersionMoreEntityRebindTest.java |  33 ++++-
 .../CatalogOsgiVersionMoreEntityTest.java       |  30 ++++-
 .../internal/JavaCatalogToSpecTransformer.java  |  10 +-
 .../mgmt/ha/HighAvailabilityManagerImpl.java    |  26 ++--
 .../brooklyn/core/mgmt/ha/OsgiManager.java      |  58 +++++++--
 .../internal/AbstractManagementContext.java     |   2 +-
 .../mgmt/internal/LocalManagementContext.java   |  11 +-
 .../NonDeploymentManagementContext.java         |   5 +-
 .../BrooklynMementoPersisterToObjectStore.java  |  42 ++++---
 .../mgmt/persist/BrooklynPersistenceUtils.java  |   3 +-
 .../persist/FileBasedStoreObjectAccessor.java   |  15 ++-
 .../mgmt/persist/PersistenceObjectStore.java    |   2 +
 .../persist/StoreObjectAccessorLocking.java     |  24 ++++
 .../core/mgmt/persist/XmlMementoSerializer.java |   5 +-
 .../rebind/BasicManagedBundleRebindSupport.java |  41 +++++++
 .../core/mgmt/rebind/RebindContextImpl.java     |  24 +++-
 .../mgmt/rebind/RebindContextLookupContext.java |  13 ++
 .../mgmt/rebind/RebindExceptionHandlerImpl.java |   8 +-
 .../core/mgmt/rebind/RebindIteration.java       |   4 +-
 .../core/mgmt/rebind/RebindManagerImpl.java     |   2 +-
 .../mgmt/rebind/dto/BrooklynMementoImpl.java    |  25 +++-
 .../mgmt/rebind/dto/MutableBrooklynMemento.java |  27 ++++
 .../brooklyn/core/plan/PlanToSpecFactory.java   |   6 +-
 .../core/plan/PlanToSpecTransformer.java        |   9 +-
 .../core/typereg/BasicManagedBundle.java        |   3 +-
 .../core/typereg/TypePlanTransformers.java      |   6 +-
 .../HighAvailabilityManagerSplitBrainTest.java  |   4 +-
 .../brooklyn/core/mgmt/ha/HotStandbyTest.java   |   2 +-
 .../brooklyn/core/mgmt/ha/WarmStandbyTest.java  |   2 +-
 .../mgmt/osgi/OsgiVersionMoreEntityTest.java    |  31 +----
 .../BrooklynMementoPersisterTestFixture.java    |   4 +-
 .../core/mgmt/persist/InMemoryObjectStore.java  |  47 ++++---
 .../core/mgmt/persist/ListeningObjectStore.java |  18 +++
 .../mgmt/persist/XmlMementoSerializerTest.java  | 122 ++++++++++---------
 .../core/mgmt/rebind/ManagementPlaneIdTest.java |  22 ++--
 .../core/mgmt/rebind/RebindTestFixture.java     |   1 -
 .../transformer/CompoundTransformerTest.java    |   2 +-
 .../core/plan/XmlPlanToSpecTransformer.java     |   7 +-
 .../jclouds/JcloudsStoreObjectAccessor.java     |  19 +--
 .../rest/resources/CatalogResource.java         |  36 +-----
 .../apache/brooklyn/util/stream/Streams.java    |  11 ++
 .../brooklyn/util/text/StringShortener.java     |   6 +-
 .../brooklyn/util/osgi/OsgiTestResources.java   |  11 +-
 .../brooklyn/util/text/StringShortenerTest.java |   2 +-
 51 files changed, 555 insertions(+), 285 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java
index aacc33d..515ec6b 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/ManagementContext.java
@@ -39,7 +39,6 @@ import org.apache.brooklyn.config.StringConfigMap;
 import org.apache.brooklyn.util.guava.Maybe;
 
 import com.google.common.annotations.Beta;
-import com.google.common.base.Optional;
 
 /**
  * This is the entry point for accessing and interacting with a realm of applications and their entities in Brooklyn.
@@ -59,22 +58,9 @@ public interface ManagementContext {
     //  - interface PropertiesReloadListener
     
     /** 
-     * UID for the Brooklyn management plane which this {@link ManagementContext} node is a part of.
-     * <p>
-     * Each Brooklyn entity is actively managed by a unique management plane 
-     * whose ID which should not normally change for the duration of that entity, 
-     * even though the nodes in that plane might, and the plane may go down and come back up. 
-     * In other words the value of {@link Application#getManagementContext()#getManagementPlaneId()} 
-     * will generally be constant (in contrast to {@link #getManagementNodeId()}).
-     * <p>
-     * This value should not be null unless the management context is still initialising. The value is set:
-     * <ul>
-     *   <li>no persistence - during launch
-     *   <li>persistence enabled, HA disabled - on rebind (during launch)
-     *   <li>persistence enabled, HA enabled - on the first HA state check (async to launch)
-     * </ul>
+     * As {@link #getManagementPlaneIdMaybe()}, but throws if not available, to prevent callers accessing prematurely.
      * 
-     * @deprecated since 0.11.0, use {@link #getOptionalManagementPlaneId()} instead.
+     * @deprecated since 0.11.0, use {@link #getManagementPlaneIdMaybe()} instead.
      */
     @Deprecated
     String getManagementPlaneId();
@@ -95,14 +81,15 @@ public interface ManagementContext {
      *   <li>persistence enabled, HA enabled - on the first HA state check (async to launch)
      * </ul>
      */
-    Optional<String> getOptionalManagementPlaneId();
+    Maybe<String> getManagementPlaneIdMaybe();
     
     /** 
      * UID for this {@link ManagementContext} node (as part of a single management plane).
      * <p>
      * No two instances of {@link ManagementContext} should ever have the same node UID. 
      * The value of {@link Application#getManagementContext()#getManagementNodeId()} may
-     * change many times (in contrast to {@link #getOptionalManagementPlaneId()}). 
+     * change if it is rebinded to a different node,
+     * in contrast to {@link #getManagementPlaneIdMaybe()} which is the same for all nodes in a Brooklyn plane. 
      * <p>
      * This value should not be null unless the management context is a non-functional
      * (non-deployment) instance. */

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java
index 574a680..76002e0 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/RebindExceptionHandler.java
@@ -30,9 +30,10 @@ import org.apache.brooklyn.api.objs.BrooklynObjectType;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
+import org.apache.brooklyn.config.ConfigKey;
 
 import com.google.common.annotations.Beta;
-import org.apache.brooklyn.config.ConfigKey;
 
 /**
  * Handler called on all exceptions to do with rebind.
@@ -81,6 +82,11 @@ public interface RebindExceptionHandler {
      * @return the catalog item to use in place of the missing one
      */
     CatalogItem<?, ?> onDanglingCatalogItemRef(String id);
+    
+    /**
+     * @return the bundle to use in place of a missing one
+     */
+    ManagedBundle onDanglingBundleRef(String id);
 
     /**
      * @return the item to use in place of the missing one

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMemento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMemento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMemento.java
index 8ee23da..aa8422f 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMemento.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMemento.java
@@ -45,6 +45,7 @@ public interface BrooklynMemento extends Serializable {
     public EnricherMemento getEnricherMemento(String id);
     public FeedMemento getFeedMemento(String id);
     public CatalogItemMemento getCatalogItemMemento(String id);
+    public ManagedBundleMemento getManagedBundleMemento(String id);
 
     public Collection<String> getApplicationIds();
     public Collection<String> getTopLevelLocationIds();
@@ -55,6 +56,7 @@ public interface BrooklynMemento extends Serializable {
     public Collection<String> getEnricherIds();
     public Collection<String> getFeedIds();
     public Collection<String> getCatalogItemIds();
+    public Collection<String> getManagedBundleIds();
 
     public Map<String, EntityMemento> getEntityMementos();
     public Map<String, LocationMemento> getLocationMementos();
@@ -62,5 +64,6 @@ public interface BrooklynMemento extends Serializable {
     public Map<String, EnricherMemento> getEnricherMementos();
     public Map<String, FeedMemento> getFeedMementos();
     public Map<String, CatalogItemMemento> getCatalogItemMementos();
+    public Map<String, ManagedBundleMemento> getManagedBundleMementos();
 
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java
index f600418..e352200 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoPersister.java
@@ -37,6 +37,7 @@ import org.apache.brooklyn.api.objs.BrooklynObjectType;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;
@@ -56,6 +57,7 @@ public interface BrooklynMementoPersister {
         Enricher lookupEnricher(String id);
         Feed lookupFeed(String id);
         CatalogItem<?, ?> lookupCatalogItem(String id);
+        ManagedBundle lookupBundle(String id);
         
         /** retrieve the item with the given ID, optionally ensuring it is of the indicated type; null if not found */
         BrooklynObject lookup(@Nullable BrooklynObjectType type, String objectId);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
index 4c94b16..cb6b740 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampToSpecTransformer.java
@@ -32,9 +32,9 @@ import org.apache.brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate;
 import org.apache.brooklyn.camp.spi.instantiate.AssemblyTemplateInstantiator;
 import org.apache.brooklyn.core.mgmt.classloading.JavaBrooklynClassLoadingContext;
-import org.apache.brooklyn.core.plan.PlanNotRecognizedException;
 import org.apache.brooklyn.core.plan.PlanToSpecTransformer;
 import org.apache.brooklyn.core.typereg.RegisteredTypes;
+import org.apache.brooklyn.core.typereg.UnsupportedTypePlanException;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.slf4j.Logger;
@@ -74,10 +74,10 @@ public class CampToSpecTransformer implements PlanToSpecTransformer {
                 if (at.getPlatformComponentTemplates()==null || at.getPlatformComponentTemplates().isEmpty()) {
                     if (at.getCustomAttributes().containsKey(BrooklynCampReservedKeys.BROOKLYN_CATALOG))
                         throw new IllegalArgumentException("Unrecognized application blueprint format: expected an application, not a brooklyn.catalog");
-                    throw new PlanNotRecognizedException("Unrecognized application blueprint format: no services defined");
+                    throw new UnsupportedTypePlanException("Unrecognized application blueprint format: no services defined");
                 }
                 // map this (expected) error to a nicer message
-                throw new PlanNotRecognizedException("Unrecognized application blueprint format");
+                throw new UnsupportedTypePlanException("Unrecognized application blueprint format");
             }
         } catch (Exception e) {
             // TODO how do we figure out that the plan is not supported vs. invalid to wrap in a PlanNotRecognizedException?
@@ -92,7 +92,7 @@ public class CampToSpecTransformer implements PlanToSpecTransformer {
     public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) {
         // Ignore old-style java type catalog items - there is a different (deprecated) transformer for that
         if (item.getPlanYaml() == null) {
-            throw new PlanNotRecognizedException("Old style catalog item " + item + " not supported.");
+            throw new UnsupportedTypePlanException("Old style catalog item " + item + " not supported.");
         }
         if (encounteredTypes.contains(item.getSymbolicName())) {
             throw new IllegalStateException("Already encountered types " + encounteredTypes + " must not contain catalog item being resolver " + item.getSymbolicName());

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
index 0d6d5c2..1248110 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.camp.brooklyn;
 
+import java.io.File;
 import java.io.Reader;
 import java.io.StringReader;
 import java.util.Map;
@@ -29,7 +30,9 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.CampTypePlanTransformer;
+import org.apache.brooklyn.camp.spi.PlatformRootSummary;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
@@ -72,6 +75,16 @@ public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplicati
         platform = launcher.getCampPlatform();
     }
 
+    @Override
+    protected LocalManagementContext createNewManagementContext(File mementoDir, HighAvailabilityMode haMode, Map<?, ?> additionalProperties) {
+        LocalManagementContext newMgmt = super.createNewManagementContext(mementoDir, haMode, additionalProperties);
+        new BrooklynCampPlatform(
+                PlatformRootSummary.builder().name("Brooklyn CAMP Platform").build(),
+                newMgmt)
+            .setConfigKeyAtManagmentContext();
+        return newMgmt;
+    }
+    
     @AfterMethod(alwaysRun = true)
     @Override
     public void tearDown() throws Exception {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogMakeOsgiBundleTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogMakeOsgiBundleTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogMakeOsgiBundleTest.java
index 6f7117e..c1030c1 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogMakeOsgiBundleTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogMakeOsgiBundleTest.java
@@ -174,7 +174,7 @@ public class CatalogMakeOsgiBundleTest extends AbstractYamlTest {
         try (FileInputStream fin = new FileInputStream(jf)) {
             BasicManagedBundle bundleMetadata = new BasicManagedBundle();
             Bundle bundle =
-                ((LocalManagementContext)mgmt()).getOsgiManager().get().installUploadedBundle(bundleMetadata, fin);
+                ((LocalManagementContext)mgmt()).getOsgiManager().get().installUploadedBundle(bundleMetadata, fin, true);
             bundlesToRemove.add(bundle);
         } catch (Exception e) {
             throw Exceptions.propagate(e);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java
index cee7a4d..a3ca51b 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java
@@ -20,23 +20,32 @@ package org.apache.brooklyn.camp.brooklyn.catalog;
 
 import static org.testng.Assert.assertEquals;
 
+import java.util.Map;
+
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
+import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.camp.brooklyn.AbstractYamlRebindTest;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.osgi.OsgiVersionMoreEntityTest;
 import org.apache.brooklyn.core.test.entity.TestEntity;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.entity.stock.BasicApplication;
+import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.core.ClassLoaderUtils;
+import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.javalang.Reflections;
 import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
@@ -44,7 +53,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
 /** Many of the same tests as per {@link OsgiVersionMoreEntityTest} but using YAML for catalog and entities, so catalog item ID is set automatically */
-public class CatalogOsgiVersionMoreEntityRebindTest extends AbstractYamlRebindTest {
+public class CatalogOsgiVersionMoreEntityRebindTest extends AbstractYamlRebindTest implements OsgiTestResources {
     
     @SuppressWarnings("unused")
     private static final Logger log = LoggerFactory.getLogger(CatalogOsgiVersionMoreEntityRebindTest.class);
@@ -54,7 +63,27 @@ public class CatalogOsgiVersionMoreEntityRebindTest extends AbstractYamlRebindTe
         return true;
     }
 
-    // See https://issues.apache.org/jira/browse/BROOKLYN-409
+    @Test
+    public void testRebindAppIncludingBundle() throws Exception {
+        TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_PATH);
+        ((ManagementContextInternal)mgmt()).getOsgiManager().get().installUploadedBundle(new BasicManagedBundle(), 
+            new ResourceUtils(getClass()).getResourceFromUrl(BROOKLYN_TEST_MORE_ENTITIES_V1_URL), true);
+        
+        createAndStartApplication("services: [ { type: "+BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY+" } ]");
+        
+        StartableApplication newApp = rebind();
+
+        // bundles installed
+        Map<String, ManagedBundle> bundles = ((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundles();
+        Asserts.assertSize(bundles.keySet(), 1);
+        
+        // types installed
+        RegisteredType t = mgmt().getTypeRegistry().get("org.apache.brooklyn.test.osgi.entities.more.MoreEntity");
+        Assert.assertNotNull(t);
+        
+        Assert.assertNotNull(newApp);
+    }
+    
     @Test
     public void testPolicyInBundleReferencedByStockCatalogItem() throws Exception {
         TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_PATH);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
index 15ff38e..118c518 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
@@ -20,6 +20,8 @@ package org.apache.brooklyn.camp.brooklyn.catalog;
 
 import static org.testng.Assert.assertTrue;
 
+import java.util.Map;
+
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
@@ -27,16 +29,22 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynEntityMatcher;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.osgi.OsgiVersionMoreEntityTest;
 import org.apache.brooklyn.core.objs.BrooklynTypes;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
 import org.apache.brooklyn.core.typereg.RegisteredTypes;
+import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.osgi.OsgiTestResources;
 import org.apache.brooklyn.util.text.Strings;
+import org.osgi.framework.Bundle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -45,7 +53,7 @@ import org.testng.annotations.Test;
 import com.google.common.collect.Iterables;
 
 /** Many of the same tests as per {@link OsgiVersionMoreEntityTest} but using YAML for catalog and entities, so catalog item ID is set automatically */
-public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest {
+public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest implements OsgiTestResources {
     
     private static final Logger log = LoggerFactory.getLogger(CatalogOsgiVersionMoreEntityTest.class);
 
@@ -58,6 +66,26 @@ public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest {
         return ResourceUtils.create(CatalogOsgiVersionMoreEntityTest.class).getResourceAsString(
             "classpath:/"+CatalogOsgiVersionMoreEntityTest.class.getPackage().getName().replace('.', '/')+"/"+filename);
     }
+
+    @Test
+    public void testBrooklynManagedBundleInstall() throws Exception {
+        BasicManagedBundle mb = new BasicManagedBundle();
+        Bundle b = ((ManagementContextInternal)mgmt()).getOsgiManager().get().installUploadedBundle(mb, 
+            new ResourceUtils(getClass()).getResourceFromUrl(BROOKLYN_TEST_MORE_ENTITIES_V1_URL), true);
+        Assert.assertEquals(mb.getSymbolicName(), b.getSymbolicName());
+        
+        // bundle installed
+        Map<String, ManagedBundle> bundles = ((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundles();
+        Asserts.assertSize(bundles.keySet(), 1);
+        Assert.assertEquals(mb.getId(), Iterables.getOnlyElement( bundles.keySet() ));
+        
+        // types installed
+        RegisteredType t = mgmt().getTypeRegistry().get(BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY);
+        Assert.assertNotNull(t);
+        
+        // can deploy
+        createAndStartApplication("services: [ { type: "+BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY+" } ]");
+    }
     
     @Test
     public void testMoreEntityV1() throws Exception {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
index 4e15d24..2c76520 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
@@ -30,8 +30,8 @@ import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.objs.BasicSpecParameter;
-import org.apache.brooklyn.core.plan.PlanNotRecognizedException;
 import org.apache.brooklyn.core.plan.PlanToSpecTransformer;
+import org.apache.brooklyn.core.typereg.UnsupportedTypePlanException;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -65,13 +65,13 @@ public class JavaCatalogToSpecTransformer implements PlanToSpecTransformer {
     }
 
     @Override
-    public EntitySpec<? extends Application> createApplicationSpec(String plan) throws PlanNotRecognizedException {
-        throw new PlanNotRecognizedException(getClass().getName() + " doesn't parse application plans.");
+    public EntitySpec<? extends Application> createApplicationSpec(String plan) throws UnsupportedTypePlanException {
+        throw new UnsupportedTypePlanException(getClass().getName() + " doesn't parse application plans.");
     }
 
     @Override
     public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(
-            CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws PlanNotRecognizedException {
+            CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws UnsupportedTypePlanException {
         @SuppressWarnings("deprecation")
         String javaType = item.getJavaType();
         if (javaType != null) {
@@ -104,7 +104,7 @@ public class JavaCatalogToSpecTransformer implements PlanToSpecTransformer {
             SpecT untypedSpc = (SpecT) spec;
             return untypedSpc;
         } else {
-            throw new PlanNotRecognizedException(getClass().getName() + " parses only old-style catalog items containing javaType");
+            throw new UnsupportedTypePlanException(getClass().getName() + " parses only old-style catalog items containing javaType");
         }
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
index db65c9b..11cf9f3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerImpl.java
@@ -333,7 +333,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
                 ManagementPlaneSyncRecord newState = loadManagementPlaneSyncRecord(true);
                 String masterNodeId = newState.getMasterNodeId();
                 ManagementNodeSyncRecord masterNodeDetails = newState.getManagementNodes().get(masterNodeId);
-                LOG.info("Management node "+ownNodeId+" running as HA " + getInternalNodeState() + " autodetected"
+                LOG.info("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" running as HA " + getInternalNodeState() + " autodetected"
                         + (startMode == HighAvailabilityMode.HOT_STANDBY || startMode == HighAvailabilityMode.HOT_BACKUP ? 
                             " (will change to "+startMode+")" : "")
                         + ", " +
@@ -343,25 +343,25 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
                         (masterNodeDetails==null || masterNodeDetails.getUri()==null ? " (no url)" : " at "+masterNodeDetails.getUri())));
                 break;
             case MASTER:
-                LOG.info("Management node "+ownNodeId+" running as HA MASTER autodetected");
+                LOG.info("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" running as HA MASTER autodetected");
                 break;
             default:
-                throw new IllegalStateException("Management node "+ownNodeId+" set to HA AUTO, encountered unexpected mode "+getInternalNodeState());
+                throw new IllegalStateException("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" set to HA AUTO, encountered unexpected mode "+getInternalNodeState());
             }
             break;
         case MASTER:
             if (!failOnExplicitModesIfUnusual || existingMaster==null) {
                 promoteToMaster();
                 if (existingMaster!=null) {
-                    LOG.info("Management node "+ownNodeId+" running as HA MASTER explicitly");
+                    LOG.info("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" running as HA MASTER explicitly");
                 } else {
-                    LOG.info("Management node "+ownNodeId+" running as HA MASTER explicitly, stealing from "+existingMaster);
+                    LOG.info("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" running as HA MASTER explicitly, stealing from "+existingMaster);
                 }
             } else if (!weAreRecognisedAsMaster) {
                 throw new IllegalStateException("Master already exists; cannot run as master (master "+existingMaster.toVerboseString()+"); "
                     + "to trigger a promotion, set a priority and demote the current master");
             } else {
-                LOG.info("Management node "+ownNodeId+" already running as HA MASTER, when set explicitly");
+                LOG.info("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" already running as HA MASTER, when set explicitly");
             }
             break;
         case HOT_BACKUP:
@@ -383,11 +383,11 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
                     publishAndCheck(true);
                 }
                 if (failOnExplicitModesIfUnusual && existingMaster==null) {
-                    LOG.error("Management node "+ownNodeId+" detected no master when "+startMode+" requested and existing master required; failing.");
+                    LOG.error("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" detected no master when "+startMode+" requested and existing master required; failing.");
                     throw new IllegalStateException("No existing master; cannot start as "+startMode);
                 }
             }
-            String message = "Management node "+ownNodeId+" running as HA "+getNodeState()+" (";
+            String message = "Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" running as HA "+getNodeState()+" (";
             if (getNodeState().toString().equals(startMode.toString()))
                 message += "explicitly requested";
             else if (startMode==HighAvailabilityMode.HOT_STANDBY && getNodeState()==ManagementNodeState.STANDBY)
@@ -410,7 +410,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
             break;
         case DISABLED:
             // safe just to run even if we weren't master
-            LOG.info("Management node "+ownNodeId+" HA DISABLED (was "+getInternalNodeState()+")");
+            LOG.info("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" HA DISABLED (was "+getInternalNodeState()+")");
             demoteTo(ManagementNodeState.FAILED);
             if (pollingTask!=null) pollingTask.cancel(true);
             break;
@@ -435,15 +435,15 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
                     publishHealth();
 
                     if (getNodeState()==ManagementNodeState.HOT_STANDBY || getNodeState()==ManagementNodeState.HOT_BACKUP) {
-                        LOG.info("Management node "+ownNodeId+" now running as HA "+getNodeState()+"; "
+                        LOG.info("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" now running as HA "+getNodeState()+"; "
                             + managementContext.getApplications().size()+" application"+Strings.s(managementContext.getApplications().size())+" loaded");
                     } else {
                         // shouldn't come here, we should have gotten an error above
-                        LOG.warn("Management node "+ownNodeId+" unable to promote to "+startMode+" (currently "+getNodeState()+"); "
+                        LOG.warn("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" unable to promote to "+startMode+" (currently "+getNodeState()+"); "
                             + "(see log for further details)");
                     }
                 } catch (Exception e) {
-                    LOG.warn("Management node "+ownNodeId+" unable to promote to "+startMode+" (currently "+getNodeState()+"); rethrowing: "+Exceptions.collapseText(e));
+                    LOG.warn("Management node "+ownNodeId+" in "+managementContext.getManagementPlaneIdMaybe().or("<new-plane>")+" unable to promote to "+startMode+" (currently "+getNodeState()+"); rethrowing: "+Exceptions.collapseText(e));
                     nodeStateTransitionComplete = true;
                     throw Exceptions.propagate(e);
                 }
@@ -980,7 +980,7 @@ public class HighAvailabilityManagerImpl implements HighAvailabilityManager {
         if (disabled) {
             // if HA is disabled, then we are the only node - no persistence; just load a memento to describe this node
             Builder builder = ManagementPlaneSyncRecordImpl.builder()
-                .planeId(managementContext.getOptionalManagementPlaneId().orNull())
+                .planeId(managementContext.getManagementPlaneIdMaybe().orNull())
                 .node(createManagementNodeSyncRecord(true));
             if (getTransitionTargetNodeState() == ManagementNodeState.MASTER) {
                 builder.masterNodeId(ownNodeId);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
index 37ba4ce..fbef947 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java
@@ -32,16 +32,20 @@ import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
 import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.BrooklynVersion;
+import org.apache.brooklyn.core.catalog.internal.CatalogBundleLoader;
 import org.apache.brooklyn.core.mgmt.persist.OsgiClassPrefixer;
 import org.apache.brooklyn.core.server.BrooklynServerConfig;
 import org.apache.brooklyn.core.server.BrooklynServerPaths;
 import org.apache.brooklyn.core.typereg.BasicManagedBundle;
+import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.osgi.Osgis;
@@ -57,11 +61,15 @@ import org.apache.brooklyn.util.stream.Streams;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
 import org.osgi.framework.launch.Framework;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
@@ -125,7 +133,7 @@ public class OsgiManager {
         return ImmutableMap.copyOf(managedBundles);
     }
     
-    public Bundle installUploadedBundle(ManagedBundle bundleMetadata, InputStream zipIn) {
+    public Bundle installUploadedBundle(ManagedBundle bundleMetadata, InputStream zipIn, boolean loadCatalogBom) {
         try {
             Bundle alreadyBundle = checkBundleInstalledThrowIfInconsistent(bundleMetadata, false);
             if (alreadyBundle!=null) {
@@ -152,19 +160,18 @@ public class OsgiManager {
             }
             mgmt.getRebindManager().getChangeListener().onChanged(bundleMetadata);
             
+            // starting here  flags wiring issues earlier
+            // but may break some things running from the IDE
             bundleInstalled.start();
-            // benefits of start:
-            // a) we get wiring issues thrown here, and
-            // b) catalog.bom in root will be scanned synchronously here
-            // however drawbacks:
-            // c) other code doesn't always do it (see eg BundleMaker)
-            // d) heavier-weight earlier
-            // e) tests in IDE break (but mvn fine)
+
+            if (loadCatalogBom) {
+                loadCatalogBom(bundleInstalled);
+            }
             
             return bundleInstalled;
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
-            throw new IllegalStateException("Bundle "+bundleMetadata+" failed to install: " + e.getMessage(), e);
+            throw new IllegalStateException("Bundle "+bundleMetadata+" failed to install: " + Exceptions.collapseText(e), e);
         }
     }
     
@@ -188,6 +195,39 @@ public class OsgiManager {
         }
     }
 
+    @Beta
+    // TODO this is designed to work if the FEATURE_LOAD_BUNDLE_CATALOG_BOM is disabled, the default, but unintuitive here
+    // it probably works even if that is true, but we should consider what to do;
+    // possibly remove that other capability, so that bundles with BOMs _have_ to be installed via this method.
+    // (load order gets confusing with auto-scanning...)
+    public List<? extends CatalogItem<?,?>> loadCatalogBom(Bundle bundle) {
+        List<? extends CatalogItem<?, ?>> catalogItems = MutableList.of();
+        loadCatalogBom(mgmt, bundle, catalogItems);
+        return catalogItems;
+    }
+    
+    private static Iterable<? extends CatalogItem<?, ?>> loadCatalogBom(ManagementContext mgmt, Bundle bundle, Iterable<? extends CatalogItem<?, ?>> catalogItems) {
+        if (!BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_LOAD_BUNDLE_CATALOG_BOM)) {
+            // if the above feature is not enabled, let's do it manually (as a contract of this method)
+            try {
+                // TODO improve on this - it ignores the configuration of whitelists, see CatalogBomScanner.
+                // One way would be to add the CatalogBomScanner to the new Scratchpad area, then retrieving the singleton
+                // here to get back the predicate from it.
+                final Predicate<Bundle> applicationsPermitted = Predicates.<Bundle>alwaysTrue();
+
+                catalogItems = new CatalogBundleLoader(applicationsPermitted, mgmt).scanForCatalog(bundle);
+            } catch (RuntimeException ex) {
+                try {
+                    bundle.uninstall();
+                } catch (BundleException e) {
+                    log.error("Cannot uninstall bundle " + bundle.getSymbolicName() + ":" + bundle.getVersion(), e);
+                }
+                throw new IllegalArgumentException("Error installing catalog items", ex);
+            }
+        }
+        return catalogItems;
+    }
+    
     private void checkCorrectlyInstalled(OsgiBundleWithUrl bundle, Bundle b) {
         String nv = b.getSymbolicName()+":"+b.getVersion().toString();
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/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 89d5b3c..9bd4d21 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
@@ -524,7 +524,7 @@ public abstract class AbstractManagementContext implements ManagementContextInte
         result = getLocationManager().getLocation(id);
         if (result!=null && type.isInstance(result)) return (T)result;
 
-        // TODO policies, enrichers, feeds
+        // TODO policies, enrichers, feeds; bundles?
         return null;
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java
index ccc59b1..bdb6302 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/LocalManagementContext.java
@@ -69,7 +69,6 @@ import org.slf4j.LoggerFactory;
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
-import com.google.common.base.Optional;
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableSet;
 
@@ -217,21 +216,21 @@ public class LocalManagementContext extends AbstractManagementContext {
     }
     
     @Override
-    public Optional<String> getOptionalManagementPlaneId() {
-        return Optional.fromNullable(managementPlaneId);
+    public Maybe<String> getManagementPlaneIdMaybe() {
+        return Maybe.ofDisallowingNull(managementPlaneId);
     }
     
     public void setManagementPlaneId(String newPlaneId) {
         if (managementPlaneId != null && !managementPlaneId.equals(newPlaneId)) {
-            log.warn("Management plane ID changed from {} to {}", managementPlaneId, newPlaneId);
-            log.debug("Management plane ID changed from {} to {}", new Object[] {managementPlaneId, newPlaneId, new RuntimeException("Stack trace for setManagementPlaneId")});
+            log.warn("Management plane ID at {} {} changed from {} to {} (can happen on concurrent startup of multiple nodes)", new Object[] { managementNodeId, getHighAvailabilityManager().getNodeState(), managementPlaneId, newPlaneId });
+            log.debug("Management plane ID at {} {} changed from {} to {} (can happen on concurrent startup of multiple nodes)", new Object[] {managementNodeId, getHighAvailabilityManager().getNodeState(), managementPlaneId, newPlaneId, new RuntimeException("Stack trace for setManagementPlaneId")});
         }
         this.managementPlaneId = newPlaneId;
     }
 
     public void generateManagementPlaneId() {
         if (this.managementPlaneId != null) {
-            throw new IllegalStateException("Request to generate a management plane ID but one already exists (" + managementPlaneId + ")");
+            throw new IllegalStateException("Request to generate a management plane ID for node "+managementNodeId+" but one already exists (" + managementPlaneId + ")");
         }
         this.managementPlaneId = Strings.makeRandomId(8);
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java
index 10f49cd..4e14207 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/NonDeploymentManagementContext.java
@@ -76,7 +76,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Objects;
-import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
@@ -130,8 +129,8 @@ public class NonDeploymentManagementContext implements ManagementContextInternal
     }
     
     @Override
-    public Optional<String> getOptionalManagementPlaneId() {
-        return (initialManagementContext == null) ? Optional.<String>absent() : initialManagementContext.getOptionalManagementPlaneId();
+    public Maybe<String> getManagementPlaneIdMaybe() {
+        return (initialManagementContext == null) ? Maybe.<String>absent("Uninitialized non-deployment management context") : initialManagementContext.getManagementPlaneIdMaybe();
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java
index f0af9d1..142bcbc 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java
@@ -65,11 +65,9 @@ import org.apache.brooklyn.core.mgmt.rebind.dto.BrooklynMementoManifestImpl;
 import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
-import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.xstream.XmlUtil;
 import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
 import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.stream.Streams;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;
@@ -311,6 +309,11 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         Visitor loaderVisitor = new Visitor() {
             @Override
             public void visit(BrooklynObjectType type, String id, String contentsSubpath) throws Exception {
+                if (type == BrooklynObjectType.MANAGED_BUNDLE && id.endsWith(".jar")) {
+                    // don't visit jar files directly; someone else will read them
+                    return;
+                }
+                
                 String contents = null;
                 try {
                     contents = read(contentsSubpath);
@@ -325,9 +328,9 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
                     LOG.warn("ID mismatch on "+type.toCamelCase()+", "+id+" from path, "+safeXmlId+" from xml");
                 
                 if (type == BrooklynObjectType.MANAGED_BUNDLE) {
-                    // TODO write to temp file
-                    String jarData = read(contentsSubpath+".jar");
-                    builder.bundleJar(id, ByteSource.wrap(jarData.getBytes()));
+                    // TODO write to temp file, destroy when loaded
+                    byte[] jarData = readBytes(contentsSubpath+".jar");
+                    builder.bundleJar(id, ByteSource.wrap(jarData));
                 }
                 builder.put(type, xmlId, contents);
             }
@@ -669,7 +672,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         }
     }
 
-    private void addPersistContentIfManagedBundle(BrooklynObjectType type, String id, List<ListenableFuture<?>> futures, PersistenceExceptionHandler exceptionHandler) {
+    private void addPersistContentIfManagedBundle(final BrooklynObjectType type, final String id, List<ListenableFuture<?>> futures, final PersistenceExceptionHandler exceptionHandler) {
         if (type==BrooklynObjectType.MANAGED_BUNDLE) {
             if (mgmt==null) {
                 throw new IllegalStateException("Cannot persist bundles without a mangaement context");
@@ -677,26 +680,20 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             final ManagedBundle mb = ((ManagementContextInternal)mgmt).getOsgiManager().get().getManagedBundles().get(id);
             if (mb==null) {
                 LOG.warn("Cannot find managed bundle for added bundle "+id+"; ignoring");
-            }
-            if (mb.getUrl()==null) {
-                LOG.trace("No URL for managed bundle for bundle "+id+", so not persisting");
                 return;
             }
             
-            String jarContent = Streams.readFullyStringAndClose(new ResourceUtils("persist").getResourceFromUrl(mb.getUrl()));
-            
-            // erase the URL once persisted - this prevents it from re-persisting
-            // (could introduce multiple or a transient field instead?)
             if (mb instanceof BasicManagedBundle) {
                 final File f = ((BasicManagedBundle)mb).getTempLocalFileWhenJustUploaded();
+                // use the above transient field to know when to upload
                 if (f!=null) {
-                    futures.add(asyncPersist(type.getSubPathName(), type, id+".jar", jarContent, exceptionHandler));
-                    executor.submit(new Runnable() {
+                    futures.add( executor.submit(new Runnable() {
                         @Override
                         public void run() {
+                            persist(type.getSubPathName(), type, id+".jar", com.google.common.io.Files.asByteSource(f), exceptionHandler);
                             ((BasicManagedBundle)mb).setTempLocalFileWhenJustUploaded(null);
                             f.delete();
-                        }});
+                        } }) );
                 }
             }
         }
@@ -727,6 +724,11 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         return objectAccessor.get();
     }
 
+    private byte[] readBytes(String subPath) {
+        StoreObjectAccessor objectAccessor = objectStore.newAccessor(subPath);
+        return objectAccessor.getBytes();
+    }
+
     private void persist(String subPath, Memento memento, PersistenceExceptionHandler exceptionHandler) {
         try {
             getWriter(getPath(subPath, memento.getId())).put(getSerializerWithStandardClassLoader().toString(memento));
@@ -746,6 +748,14 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         }
     }
     
+    private void persist(String subPath, BrooklynObjectType type, String id, ByteSource content, PersistenceExceptionHandler exceptionHandler) {
+        try {
+            getWriter(getPath(subPath, id)).put(content);
+        } catch (Exception e) {
+            exceptionHandler.onPersistRawMementoFailed(type, id, e);
+        }
+    }
+    
     private void delete(String subPath, String id, PersistenceExceptionHandler exceptionHandler) {
         try {
             StoreObjectAccessorWithLock w = getWriter(getPath(subPath, id));

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynPersistenceUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynPersistenceUtils.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynPersistenceUtils.java
index c509208..b3e17c5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynPersistenceUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynPersistenceUtils.java
@@ -44,7 +44,6 @@ import org.apache.brooklyn.core.mgmt.ha.ManagementPlaneSyncRecordPersisterToObje
 import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
 import org.apache.brooklyn.core.mgmt.internal.LocalLocationManager;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.rebind.PersistenceExceptionHandlerImpl;
 import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer;
 import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformerLoader;
@@ -166,7 +165,7 @@ public class BrooklynPersistenceUtils {
         MementoSerializer<Object> rawSerializer = new XmlMementoSerializer<Object>(mgmt.getClass().getClassLoader());
         RetryingMementoSerializer<Object> serializer = new RetryingMementoSerializer<Object>(rawSerializer, 1);
         
-        result.planeId(mgmt.getOptionalManagementPlaneId().orNull());
+        result.planeId(mgmt.getManagementPlaneIdMaybe().orNull());
         for (Location instance: mgmt.getLocationManager().getLocations())
             result.location(instance.getId(), serializer.toString(newObjectMemento(instance)));
         for (Entity instance: mgmt.getEntityManager().getEntities()) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessor.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessor.java
index f061884..a9f0613 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessor.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/FileBasedStoreObjectAccessor.java
@@ -19,17 +19,20 @@
 package org.apache.brooklyn.core.mgmt.persist;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Date;
 
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.io.FileUtil;
+import org.apache.brooklyn.util.stream.Streams;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Charsets;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
+import com.google.common.io.ByteSource;
 import com.google.common.io.Files;
 
 /**
@@ -76,10 +79,14 @@ public class FileBasedStoreObjectAccessor implements PersistenceObjectStore.Stor
 
     @Override
     public void put(String val) {
+        put(ByteSource.wrap(val.getBytes(Charsets.UTF_8)));
+    }
+    
+    @Override
+    public void put(ByteSource bytes) {
         try {
-            if (val==null) val = "";
             FileUtil.setFilePermissionsTo600(tmpFile);
-            Files.write(val, tmpFile, Charsets.UTF_8);
+            Streams.copyClose(bytes.openStream(), new FileOutputStream(tmpFile));
             FileBasedObjectStore.moveFile(tmpFile, file);
         } catch (IOException e) {
             throw Exceptions.propagate("Problem writing data to file "+file+" (via temporary file "+tmpFile+")", e);
@@ -125,6 +132,6 @@ public class FileBasedStoreObjectAccessor implements PersistenceObjectStore.Stor
     
     @Override
     public String toString() {
-        return Objects.toStringHelper(this).add("file", file).toString();
+        return MoreObjects.toStringHelper(this).add("file", file).toString();
     }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/PersistenceObjectStore.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/PersistenceObjectStore.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/PersistenceObjectStore.java
index aa83e14..18a5b64 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/PersistenceObjectStore.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/PersistenceObjectStore.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;
+import com.google.common.io.ByteSource;
 
 /**
  * Interface for working with persistence targets, including file system and jclouds object stores.
@@ -42,6 +43,7 @@ public interface PersistenceObjectStore {
         byte[] getBytes();
         boolean exists();
         void put(String contentsToReplaceOrCreate);
+        void put(ByteSource bytes);
         void append(String contentsToAppendOrCreate);
         void delete();
         // NB: creation date is available for many blobstores but 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/StoreObjectAccessorLocking.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/StoreObjectAccessorLocking.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/StoreObjectAccessorLocking.java
index 302121f..49de188 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/StoreObjectAccessorLocking.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/StoreObjectAccessorLocking.java
@@ -32,6 +32,8 @@ import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.javalang.JavaClassNames;
 import org.apache.brooklyn.util.time.Duration;
 
+import com.google.common.io.ByteSource;
+
 /** Wraps access to an object (the delegate {@link StoreObjectAccessor} 
  * in a guarded read-write context such that callers will be blocked if another thread
  * is accessing the object in an incompatible way (e.g. trying to read when someone is writing).
@@ -146,6 +148,28 @@ public class StoreObjectAccessorLocking implements PersistenceObjectStore.StoreO
     }
     
     @Override
+    public void put(ByteSource val) {
+        try {
+            queuedWriters.add(Thread.currentThread());
+            lock.writeLock().lockInterruptibly();
+            try {
+                queuedWriters.remove(Thread.currentThread());
+                if (hasScheduledPutOrDeleteWithNoRead()) 
+                    // don't bother writing if someone will write after us and no one is reading
+                    return;
+                delegate.put(val);
+                
+            } finally {
+                lock.writeLock().unlock();
+            }
+        } catch (InterruptedException e) {
+            throw Exceptions.propagate(e);
+        } finally {
+            queuedWriters.remove(Thread.currentThread());
+        }
+    }
+    
+    @Override
     public void append(String val) {
         try {
             lock.writeLock().lockInterruptibly();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
index 16beb4e..1bded8b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializer.java
@@ -57,6 +57,7 @@ import org.apache.brooklyn.core.mgmt.rebind.dto.BasicEnricherMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicEntityMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicFeedMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicLocationMemento;
+import org.apache.brooklyn.core.mgmt.rebind.dto.BasicManagedBundleMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BasicPolicyMemento;
 import org.apache.brooklyn.core.mgmt.rebind.dto.MutableBrooklynMemento;
 import org.apache.brooklyn.core.sensor.BasicAttributeSensor;
@@ -102,9 +103,6 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
         this.delegatingClassLoader = new OsgiClassLoader(classLoader);
         xstream.setClassLoader(this.delegatingClassLoader);
         
-        // old (deprecated in 070? or earlier) single-file persistence uses this keyword; TODO remove soon in 080 ?
-        xstream.alias("brooklyn", MutableBrooklynMemento.class);
-        
         xstream.alias("entity", BasicEntityMemento.class);
         xstream.alias("location", BasicLocationMemento.class);
         xstream.alias("policy", BasicPolicyMemento.class);
@@ -112,6 +110,7 @@ public class XmlMementoSerializer<T> extends XmlSerializer<T> implements Memento
         xstream.alias("enricher", BasicEnricherMemento.class);
         xstream.alias("configKey", BasicConfigKey.class);
         xstream.alias("catalogItem", BasicCatalogItemMemento.class);
+        xstream.alias("managedBundle", BasicManagedBundleMemento.class);
         xstream.alias("bundle", CatalogBundleDto.class);
         xstream.alias("attributeSensor", BasicAttributeSensor.class);
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicManagedBundleRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicManagedBundleRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicManagedBundleRebindSupport.java
new file mode 100644
index 0000000..384fa65
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicManagedBundleRebindSupport.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.mgmt.rebind;
+
+import org.apache.brooklyn.api.mgmt.rebind.RebindContext;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.ManagedBundleMemento;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
+
+public class BasicManagedBundleRebindSupport extends AbstractBrooklynObjectRebindSupport<ManagedBundleMemento> {
+
+    public BasicManagedBundleRebindSupport(BasicManagedBundle mb) {
+        super(mb);
+    }
+
+    @Override
+    protected void addConfig(RebindContext rebindContext, ManagedBundleMemento memento) {
+        // no op
+    }
+
+    @Override
+    protected void addCustoms(RebindContext rebindContext, ManagedBundleMemento memento) {
+        // no op
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextImpl.java
index 262c4a1..cc301c9 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextImpl.java
@@ -49,6 +49,7 @@ public class RebindContextImpl implements RebindContext {
     private final Map<String, Enricher> enrichers = Maps.newLinkedHashMap();
     private final Map<String, Feed> feeds = Maps.newLinkedHashMap();
     private final Map<String, CatalogItem<?, ?>> catalogItems = Maps.newLinkedHashMap();
+    private final Map<String, ManagedBundle> bundles = Maps.newLinkedHashMap();
     
     private final ClassLoader classLoader;
     private final ManagementContext mgmt;
@@ -88,8 +89,12 @@ public class RebindContextImpl implements RebindContext {
         catalogItems.put(id, catalogItem);
     }
 
+    public void registerBundle(String id, ManagedBundle bundle) {
+        bundles.put(id, bundle);
+    }
+    
     public void installBundle(ManagedBundle bundle, InputStream zipInput) {
-        ((LocalManagementContext)mgmt).getOsgiManager().get().installUploadedBundle(bundle, zipInput);
+        ((LocalManagementContext)mgmt).getOsgiManager().get().installUploadedBundle(bundle, zipInput, true);
     }
     
     public void unregisterPolicy(Policy policy) {
@@ -108,6 +113,10 @@ public class RebindContextImpl implements RebindContext {
         catalogItems.remove(item.getId());
     }
 
+    public void unregisterBundle(ManagedBundle bundle) {
+        bundles.remove(bundle.getId());
+    }
+
     public void clearCatalogItems() {
         catalogItems.clear();
     }
@@ -128,12 +137,16 @@ public class RebindContextImpl implements RebindContext {
         return enrichers.get(id);
     }
 
+    public Feed getFeed(String id) {
+        return feeds.get(id);
+    }
+    
     public CatalogItem<?, ?> getCatalogItem(String id) {
         return catalogItems.get(id);
     }
 
-    public Feed getFeed(String id) {
-        return feeds.get(id);
+    public ManagedBundle getBundle(String id) {
+        return bundles.get(id);
     }
     
     @Override
@@ -170,6 +183,10 @@ public class RebindContextImpl implements RebindContext {
         return catalogItems.values();
     }
     
+    public Collection<ManagedBundle> getBundles() {
+        return bundles.values();
+    }
+
     @Override
     public Map<String,BrooklynObject> getAllBrooklynObjects() {
         MutableMap<String,BrooklynObject> result = MutableMap.of();
@@ -179,6 +196,7 @@ public class RebindContextImpl implements RebindContext {
         result.putAll(enrichers);
         result.putAll(feeds);
         result.putAll(catalogItems);
+        result.putAll(bundles);
         return result.asUnmodifiable();
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java
index eb55784..f463047 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindContextLookupContext.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.api.objs.BrooklynObjectType;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -129,6 +130,16 @@ public class RebindContextLookupContext implements LookupContext {
     }
     
     @Override
+    public ManagedBundle lookupBundle(String id) {
+        ManagedBundle result = rebindContext.getBundle(id);
+        if (result == null) {
+            // no need for managementContext.lookup(id, ManagedBundle.class);
+            result = exceptionHandler.onDanglingBundleRef(id);
+        }
+        return result;
+    }
+    
+    @Override
     public BrooklynObject lookup(BrooklynObjectType type, String id) {
         if (type==null) {
             BrooklynObject result = peek(null, id);
@@ -140,6 +151,7 @@ public class RebindContextLookupContext implements LookupContext {
         
         switch (type) {
         case CATALOG_ITEM: return lookupCatalogItem(id);
+        case MANAGED_BUNDLE: return lookupBundle(id);
         case ENRICHER: return lookupEnricher(id);
         case ENTITY: return lookupEntity(id);
         case FEED: return lookupFeed(id);
@@ -162,6 +174,7 @@ public class RebindContextLookupContext implements LookupContext {
         
         switch (type) {
         case CATALOG_ITEM: return rebindContext.getCatalogItem(id);
+        case MANAGED_BUNDLE: return rebindContext.getBundle(id);
         case ENRICHER: return rebindContext.getEnricher(id);
         case ENTITY: return rebindContext.getEntity(id);
         case FEED: return rebindContext.getFeed(id);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java
index 08a1eef..17d4073 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindExceptionHandlerImpl.java
@@ -38,6 +38,7 @@ import org.apache.brooklyn.api.objs.BrooklynObjectType;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.QuorumCheck;
@@ -247,7 +248,12 @@ public class RebindExceptionHandlerImpl implements RebindExceptionHandler {
     }
 
     @Override
-    public CatalogItem<?, ?> onDanglingUntypedItemRef(String id) {
+    public ManagedBundle onDanglingBundleRef(String id) {
+        return (ManagedBundle) onDanglingUntypedItemRef(id);
+    }
+
+    @Override
+    public BrooklynObject onDanglingUntypedItemRef(String id) {
         missingUntypedItems.add(id);
         if (danglingRefFailureMode == RebindManager.RebindFailureMode.FAIL_FAST) {
             throw new IllegalStateException("No item found with id "+id);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
index e12c796..92a87a7 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
@@ -499,7 +499,9 @@ public abstract class RebindIteration {
                 LOG.warn("Rebinding against existing persisted state, but no planeId found. Will generate a new one. " +
                         "Expected if this is the first rebind after upgrading to Brooklyn 0.12.0+");
             }
-            ((LocalManagementContext)managementContext).generateManagementPlaneId();
+            if (managementContext.getManagementPlaneIdMaybe().isAbsent()) {
+                ((LocalManagementContext)managementContext).generateManagementPlaneId();
+            }
         } else {
             ((LocalManagementContext)managementContext).setManagementPlaneId(persistedPlaneId);
         }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
index f7ee653..d605753 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindManagerImpl.java
@@ -175,7 +175,7 @@ public class RebindManagerImpl implements RebindManager {
     private class PlaneIdSupplier implements Supplier<String> {
         @Override
         public String get() {
-            return managementContext.getOptionalManagementPlaneId().orNull();
+            return managementContext.getManagementPlaneIdMaybe().orNull();
         }
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoImpl.java
index d6dd359..d60c8f3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoImpl.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.EnricherMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.FeedMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.LocationMemento;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.ManagedBundleMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.PolicyMemento;
 import org.apache.brooklyn.core.BrooklynVersion;
@@ -57,7 +58,7 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
         protected final Map<String, EnricherMemento> enrichers = Maps.newConcurrentMap();
         protected final Map<String, FeedMemento> feeds = Maps.newConcurrentMap();
         protected final Map<String, CatalogItemMemento> catalogItems = Maps.newConcurrentMap();
-
+        protected final Map<String, ManagedBundleMemento> bundles = Maps.newConcurrentMap();
         
         public Builder planeId(String val) {
             planeId = val; return this;
@@ -89,6 +90,8 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
                 feed((FeedMemento)memento);
             } else if (memento instanceof CatalogItemMemento) {
                 catalogItem((CatalogItemMemento) memento);
+            } else if (memento instanceof ManagedBundleMemento) {
+                bundle((ManagedBundleMemento) memento);
             } else {
                 throw new IllegalStateException("Unexpected memento type :"+memento);
             }
@@ -133,6 +136,9 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
         public Builder catalogItem(CatalogItemMemento val) {
             catalogItems.put(val.getId(), val); return this;
         }
+        public Builder bundle(ManagedBundleMemento val) {
+            bundles.put(val.getId(), val); return this;
+        }
         public BrooklynMemento build() {
             return new BrooklynMementoImpl(this);
         }
@@ -149,6 +155,7 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
     private Map<String, EnricherMemento> enrichers;
     private Map<String, FeedMemento> feeds;
     private Map<String, CatalogItemMemento> catalogItems;
+    private Map<String, ManagedBundleMemento> bundles;
     
     private BrooklynMementoImpl(Builder builder) {
         planeId = builder.planeId;
@@ -161,6 +168,7 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
         enrichers = builder.enrichers;
         feeds = builder.feeds;
         catalogItems = builder.catalogItems;
+        bundles = builder.bundles;
     }
 
     @Override
@@ -199,6 +207,11 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
     }
 
     @Override
+    public ManagedBundleMemento getManagedBundleMemento(String id) {
+        return bundles.get(id);
+    }
+
+    @Override
     public Collection<String> getApplicationIds() {
         return ImmutableList.copyOf(applicationIds);
     }
@@ -229,6 +242,11 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
     }
 
     @Override
+    public Collection<String> getManagedBundleIds() {
+        return Collections.unmodifiableSet(bundles.keySet());
+    }
+
+    @Override
     public Collection<String> getFeedIds() {
         return Collections.unmodifiableSet(feeds.keySet());
     }
@@ -266,4 +284,9 @@ public class BrooklynMementoImpl implements BrooklynMemento, Serializable {
     public Map<String, CatalogItemMemento> getCatalogItemMementos() {
         return Collections.unmodifiableMap(catalogItems);
     }
+
+    @Override
+    public Map<String, ManagedBundleMemento> getManagedBundleMementos() {
+        return Collections.unmodifiableMap(bundles);
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MutableBrooklynMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MutableBrooklynMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MutableBrooklynMemento.java
index 7dce070..a7dcbe9 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MutableBrooklynMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MutableBrooklynMemento.java
@@ -30,7 +30,11 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.EnricherMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.FeedMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.LocationMemento;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.ManagedBundleMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.PolicyMemento;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 import com.google.common.collect.ImmutableList;
@@ -48,7 +52,10 @@ import com.google.common.collect.Sets;
 public class MutableBrooklynMemento implements BrooklynMemento {
 
     // TODO Is this class pulling its weight? Do we really need it?
+    // (shouldn't be used anymore -- have added logging April 2017 to ensure not used)
 
+    private static final Logger log = LoggerFactory.getLogger(MutableBrooklynMemento.class);
+    
     private static final long serialVersionUID = -442895028005849060L;
     
     private String planeId;
@@ -60,7 +67,12 @@ public class MutableBrooklynMemento implements BrooklynMemento {
     private final Map<String, EnricherMemento> enrichers = Maps.newLinkedHashMap();
     private final Map<String, FeedMemento> feeds = Maps.newLinkedHashMap();
     private final Map<String, CatalogItemMemento> catalogItems = Maps.newLinkedHashMap();
+    private final Map<String, ManagedBundleMemento> bundles = Maps.newLinkedHashMap();
 
+    {
+        log.warn("Using legacy "+this, new Exception("location of use of legacy "+this));
+    }
+    
     public MutableBrooklynMemento() {
     }
     
@@ -301,4 +313,19 @@ public class MutableBrooklynMemento implements BrooklynMemento {
     public Map<String, CatalogItemMemento> getCatalogItemMementos() {
         return ImmutableMap.copyOf(catalogItems);
     }
+
+    @Override
+    public ManagedBundleMemento getManagedBundleMemento(String id) {
+        return null;
+    }
+
+    @Override
+    public Collection<String> getManagedBundleIds() {
+        return MutableList.of();
+    }
+
+    @Override
+    public Map<String, ManagedBundleMemento> getManagedBundleMementos() {
+        return bundles;
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java
index 9281e81..84cbdf3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java
+++ b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecFactory.java
@@ -22,10 +22,12 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+
 import org.apache.brooklyn.api.framework.FrameworkLookup;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer;
 import org.apache.brooklyn.core.typereg.TypePlanTransformers;
+import org.apache.brooklyn.core.typereg.UnsupportedTypePlanException;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
@@ -127,7 +129,7 @@ public class PlanToSpecFactory {
                     continue;
                 }
                 return Maybe.of(result);
-            } catch (PlanNotRecognizedException e) {
+            } catch (PlanNotRecognizedException|UnsupportedTypePlanException e) {
                 transformersWhoDontSupport.add(t.getShortDescription() +
                     (Strings.isNonBlank(e.getMessage()) ? " ("+e.getMessage()+")" : ""));
             } catch (Throwable e) {
@@ -144,7 +146,7 @@ public class PlanToSpecFactory {
             result = otherProblemsFromTransformers.size()==1 ? Exceptions.create(null, otherProblemsFromTransformers) :
                 Exceptions.create("All plan transformers failed", otherProblemsFromTransformers);
         } else {
-            result = new PlanNotRecognizedException("Invalid plan; format could not be recognized, trying with: "+transformersWhoDontSupport);
+            result = new UnsupportedTypePlanException("Invalid plan; format could not be recognized, trying with: "+transformersWhoDontSupport);
         }
         return Maybe.absent(result);
     }