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:02 UTC

[01/13] brooklyn-server git commit: bulk of structural additions to support persisting osgi bundles

Repository: brooklyn-server
Updated Branches:
  refs/heads/master d09b58f9f -> ce5ee7b86


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java
index 664ddfe..9bc8e94 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java
@@ -25,6 +25,7 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoManifest;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.CatalogItemMemento;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.ManagedBundleMemento;
 import org.apache.brooklyn.api.objs.BrooklynObjectType;
 
 import com.google.common.collect.Maps;
@@ -46,10 +47,12 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
         protected final Map<String, String> enricherIdToType = Maps.newConcurrentMap();
         protected final Map<String, String> feedIdToType = Maps.newConcurrentMap();
         protected final Map<String, CatalogItemMemento> catalogItems = Maps.newConcurrentMap();
+        protected final Map<String, ManagedBundleMemento> bundles = Maps.newConcurrentMap();
 
         public Builder planeId(String planeId) {
             this.planeId = planeId; return this;
         }
+
         /** @deprecated since 0.11.0; value is not used */
         @Deprecated
         public Builder brooklynVersion(String val) {
@@ -89,6 +92,12 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
         public Builder catalogItem(CatalogItemMemento val) {
             catalogItems.put(val.getId(), val); return this;
         }
+        public Builder bundles(Map<String, ManagedBundleMemento> vals) {
+            bundles.putAll(vals); return this;
+        }
+        public Builder bundle(ManagedBundleMemento val) {
+            bundles.put(val.getId(), val); return this;
+        }
 
         public Builder putType(BrooklynObjectType type, String id, String javaType) {
             switch (type) {
@@ -97,7 +106,9 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
             case POLICY: return policy(id, javaType);
             case ENRICHER: return enricher(id, javaType);
             case FEED: return feed(id, javaType);
-            case CATALOG_ITEM: throw new IllegalArgumentException(type.toCamelCase()+" requires different parameters");
+            case CATALOG_ITEM: 
+            case MANAGED_BUNDLE: 
+                throw new IllegalArgumentException(type.toCamelCase()+" requires different parameters");
             case UNKNOWN: 
             default: 
                 throw new IllegalArgumentException(type.toCamelCase()+" not supported");
@@ -116,6 +127,7 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
     private final Map<String, String> enricherIdToType;
     private final Map<String, String> feedIdToType;
     private Map<String, CatalogItemMemento> catalogItems;
+    private Map<String, ManagedBundleMemento> bundles; 
     
     private BrooklynMementoManifestImpl(Builder builder) {
         planeId = builder.planeId;
@@ -125,6 +137,7 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
         enricherIdToType = builder.enricherIdToType;
         feedIdToType = builder.feedIdToType;
         catalogItems = builder.catalogItems;
+        bundles = builder.bundles;
     }
 
     @Override
@@ -171,6 +184,21 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
     public Map<String, CatalogItemMemento> getCatalogItemMementos() {
         return Collections.unmodifiableMap(catalogItems);
     }
+    
+    @Override
+    public ManagedBundleMemento getBundle(String id) {
+        return bundles.get(id);
+    }
+
+    @Override
+    public Collection<String> getBundleIds() {
+        return Collections.unmodifiableSet(bundles.keySet());
+    }
+
+    @Override
+    public Map<String, ManagedBundleMemento> getBundles() {
+        return Collections.unmodifiableMap(bundles);
+    }
 
     @Override
     public boolean isEmpty() {
@@ -179,7 +207,8 @@ public class BrooklynMementoManifestImpl implements BrooklynMementoManifest, Ser
                 policyIdToType.isEmpty() &&
                 enricherIdToType.isEmpty() &&
                 feedIdToType.isEmpty() &&
-                catalogItems.isEmpty();
+                catalogItems.isEmpty() &&
+                bundles.isEmpty();
     }
     
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
index da54080..fbf24b8 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
@@ -38,6 +38,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.api.objs.BrooklynObject;
@@ -48,6 +49,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.AttributeSensor.SensorPersistenceMode;
 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.core.catalog.internal.CatalogItemDo;
 import org.apache.brooklyn.core.enricher.AbstractEnricher;
@@ -111,6 +113,8 @@ public class MementosGenerators {
             return newFeedMemento((Feed)instance);
         } else if (instance instanceof CatalogItem) {
             return newCatalogItemMemento((CatalogItem<?,?>) instance);
+        } else if (instance instanceof ManagedBundle) {
+            return newManagedBundleMemento((ManagedBundle) instance);
         } else {
             throw new IllegalArgumentException("Unexpected brooklyn type: "+(instance == null ? "null" : instance.getClass())+" ("+instance+")");
         }
@@ -442,6 +446,15 @@ public class MementosGenerators {
         return builder.build();
     }
     
+    private static ManagedBundleMemento newManagedBundleMemento(ManagedBundle bundle) {
+        BasicManagedBundleMemento.Builder builder = BasicManagedBundleMemento.builder();
+        populateBrooklynObjectMementoBuilder(bundle, builder);
+        builder.url(bundle.getUrl())
+            .symbolicName(bundle.getSymbolicName())
+            .version(bundle.getVersion());
+        return builder.build();
+    }
+    
     private static void populateBrooklynObjectMementoBuilder(BrooklynObject instance, AbstractMemento.Builder<?> builder) {
         if (Proxy.isProxyClass(instance.getClass())) {
             throw new IllegalStateException("Attempt to create memento from proxy "+instance+" (would fail with wrong type)");

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java
index 74b8bb0..ce4a2bf 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java
@@ -246,6 +246,7 @@ public class CompoundTransformer {
         Map<String, String> enrichers = MutableMap.copyOf(rawData.getEnrichers());
         Map<String, String> feeds = MutableMap.copyOf(rawData.getFeeds());
         Map<String, String> catalogItems = MutableMap.copyOf(rawData.getCatalogItems());
+        Map<String, String> bundles = MutableMap.copyOf(rawData.getBundles());
 
         // TODO @neykov asks whether transformers should be run in registration order,
         // rather than in type order.  TBD.  (would be an easy change.)
@@ -303,6 +304,14 @@ public class CompoundTransformer {
                 }
                 catalogItems.keySet().removeAll(itemsToDelete);
                 break;
+            case MANAGED_BUNDLE:
+                missing = Sets.difference(itemsToDelete, bundles.keySet());
+                if (missing.size() > 0) {
+                    LOG.warn("Unable to delete " + type + " id"+Strings.s(missing.size())+" ("+missing+"), "
+                            + "because not found in persisted state (continuing)");
+                }
+                bundles.keySet().removeAll(itemsToDelete);
+                break;
             case UNKNOWN:
                 break; // no-op
             default:
@@ -344,6 +353,11 @@ public class CompoundTransformer {
                             entry.setValue(transformer.transform(entry.getValue()));
                         }
                         break;
+                    case MANAGED_BUNDLE:
+                        for (Map.Entry<String, String> entry : bundles.entrySet()) {
+                            entry.setValue(transformer.transform(entry.getValue()));
+                        }
+                        break;
                     case UNKNOWN:
                         break; // no-op
                     default:
@@ -360,6 +374,7 @@ public class CompoundTransformer {
                 .enrichers(enrichers)
                 .feeds(feeds)
                 .catalogItems(catalogItems)
+                .bundles(bundles)
                 .build();
     }
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
index f7df463..0c2c87b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicBrooklynTypeRegistry.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.api.typereg.RegisteredType.TypeImplementationPlan;
 import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemBuilder;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
@@ -48,6 +49,7 @@ import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 
 public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry {
@@ -55,6 +57,7 @@ public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry {
     private static final Logger log = LoggerFactory.getLogger(BasicBrooklynTypeRegistry.class);
     
     private ManagementContext mgmt;
+    private Map<String,ManagedBundle> uploadedBundles = MutableMap.of();
     private Map<String,RegisteredType> localRegisteredTypes = MutableMap.of();
 
     public BasicBrooklynTypeRegistry(ManagementContext mgmt) {
@@ -321,4 +324,5 @@ public class BasicBrooklynTypeRegistry implements BrooklynTypeRegistry {
             throw new IllegalStateException("Cannot add "+type+" to catalog; different "+oldType+" is already present");
         }
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
new file mode 100644
index 0000000..4223e79
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
@@ -0,0 +1,150 @@
+/*
+ * 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.typereg;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
+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.objs.AbstractBrooklynObject;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
+
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+
+public class BasicManagedBundle extends AbstractBrooklynObject implements ManagedBundle, BrooklynObjectInternal {
+
+    private String symbolicName;
+    private String version;
+    private String url;
+
+    // for deserializing (not sure if needed?)
+    @SuppressWarnings("unused")
+    private BasicManagedBundle() {}
+
+    public BasicManagedBundle(String name, String version, String url) {
+        if (name == null && version == null) {
+            Preconditions.checkNotNull(url, "Either a URL or both name and version are required");
+        } else {
+            Preconditions.checkNotNull(name, "Either a URL or both name and version are required");
+            Preconditions.checkNotNull(version, "Either a URL or both name and version are required");
+        }
+
+        this.symbolicName = name;
+        this.version = version;
+        this.url = url;
+    }
+    
+    @Override
+    public boolean isNameResolved() {
+        return symbolicName != null && version != null;
+    }
+    
+    @Override
+    public String getSymbolicName() {
+        return symbolicName;
+    }
+
+    @Override
+    public String getVersion() {
+        return version;
+    }
+
+    @Override
+    public String getUrl() {
+        return url;
+    }
+
+    @Override
+    public String getOsgiUniqueUrl() {
+        return "brooklyn:"+getId();
+    }
+    
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("symbolicName", symbolicName)
+                .add("version", version)
+                .add("url", url)
+                .toString();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(symbolicName, version, url);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        OsgiBundleWithUrl other = (OsgiBundleWithUrl) obj;
+        if (!Objects.equal(symbolicName, other.getSymbolicName())) return false;
+        if (!Objects.equal(version, other.getVersion())) return false;
+        if (!Objects.equal(url, other.getUrl())) return false;
+        return true;
+    }
+
+    // ---
+    
+    @Override
+    public String getDisplayName() {
+        return null;
+    }
+
+    @Override
+    public <T> T setConfig(ConfigKey<T> key, T val) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public <T> T getConfig(ConfigKey<T> key) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public RebindSupport<?> getRebindSupport() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ConfigurationSupportInternal config() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SubscriptionSupportInternal subscriptions() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setDisplayName(String newName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected BrooklynObjectInternal configure(Map<?, ?> flags) {
+        throw new UnsupportedOperationException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/typereg/BasicOsgiBundleWithUrl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicOsgiBundleWithUrl.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicOsgiBundleWithUrl.java
index 1c8cc40..5db9820 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicOsgiBundleWithUrl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicOsgiBundleWithUrl.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.core.typereg;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
 import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
 
@@ -35,16 +36,20 @@ public class BasicOsgiBundleWithUrl implements CatalogBundle, OsgiBundleWithUrl
 
     public BasicOsgiBundleWithUrl(String name, String version, String url) {
         if (name == null && version == null) {
-            Preconditions.checkNotNull(url, "url to an OSGi bundle is required");
+            Preconditions.checkNotNull(url, "Either a URL or both name and version are required");
         } else {
-            Preconditions.checkNotNull(name, "both name and version are required");
-            Preconditions.checkNotNull(version, "both name and version are required");
+            Preconditions.checkNotNull(name, "Either a URL or both name and version are required");
+            Preconditions.checkNotNull(version, "Either a URL or both name and version are required");
         }
 
         this.symbolicName = name;
         this.version = version;
         this.url = url;
     }
+    
+    public BasicOsgiBundleWithUrl(OsgiBundleWithUrl b) {
+        this(b.getSymbolicName(), b.getVersion(), b.getUrl());
+    }
 
     @Override
     public boolean isNameResolved() {
@@ -74,7 +79,7 @@ public class BasicOsgiBundleWithUrl implements CatalogBundle, OsgiBundleWithUrl
 
     @Override
     public String toString() {
-        return Objects.toStringHelper(this)
+        return MoreObjects.toStringHelper(this)
                 .add("symbolicName", symbolicName)
                 .add("version", version)
                 .add("url", url)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
index 29ea68b..4e18336 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
@@ -537,7 +537,7 @@ public class RebindTestUtils {
             BrooklynMementoRawData data = persister.loadMementoRawData(RebindExceptionHandlerImpl.builder().build());
             List<BrooklynObjectType> types = ImmutableList.of(BrooklynObjectType.ENTITY, BrooklynObjectType.LOCATION, 
                     BrooklynObjectType.POLICY, BrooklynObjectType.ENRICHER, BrooklynObjectType.FEED, 
-                    BrooklynObjectType.CATALOG_ITEM);
+                    BrooklynObjectType.CATALOG_ITEM, BrooklynObjectType.MANAGED_BUNDLE);
             for (BrooklynObjectType type : types) {
                 LOG.info(type+" ("+data.getObjectsOfType(type).keySet()+"):");
                 for (Map.Entry<String, String> entry : data.getObjectsOfType(type).entrySet()) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java
index b94970d..e012ac4 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RecordingRebindExceptionHandler.java
@@ -69,7 +69,7 @@ public class RecordingRebindExceptionHandler extends RebindExceptionHandlerImpl
 
     @Override
     public void onCreateFailed(BrooklynObjectType type, String id, String instanceType, Exception e) {
-        createFailures.put(id, new IllegalStateException("problem creating location "+id+" of type "+instanceType, e));
+        createFailures.put(id, new IllegalStateException("problem creating "+type+" "+id+" of type "+instanceType, e));
         super.onCreateFailed(type, id, instanceType, e);
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractCleanOrphanedStateTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractCleanOrphanedStateTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractCleanOrphanedStateTest.java
index b64f291..9cac744 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractCleanOrphanedStateTest.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractCleanOrphanedStateTest.java
@@ -55,6 +55,7 @@ public abstract class AbstractCleanOrphanedStateTest extends RebindTestFixtureWi
                     .planeId(input.getPlaneId())
                     .brooklynVersion(input.getBrooklynVersion())
                     .catalogItems(input.getCatalogItems())
+                    .bundles(input.getBundles())
                     .entities(MutableMap.<String, String>builder().putAll(input.getEntities()).removeAll(deletions.entities).build())
                     .locations(MutableMap.<String, String>builder().putAll(input.getLocations()).removeAll(deletions.locations).build())
                     .feeds(MutableMap.<String, String>builder().putAll(input.getFeeds()).removeAll(deletions.feeds).build())


[02/13] brooklyn-server git commit: bulk of structural additions to support persisting osgi bundles

Posted by ge...@apache.org.
bulk of structural additions to support persisting osgi bundles

not yet actually writing or reading bundle zip data, nor installing them, but saving metadata, and clear now where to add the binary zip data


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

Branch: refs/heads/master
Commit: fbe99f1f814c3442f7ffec644d1d1eea023ceef6
Parents: eb4992e
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Wed Apr 19 19:11:56 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Apr 21 12:45:34 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/api/entity/Entity.java  |   8 +-
 .../mementos/BrooklynMementoManifest.java       |   7 +-
 .../mementos/BrooklynMementoPersister.java      |   2 +
 .../rebind/mementos/BrooklynMementoRawData.java |  38 ++++-
 .../rebind/mementos/CatalogItemMemento.java     |   1 +
 .../rebind/mementos/ManagedBundleMemento.java   |  32 ++++
 .../brooklyn/api/objs/BrooklynObjectType.java   |   4 +-
 .../api/typereg/BrooklynTypeRegistry.java       |   2 +-
 .../brooklyn/api/typereg/ManagedBundle.java     |  29 ++++
 .../brooklyn/api/typereg/OsgiBundleWithUrl.java |   2 +-
 .../core/BrooklynFeatureEnablement.java         |   2 +
 .../brooklyn/core/entity/AbstractEntity.java    |   8 +-
 .../brooklyn/core/mgmt/ha/OsgiManager.java      |  44 ++++--
 .../BrooklynMementoPersisterToObjectStore.java  |  18 ++-
 .../mgmt/persist/BrooklynPersistenceUtils.java  |  28 +++-
 .../AbstractBrooklynObjectRebindSupport.java    |   1 -
 .../rebind/ActivePartialRebindIteration.java    |  19 +--
 .../rebind/ImmediateDeltaChangeListener.java    |  11 +-
 .../rebind/PeriodicDeltaChangeListener.java     |  33 ++--
 .../core/mgmt/rebind/PersisterDeltaImpl.java    |  21 ++-
 .../core/mgmt/rebind/RebindContextImpl.java     |   8 +-
 .../mgmt/rebind/RebindExceptionHandlerImpl.java |   8 +-
 .../core/mgmt/rebind/RebindIteration.java       |  35 ++++-
 .../core/mgmt/rebind/RebindManagerImpl.java     |   2 +
 .../core/mgmt/rebind/dto/AbstractMemento.java   |   6 +-
 .../rebind/dto/AbstractTreeNodeMemento.java     |   4 +-
 .../rebind/dto/BasicCatalogItemMemento.java     |   4 +-
 .../mgmt/rebind/dto/BasicEnricherMemento.java   |   4 +-
 .../mgmt/rebind/dto/BasicEntityMemento.java     |   4 +-
 .../core/mgmt/rebind/dto/BasicFeedMemento.java  |   4 +-
 .../mgmt/rebind/dto/BasicLocationMemento.java   |   4 +-
 .../rebind/dto/BasicManagedBundleMemento.java   | 130 ++++++++++++++++
 .../mgmt/rebind/dto/BasicPolicyMemento.java     |   4 +-
 .../rebind/dto/BrooklynMementoManifestImpl.java |  33 +++-
 .../mgmt/rebind/dto/MementosGenerators.java     |  13 ++
 .../rebind/transformer/CompoundTransformer.java |  15 ++
 .../core/typereg/BasicBrooklynTypeRegistry.java |   4 +
 .../core/typereg/BasicManagedBundle.java        | 150 +++++++++++++++++++
 .../core/typereg/BasicOsgiBundleWithUrl.java    |  13 +-
 .../core/mgmt/rebind/RebindTestUtils.java       |   2 +-
 .../rebind/RecordingRebindExceptionHandler.java |   2 +-
 .../AbstractCleanOrphanedStateTest.java         |   1 +
 42 files changed, 668 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
index d67d06c..b8e13b7 100644
--- a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.api.entity;
 
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import javax.annotation.Nullable;
@@ -160,7 +161,7 @@ public interface Entity extends BrooklynObject {
     /**
      * @return an immutable thread-safe view of the policies.
      * 
-     * @deprecated since 0.9.0; see {@link PolicySupport#getPolicies()}
+     * @deprecated since 0.9.0; see {@link PolicySupport#asList()}
      */
     @Deprecated
     Collection<Policy> getPolicies();
@@ -168,7 +169,7 @@ public interface Entity extends BrooklynObject {
     /**
      * @return an immutable thread-safe view of the enrichers.
      * 
-     * @deprecated since 0.9.0; see {@link EnricherSupport#getEnrichers()}
+     * @deprecated since 0.9.0; see {@link EnricherSupport#asList()}
      */
     @Deprecated
     Collection<Enricher> getEnrichers();
@@ -178,7 +179,7 @@ public interface Entity extends BrooklynObject {
      *
      * Groupings can be used to allow easy management/monitoring of a group of entities.
      * 
-     * @deprecated since 0.9.0; see {@link GroupSupport#getGroups()} and {@link #groups()}
+     * @deprecated since 0.9.0; see {@link #groups()} and {@link GroupSupport#iterator()}
      */
     @Deprecated
     Collection<Group> getGroups();
@@ -349,6 +350,7 @@ public interface Entity extends BrooklynObject {
         
         int size();
         boolean isEmpty();
+        List<T> asList();
         
         /**
          * Adds an instance.

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java
index a96601f..97fd91a 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java
@@ -51,11 +51,14 @@ public interface BrooklynMementoManifest extends Serializable {
     public Map<String, String> getFeedIdToType();
     
     public CatalogItemMemento getCatalogItemMemento(String id);
-
     public Collection<String> getCatalogItemIds();
-
     public Map<String, CatalogItemMemento> getCatalogItemMementos();
 
+    public ManagedBundleMemento getBundle(String id);
+    /** returns UID not symbolic name + version */
+    public Collection<String> getBundleIds();
+    public Map<String, ManagedBundleMemento> getBundles();
+
     public boolean isEmpty();
     
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/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 c2cdae3..f600418 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
@@ -118,6 +118,7 @@ public interface BrooklynMementoPersister {
         Collection<EnricherMemento> enrichers();
         Collection<FeedMemento> feeds();
         Collection<CatalogItemMemento> catalogItems();
+        Collection<ManagedBundleMemento> bundles();
         
         Collection<String> removedLocationIds();
         Collection<String> removedEntityIds();
@@ -125,6 +126,7 @@ public interface BrooklynMementoPersister {
         Collection<String> removedEnricherIds();
         Collection<String> removedFeedIds();
         Collection<String> removedCatalogItemIds();
+        Collection<String> removedBundleIds();
         
         Collection<? extends Memento> getObjectsOfType(BrooklynObjectType type);
         Collection<String> getRemovedIdsOfType(BrooklynObjectType type);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java
index 9df4bb6..cdebb8c 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoRawData.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.objs.BrooklynObjectType;
 
 import com.google.common.annotations.Beta;
 import com.google.common.collect.Maps;
+import com.google.common.io.ByteSource;
 
 /**
  * Represents the raw persisted data.
@@ -50,10 +51,13 @@ public class BrooklynMementoRawData {
         protected final Map<String, String> enrichers = Maps.newConcurrentMap();
         protected final Map<String, String> feeds = Maps.newConcurrentMap();
         protected final Map<String, String> catalogItems = Maps.newConcurrentMap();
+        protected final Map<String, String> bundles = Maps.newConcurrentMap();
+        protected final Map<String, ByteSource> bundleJars = Maps.newConcurrentMap();
 
         public Builder planeId(String val) {
             planeId = val; return this;
         }
+
         /** @deprecated since 0.11.0; value not used */
         @Deprecated
         public Builder brooklynVersion(String val) {
@@ -95,6 +99,19 @@ public class BrooklynMementoRawData {
         public Builder catalogItems(Map<String, String> vals) {
             catalogItems.putAll(vals); return this;
         }
+        public Builder bundle(String id, String val) {
+            bundles.put(id, val); return this;
+        }
+        public Builder bundles(Map<String, String> vals) {
+            bundles.putAll(vals); return this;
+        }
+        // extra call needed to store jar source
+        public Builder bundleJar(String id, ByteSource val) {
+            bundleJars.put(id, val); return this;
+        }
+        public Builder bundleJars(Map<String, ByteSource> vals) {
+            bundleJars.putAll(vals); return this;
+        }
         
         public Builder put(BrooklynObjectType type, String id, String val) {
             switch (type) {
@@ -104,6 +121,7 @@ public class BrooklynMementoRawData {
             case ENRICHER: return enricher(id, val);
             case FEED: return feed(id, val);
             case CATALOG_ITEM: return catalogItem(id, val);
+            case MANAGED_BUNDLE: return bundle(id, val);
             case UNKNOWN:
             default:
                 throw new IllegalArgumentException(type+" not supported");
@@ -117,12 +135,13 @@ public class BrooklynMementoRawData {
             case ENRICHER: return enrichers(vals);
             case FEED: return feeds(vals);
             case CATALOG_ITEM: return catalogItems(vals);
+            case MANAGED_BUNDLE: return bundles(vals);
             case UNKNOWN:
             default:
                 throw new IllegalArgumentException(type+" not supported");
             }
         }
-
+        
         public BrooklynMementoRawData build() {
             return new BrooklynMementoRawData(this);
         }
@@ -136,6 +155,8 @@ public class BrooklynMementoRawData {
     private final Map<String, String> enrichers;
     private final Map<String, String> feeds;
     private final Map<String, String> catalogItems;
+    private final Map<String, String> bundles;
+    private final Map<String, ByteSource> bundleJars;
     
     private BrooklynMementoRawData(Builder builder) {
         planeId = builder.planeId;
@@ -146,6 +167,8 @@ public class BrooklynMementoRawData {
         enrichers = builder.enrichers;
         feeds = builder.feeds;
         catalogItems = builder.catalogItems;
+        bundles = builder.bundles;
+        bundleJars = builder.bundleJars;
     }
 
     @Nullable
@@ -188,6 +211,14 @@ public class BrooklynMementoRawData {
         return Collections.unmodifiableMap(catalogItems);
     }
     
+    public Map<String, String> getBundles() {
+        return Collections.unmodifiableMap(bundles);
+    }
+    
+    public Map<String, ByteSource> getBundleJars() {
+        return Collections.unmodifiableMap(bundleJars);
+    }
+    
     // to handle reset catalog
     @Beta
     public void clearCatalogItems() {
@@ -195,7 +226,7 @@ public class BrooklynMementoRawData {
     }
     
     public boolean isEmpty() {
-        return planeId == null && entities.isEmpty() && locations.isEmpty() && policies.isEmpty() && enrichers.isEmpty() && feeds.isEmpty() && catalogItems.isEmpty();
+        return planeId == null && entities.isEmpty() && locations.isEmpty() && policies.isEmpty() && enrichers.isEmpty() && feeds.isEmpty() && catalogItems.isEmpty() && bundles.isEmpty();
     }
     
     public Map<String, String> getObjectsOfType(BrooklynObjectType type) {
@@ -206,8 +237,11 @@ public class BrooklynMementoRawData {
         case ENRICHER: return getEnrichers();
         case FEED: return getFeeds();
         case CATALOG_ITEM: return getCatalogItems();
+        case MANAGED_BUNDLE: return getBundles();
+        case UNKNOWN:
         default:
             throw new IllegalArgumentException("Type "+type+" not supported");
         }
     }
+
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java
index 57fbb8d..0ab7bc8 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java
@@ -51,4 +51,5 @@ public interface CatalogItemMemento extends Memento {
     boolean isDeprecated();
 
     boolean isDisabled();
+    
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/ManagedBundleMemento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/ManagedBundleMemento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/ManagedBundleMemento.java
new file mode 100644
index 0000000..f2ec818
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/ManagedBundleMemento.java
@@ -0,0 +1,32 @@
+/*
+ * 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.api.mgmt.rebind.mementos;
+
+import com.google.common.io.ByteSource;
+
+public interface ManagedBundleMemento extends Memento {
+
+    String getSymbolicName();
+    String getVersion();
+
+    String getUrl();
+    
+    ByteSource getJarContent();
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java
index e0ef84c..1fabaf2 100644
--- a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java
+++ b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java
@@ -29,19 +29,21 @@ import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.CaseFormat;
 
 @Beta
 public enum BrooklynObjectType {
-    // these are correctly type-checked by i can't tell how to get java not to warn!
+    // these are correctly type-checked but i can't tell how to get java not to warn!
     @SuppressWarnings("unchecked") ENTITY(Entity.class, EntitySpec.class, "entities"),
     @SuppressWarnings("unchecked") LOCATION(Location.class, LocationSpec.class, "locations"),
     @SuppressWarnings("unchecked") POLICY(Policy.class, PolicySpec.class, "policies"),
     @SuppressWarnings("unchecked") ENRICHER(Enricher.class, EnricherSpec.class, "enrichers"),
     FEED(Feed.class, null, "feeds"),
     CATALOG_ITEM(CatalogItem.class, null, "catalog"),
+    MANAGED_BUNDLE(ManagedBundle.class, null, "bundle"),
     UNKNOWN(null, null, "unknown");
     
     private final Class<? extends BrooklynObject> interfaceType;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java b/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java
index ae26ac1..5b15c75 100644
--- a/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java
+++ b/api/src/main/java/org/apache/brooklyn/api/typereg/BrooklynTypeRegistry.java
@@ -85,5 +85,5 @@ public interface BrooklynTypeRegistry {
     @Beta
     /** Typesafe non-spec variant of {@link #createFromPlan(Class, String, Object, RegisteredTypeLoadingContext)} */
     <T> T createBeanFromPlan(String planFormat, Object planData, @Nullable RegisteredTypeLoadingContext optionalConstraint, @Nullable Class<T> optionalBeanSuperType);
-
+    
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java b/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java
new file mode 100644
index 0000000..9fe7e8a
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.api.typereg;
+
+import org.apache.brooklyn.api.mgmt.rebind.Rebindable;
+import org.apache.brooklyn.api.objs.BrooklynObject;
+
+/** Describes an OSGi bundle which Brooklyn manages, including persisting */
+public interface ManagedBundle extends BrooklynObject, Rebindable, OsgiBundleWithUrl {
+
+    String getOsgiUniqueUrl();
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/api/src/main/java/org/apache/brooklyn/api/typereg/OsgiBundleWithUrl.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/typereg/OsgiBundleWithUrl.java b/api/src/main/java/org/apache/brooklyn/api/typereg/OsgiBundleWithUrl.java
index e8b278b..b17b993 100644
--- a/api/src/main/java/org/apache/brooklyn/api/typereg/OsgiBundleWithUrl.java
+++ b/api/src/main/java/org/apache/brooklyn/api/typereg/OsgiBundleWithUrl.java
@@ -26,7 +26,7 @@ public interface OsgiBundleWithUrl {
     public String getSymbolicName();
     public String getVersion();
     
-    /** where this bundle can be downloaded; typically required unless we are guaranteed the bundle will be manually installed */
+    /** where this bundle can be downloaded; typically required unless we are guaranteed the bundle will be manually installed or handled by persistence */
     public String getUrl();
     
     /** @return true if we have a name and version for this bundle;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java b/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
index 4008b39..466fe88 100644
--- a/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
+++ b/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
@@ -63,6 +63,7 @@ public class BrooklynFeatureEnablement {
 
     public static final String FEATURE_CORS_CXF_PROPERTY = FEATURE_PROPERTY_PREFIX + ".corsCxfFeature";
 
+    public static final String FEATURE_BUNDLE_PERSISTENCE_PROPERTY = FEATURE_PROPERTY_PREFIX+".bundlePersistence";
     public static final String FEATURE_CATALOG_PERSISTENCE_PROPERTY = FEATURE_PROPERTY_PREFIX+".catalogPersistence";
     
     /** whether the default standby mode is {@link HighAvailabilityMode#HOT_STANDBY} or falling back to the traditional
@@ -155,6 +156,7 @@ public class BrooklynFeatureEnablement {
         setDefault(FEATURE_ENRICHER_PERSISTENCE_PROPERTY, true);
         setDefault(FEATURE_FEED_PERSISTENCE_PROPERTY, true);
         setDefault(FEATURE_FEED_REGISTRATION_PROPERTY, false);
+        setDefault(FEATURE_BUNDLE_PERSISTENCE_PROPERTY, true);
         setDefault(FEATURE_CATALOG_PERSISTENCE_PROPERTY, true);
         setDefault(FEATURE_DEFAULT_STANDBY_IS_HOT_PROPERTY, false);
         setDefault(FEATURE_USE_BROOKLYN_LIVE_OBJECTS_DATAGRID_STORAGE, false);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
index c930ac2..bbc57ec 100644
--- a/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
+++ b/core/src/main/java/org/apache/brooklyn/core/entity/AbstractEntity.java
@@ -1598,8 +1598,8 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
         public boolean isEmpty() {
             return policiesInternal.isEmpty();
         }
-        
-        protected List<Policy> asList() {
+        @Override
+        public List<Policy> asList() {
             return ImmutableList.<Policy>copyOf(policiesInternal);
         }
 
@@ -1670,8 +1670,8 @@ public abstract class AbstractEntity extends AbstractBrooklynObject implements E
         public boolean isEmpty() {
             return enrichersInternal.isEmpty();
         }
-        
-        protected List<Enricher> asList() {
+        @Override
+        public List<Enricher> asList() {
             return ImmutableList.<Enricher>copyOf(enrichersInternal);
         }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/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 7e68a31..c64a131 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
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.core.mgmt.ha;
 
 import java.io.File;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.Arrays;
 import java.util.Collections;
@@ -31,6 +32,7 @@ import java.util.concurrent.atomic.AtomicReference;
 
 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.BrooklynVersion;
@@ -56,6 +58,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 
@@ -71,6 +74,7 @@ public class OsgiManager {
     protected final OsgiClassPrefixer osgiClassPrefixer;
     protected Framework framework;
     protected File osgiCacheDir;
+    protected Map<String, ManagedBundle> managedBundles = MutableMap.of();
     
     public OsgiManager(ManagementContext mgmt) {
         this.mgmt = mgmt;
@@ -113,22 +117,44 @@ public class OsgiManager {
         framework = null;
     }
 
-    public synchronized void registerBundle(CatalogBundle bundle) {
+    public Map<String, ManagedBundle> getManagedBundles() {
+        return ImmutableMap.copyOf(managedBundles);
+    }
+    
+    public void installUploadedBundle(ManagedBundle bundleMetadata, InputStream zip) {
         try {
-            if (checkBundleInstalledThrowIfInconsistent(bundle)) {
+            if (checkBundleInstalledThrowIfInconsistent(bundleMetadata)) {
                 return;
             }
 
-            Bundle b = Osgis.install(framework, bundle.getUrl());
+            Bundle bundleInstalled = framework.getBundleContext().installBundle(bundleMetadata.getOsgiUniqueUrl(), zip);
+            checkCorrectlyInstalled(bundleMetadata, bundleInstalled);
+            
+            synchronized (managedBundles) {
+                managedBundles.put(bundleMetadata.getId(), bundleMetadata);
+            }
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            throw new IllegalStateException("Bundle "+bundleMetadata+" failed to install: " + e.getMessage(), e);
+        }
+    }
+    
+    public synchronized void registerBundle(CatalogBundle bundleMetadata) {
+        try {
+            if (checkBundleInstalledThrowIfInconsistent(bundleMetadata)) {
+                return;
+            }
 
-            checkCorrectlyInstalled(bundle, b);
+            Bundle bundleInstalled = Osgis.install(framework, bundleMetadata.getUrl());
+
+            checkCorrectlyInstalled(bundleMetadata, bundleInstalled);
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
-            throw new IllegalStateException("Bundle from "+bundle.getUrl()+" failed to install: " + e.getMessage(), e);
+            throw new IllegalStateException("Bundle from "+bundleMetadata.getUrl()+" failed to install: " + e.getMessage(), e);
         }
     }
 
-    private void checkCorrectlyInstalled(CatalogBundle bundle, Bundle b) {
+    private void checkCorrectlyInstalled(OsgiBundleWithUrl bundle, Bundle b) {
         String nv = b.getSymbolicName()+":"+b.getVersion().toString();
 
         if (!isBundleNameEqualOrAbsent(bundle, b)) {
@@ -151,7 +177,7 @@ public class OsgiManager {
         }
     }
 
-    private boolean checkBundleInstalledThrowIfInconsistent(CatalogBundle bundle) {
+    private boolean checkBundleInstalledThrowIfInconsistent(OsgiBundleWithUrl bundle) {
         String bundleUrl = bundle.getUrl();
         if (bundleUrl != null) {
             Maybe<Bundle> installedBundle = Osgis.bundleFinder(framework).requiringFromUrl(bundleUrl).find();
@@ -177,7 +203,7 @@ public class OsgiManager {
         return false;
     }
 
-    public static boolean isBundleNameEqualOrAbsent(CatalogBundle bundle, Bundle b) {
+    public static boolean isBundleNameEqualOrAbsent(OsgiBundleWithUrl bundle, Bundle b) {
         return !bundle.isNameResolved() ||
                 (bundle.getSymbolicName().equals(b.getSymbolicName()) &&
                 bundle.getVersion().equals(b.getVersion().toString()));
@@ -298,5 +324,5 @@ public class OsgiManager {
     public Framework getFramework() {
         return framework;
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/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 a89a528..25ef2b0 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
@@ -43,6 +43,7 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoManifest;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoPersister;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.CatalogItemMemento;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.ManagedBundleMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.BrooklynObjectType;
@@ -261,8 +262,11 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
 
         Stopwatch stopwatch = Stopwatch.createStarted();
         try {
-            for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER)
+            for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
+                // TODO exclude bundles
                 subPathDataBuilder.putAll(type, makeIdSubPathMap(objectStore.listContentsWithSubPath(type.getSubPathName())));
+            }
+            // TODO bundles
             
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
@@ -368,6 +372,16 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
                             exceptionHandler.onLoadMementoFailed(type, "memento "+objectId+" early catalog deserialization error", e);
                         }
                         break;
+                    case MANAGED_BUNDLE:
+                        try {
+                            ManagedBundleMemento memento = (ManagedBundleMemento) getSerializerWithStandardClassLoader().fromString(contents);
+                            builder.bundle( memento );
+                            // TODO load and set contents
+                        } catch (Exception e) {
+                            exceptionHandler.onLoadMementoFailed(type, "memento "+objectId+" early catalog deserialization error", e);
+                        }
+                        break;
+                        
                     default:
                         throw new IllegalStateException("Unexpected brooklyn type: "+type);
                 }
@@ -527,6 +541,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             
             futures.add(asyncUpdatePlaneId(newMemento.getPlaneId(), exceptionHandler));
             for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
+                // TODO handle bundles separately
                 for (Map.Entry<String, String> entry : newMemento.getObjectsOfType(type).entrySet()) {
                     futures.add(asyncPersist(type.getSubPathName(), type, entry.getKey(), entry.getValue(), exceptionHandler));
                 }
@@ -604,6 +619,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
                 for (Memento item : delta.getObjectsOfType(type)) {
                     if (!deletedIds.contains(item.getId())) {
+                        // TODO if type is bundle then persist the actual bundle first
                         futures.add(asyncPersist(type.getSubPathName(), item, exceptionHandler));
                     }
                 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/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 62030c8..7463eb0 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
@@ -20,8 +20,6 @@ package org.apache.brooklyn.core.mgmt.persist;
 
 import java.util.List;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
@@ -39,10 +37,13 @@ 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.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.ha.ManagementPlaneSyncRecordPersisterToObjectStore;
+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;
@@ -56,6 +57,8 @@ import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
 import org.apache.brooklyn.util.time.Time;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Stopwatch;
@@ -68,7 +71,8 @@ public class BrooklynPersistenceUtils {
     @Beta
     public static final List<BrooklynObjectType> STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER = ImmutableList.of( 
         BrooklynObjectType.ENTITY, BrooklynObjectType.LOCATION, BrooklynObjectType.POLICY,
-        BrooklynObjectType.ENRICHER, BrooklynObjectType.FEED, BrooklynObjectType.CATALOG_ITEM);
+        BrooklynObjectType.ENRICHER, BrooklynObjectType.FEED, 
+        BrooklynObjectType.CATALOG_ITEM, BrooklynObjectType.MANAGED_BUNDLE);
 
     /** Creates a {@link PersistenceObjectStore} for general-purpose use. */
     public static PersistenceObjectStore newPersistenceObjectStore(ManagementContext managementContext,
@@ -169,15 +173,25 @@ public class BrooklynPersistenceUtils {
         for (Entity instance: mgmt.getEntityManager().getEntities()) {
             instance = Entities.deproxy(instance);
             result.entity(instance.getId(), serializer.toString(newObjectMemento(instance)));
-            for (Feed instanceAdjunct: ((EntityInternal)instance).feeds().getFeeds())
+            for (Feed instanceAdjunct: ((EntityInternal)instance).feeds().getFeeds()) {
                 result.feed(instanceAdjunct.getId(), serializer.toString(newObjectMemento(instanceAdjunct)));
-            for (Enricher instanceAdjunct: instance.enrichers())
+            }
+            for (Enricher instanceAdjunct: instance.enrichers()) {
                 result.enricher(instanceAdjunct.getId(), serializer.toString(newObjectMemento(instanceAdjunct)));
-            for (Policy instanceAdjunct: instance.policies())
+            }
+            for (Policy instanceAdjunct: instance.policies()) {
                 result.policy(instanceAdjunct.getId(), serializer.toString(newObjectMemento(instanceAdjunct)));
+            }
         }
-        for (CatalogItem<?,?> instance: mgmt.getCatalog().getCatalogItems())
+        for (CatalogItem<?,?> instance: mgmt.getCatalog().getCatalogItems()) {
             result.catalogItem(instance.getId(), serializer.toString(newObjectMemento(instance)));
+        }
+        OsgiManager osgi = ((LocalManagementContext)mgmt).getOsgiManager().orNull();
+        if (osgi!=null) {
+            for (ManagedBundle instance: osgi.getManagedBundles().values()) {
+                result.catalogItem(instance.getId(), serializer.toString(newObjectMemento(instance)));
+            }
+        }
         
         return result.build();
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
index 2dd9700..df5f9ae 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/AbstractBrooklynObjectRebindSupport.java
@@ -73,7 +73,6 @@ public abstract class AbstractBrooklynObjectRebindSupport<T extends Memento> imp
 
     protected abstract void addCustoms(RebindContext rebindContext, T memento);
     
-    @SuppressWarnings("rawtypes")
     protected void addTags(RebindContext rebindContext, T memento) {
         if (instance instanceof EntityAdjunct && Strings.isNonBlank(memento.getUniqueTag())) {
             ((AdjunctTagSupport)(instance.tags())).setUniqueTag(memento.getUniqueTag());

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ActivePartialRebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ActivePartialRebindIteration.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ActivePartialRebindIteration.java
index 84e2089..a9c10ae 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ActivePartialRebindIteration.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ActivePartialRebindIteration.java
@@ -30,12 +30,10 @@ import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
 import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoPersister;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
-import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData.Builder;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.BrooklynObjectType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
 import org.apache.brooklyn.core.mgmt.persist.PersistenceActivityMetrics;
@@ -43,11 +41,13 @@ import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
 
 /**
- * Replaces a set of existing entities (and their adjunts) and locations:
+ * Replaces a set of existing entities (and their adjuncts) and locations:
  * writes their state, applies a transformation, then reads the state back.
  */
 public class ActivePartialRebindIteration extends RebindIteration {
@@ -85,7 +85,7 @@ public class ActivePartialRebindIteration extends RebindIteration {
         Preconditions.checkState(readOnlyRebindCount.get()==Integer.MIN_VALUE, "Rebind count should be MIN when running in master mode");
         Preconditions.checkNotNull(objectsToRebindInitial, "Objects to rebind must be set");
 
-        LOG.debug("Partial rebind Rebinding ("+mode+") from "+rebindManager.getPersister().getBackingStoreDescription()+"...");
+        LOG.debug("Partial rebind - rebinding ("+mode+") from "+rebindManager.getPersister().getBackingStoreDescription()+"...");
 
         super.doRun();
     }
@@ -111,8 +111,8 @@ public class ActivePartialRebindIteration extends RebindIteration {
             
             if (bo instanceof Entity) {
                 // if it's an entity, add all adjuncts. (if doing some sort of pause, that's maybe not necessary...)
-                objectsToRebindFinal.addAll( ((EntityInternal)bo).getPolicies() );
-                objectsToRebindFinal.addAll( ((EntityInternal)bo).getEnrichers() );
+                objectsToRebindFinal.addAll( ((EntityInternal)bo).policies().asList() );
+                objectsToRebindFinal.addAll( ((EntityInternal)bo).enrichers().asList() );
                 objectsToRebindFinal.addAll( ((EntityInternal)bo).feeds().getFeeds() );
             }
         }
@@ -145,10 +145,11 @@ public class ActivePartialRebindIteration extends RebindIteration {
     }
 
     @Override
-    protected void rebuildCatalog() {
+    protected void installBundlesAndRebuildCatalog() {
         checkEnteringPhase(2);
         
-        // skip; old catalog items should be re-used
+        // skip; bundles and catalog items can't be changed for a partial rebind instruction
+        // (if upgrading, they should be changed beforehand, then this used to upgrade the objects)
     }
     
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java
index 6252d28..2b59e7c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java
@@ -21,8 +21,6 @@ package org.apache.brooklyn.core.mgmt.rebind;
 import java.util.Collection;
 import java.util.Map;
 
-import org.apache.brooklyn.core.location.internal.LocationInternal;
-import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
@@ -33,11 +31,15 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.CatalogItemMemento;
 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.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.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
+import org.apache.brooklyn.core.location.internal.LocationInternal;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 
 import com.google.common.collect.Maps;
 
@@ -68,6 +70,7 @@ public class ImmediateDeltaChangeListener implements ChangeListener {
         onChanged(instance);
     }
 
+    // TODO ensure this, and onChanged, are called
     @Override
     public void onUnmanaged(BrooklynObject instance) {
         if (running && persister != null) {
@@ -82,6 +85,8 @@ public class ImmediateDeltaChangeListener implements ChangeListener {
                 delta.removedEnricherIds.add(instance.getId());
             } else if (instance instanceof CatalogItem) {
                 delta.removedCatalogItemIds.add(instance.getId());
+            } else if (instance instanceof ManagedBundle) {
+                delta.removedBundleIds.add(instance.getId());
             } else {
                 throw new IllegalStateException("Unexpected brooklyn type: "+instance);
             }
@@ -105,6 +110,8 @@ public class ImmediateDeltaChangeListener implements ChangeListener {
                 delta.enrichers.add((EnricherMemento) memento);
             } else if (instance instanceof CatalogItem) {
                 delta.catalogItems.add((CatalogItemMemento) instance);
+            } else if (instance instanceof ManagedBundle) {
+                delta.bundles.add((ManagedBundleMemento) memento);
             } else {
                 throw new IllegalStateException("Unexpected brooklyn type: "+instance);
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java
index e5d6a40..62b2069 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PeriodicDeltaChangeListener.java
@@ -41,6 +41,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.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
@@ -96,6 +97,7 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
         private Set<Enricher> enrichers = Sets.newLinkedHashSet();
         private Set<Feed> feeds = Sets.newLinkedHashSet();
         private Set<CatalogItem<?, ?>> catalogItems = Sets.newLinkedHashSet();
+        private Set<ManagedBundle> bundles = Sets.newLinkedHashSet();
         
         private Set<String> removedLocationIds = Sets.newLinkedHashSet();
         private Set<String> removedEntityIds = Sets.newLinkedHashSet();
@@ -103,15 +105,16 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
         private Set<String> removedEnricherIds = Sets.newLinkedHashSet();
         private Set<String> removedFeedIds = Sets.newLinkedHashSet();
         private Set<String> removedCatalogItemIds = Sets.newLinkedHashSet();
+        private Set<String> removedBundleIds = Sets.newLinkedHashSet();
 
         public boolean isEmpty() {
             return planeId == null &&
                     locations.isEmpty() && entities.isEmpty() && policies.isEmpty() && 
                     enrichers.isEmpty() && feeds.isEmpty() &&
-                    catalogItems.isEmpty() &&
+                    catalogItems.isEmpty() && bundles.isEmpty() &&
                     removedEntityIds.isEmpty() && removedLocationIds.isEmpty() && removedPolicyIds.isEmpty() && 
                     removedEnricherIds.isEmpty() && removedFeedIds.isEmpty() &&
-                    removedCatalogItemIds.isEmpty();
+                    removedCatalogItemIds.isEmpty() && removedBundleIds.isEmpty();
         }
         
         public void setPlaneId(String planeId) {
@@ -152,7 +155,9 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
             case FEED: return feeds;
             case POLICY: return policies;
             case CATALOG_ITEM: return catalogItems;
-            case UNKNOWN: break;
+            case MANAGED_BUNDLE: return bundles;
+            
+            case UNKNOWN: // below
             }
             throw new IllegalStateException("No collection for type "+type);
         }
@@ -165,9 +170,11 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
             case FEED: return removedFeedIds;
             case POLICY: return removedPolicyIds;
             case CATALOG_ITEM: return removedCatalogItemIds;
-            case UNKNOWN: break;
+            case MANAGED_BUNDLE: return removedBundleIds;
+            
+            case UNKNOWN: // below
             }
-            throw new IllegalStateException("No removed ids for type "+type);
+            throw new IllegalStateException("No removed collection for type "+type);
         }
 
     }
@@ -417,20 +424,20 @@ public class PeriodicDeltaChangeListener implements ChangeListener {
             }
             
             if (LOG.isDebugEnabled() && shouldLogCheckpoint()) LOG.debug("Checkpointing delta of memento: "
-                    + "updating entities={}, locations={}, policies={}, enrichers={}, catalog items={}; "
-                    + "removing entities={}, locations={}, policies={}, enrichers={}, catalog items={}",
+                    + "updating entities={}, locations={}, policies={}, enrichers={}, catalog items={}, bundles={}; "
+                    + "removing entities={}, locations={}, policies={}, enrichers={}, catalog items={}, bundles={}",
                     new Object[] {
-                        limitedCountString(prevDeltaCollector.entities), limitedCountString(prevDeltaCollector.locations), limitedCountString(prevDeltaCollector.policies), limitedCountString(prevDeltaCollector.enrichers), limitedCountString(prevDeltaCollector.catalogItems), 
-                        limitedCountString(prevDeltaCollector.removedEntityIds), limitedCountString(prevDeltaCollector.removedLocationIds), limitedCountString(prevDeltaCollector.removedPolicyIds), limitedCountString(prevDeltaCollector.removedEnricherIds), limitedCountString(prevDeltaCollector.removedCatalogItemIds)});
+                        limitedCountString(prevDeltaCollector.entities), limitedCountString(prevDeltaCollector.locations), limitedCountString(prevDeltaCollector.policies), limitedCountString(prevDeltaCollector.enrichers), limitedCountString(prevDeltaCollector.catalogItems), limitedCountString(prevDeltaCollector.bundles), 
+                        limitedCountString(prevDeltaCollector.removedEntityIds), limitedCountString(prevDeltaCollector.removedLocationIds), limitedCountString(prevDeltaCollector.removedPolicyIds), limitedCountString(prevDeltaCollector.removedEnricherIds), limitedCountString(prevDeltaCollector.removedCatalogItemIds), limitedCountString(prevDeltaCollector.removedBundleIds)});
 
             addReferencedObjects(prevDeltaCollector);
 
             if (LOG.isTraceEnabled()) LOG.trace("Checkpointing delta of memento with references: "
-                    + "updating {} entities, {} locations, {} policies, {} enrichers, {} catalog items; "
-                    + "removing {} entities, {} locations, {} policies, {} enrichers, {} catalog items",
+                    + "updating {} entities, {} locations, {} policies, {} enrichers, {} catalog items, {} bundles; "
+                    + "removing {} entities, {} locations, {} policies, {} enrichers, {} catalog items, {} bundles",
                     new Object[] {
-                        prevDeltaCollector.entities.size(), prevDeltaCollector.locations.size(), prevDeltaCollector.policies.size(), prevDeltaCollector.enrichers.size(), prevDeltaCollector.catalogItems.size(),
-                        prevDeltaCollector.removedEntityIds.size(), prevDeltaCollector.removedLocationIds.size(), prevDeltaCollector.removedPolicyIds.size(), prevDeltaCollector.removedEnricherIds.size(), prevDeltaCollector.removedCatalogItemIds.size()});
+                        prevDeltaCollector.entities.size(), prevDeltaCollector.locations.size(), prevDeltaCollector.policies.size(), prevDeltaCollector.enrichers.size(), prevDeltaCollector.catalogItems.size(), prevDeltaCollector.bundles.size(),
+                        prevDeltaCollector.removedEntityIds.size(), prevDeltaCollector.removedLocationIds.size(), prevDeltaCollector.removedPolicyIds.size(), prevDeltaCollector.removedEnricherIds.size(), prevDeltaCollector.removedCatalogItemIds.size(), prevDeltaCollector.removedBundleIds.size()});
 
             // Generate mementos for everything that has changed in this time period
             if (prevDeltaCollector.isEmpty()) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PersisterDeltaImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PersisterDeltaImpl.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PersisterDeltaImpl.java
index 30ceaa6..a772730 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PersisterDeltaImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/PersisterDeltaImpl.java
@@ -22,15 +22,16 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
 
+import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoPersister.Delta;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoPersister.MutableDelta;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.CatalogItemMemento;
 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.api.mgmt.rebind.mementos.BrooklynMementoPersister.Delta;
-import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoPersister.MutableDelta;
 import org.apache.brooklyn.api.objs.BrooklynObjectType;
 
 import com.google.common.annotations.Beta;
@@ -49,13 +50,15 @@ public class PersisterDeltaImpl implements Delta, MutableDelta {
     Collection<EnricherMemento> enrichers = Sets.newLinkedHashSet();
     Collection<FeedMemento> feeds = Sets.newLinkedHashSet();
     Collection<CatalogItemMemento> catalogItems = Sets.newLinkedHashSet();
+    Collection<ManagedBundleMemento> bundles = Sets.newLinkedHashSet();
     
     Collection<String> removedLocationIds = Sets.newLinkedHashSet();
     Collection<String> removedEntityIds = Sets.newLinkedHashSet();
     Collection<String> removedPolicyIds = Sets.newLinkedHashSet();
     Collection<String> removedEnricherIds = Sets.newLinkedHashSet();
-    Collection <String> removedFeedIds = Sets.newLinkedHashSet();
+    Collection<String> removedFeedIds = Sets.newLinkedHashSet();
     Collection<String> removedCatalogItemIds = Sets.newLinkedHashSet();
+    Collection<String> removedBundleIds = Sets.newLinkedHashSet();
     
     @Override
     public String planeId() {
@@ -93,6 +96,11 @@ public class PersisterDeltaImpl implements Delta, MutableDelta {
     }
 
     @Override
+    public Collection<ManagedBundleMemento> bundles() {
+        return Collections.unmodifiableCollection(bundles);
+    }
+
+    @Override
     public Collection<String> removedLocationIds() {
         return Collections.unmodifiableCollection(removedLocationIds);
     }
@@ -123,6 +131,11 @@ public class PersisterDeltaImpl implements Delta, MutableDelta {
     }
 
     @Override
+    public Collection<String> removedBundleIds() {
+        return Collections.unmodifiableCollection(removedBundleIds);
+    }
+
+    @Override
     public Collection<? extends Memento> getObjectsOfType(BrooklynObjectType type) {
         return Collections.unmodifiableCollection(getMutableObjectsOfType(type));
     }
@@ -140,6 +153,7 @@ public class PersisterDeltaImpl implements Delta, MutableDelta {
         case ENRICHER: return enrichers;
         case FEED: return feeds;
         case CATALOG_ITEM: return catalogItems;
+        case MANAGED_BUNDLE: return bundles;
         case UNKNOWN: 
         default:
             throw new IllegalArgumentException(type+" not supported");
@@ -159,6 +173,7 @@ public class PersisterDeltaImpl implements Delta, MutableDelta {
         case ENRICHER: return removedEnricherIds;
         case FEED: return removedFeedIds;
         case CATALOG_ITEM: return removedCatalogItemIds;
+        case MANAGED_BUNDLE: return removedBundleIds;
         case UNKNOWN: 
         default:
             throw new IllegalArgumentException(type+" not supported");

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/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 8a2caa0..262c4a1 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
@@ -20,6 +20,7 @@ package org.apache.brooklyn.core.mgmt.rebind;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import java.io.InputStream;
 import java.util.Collection;
 import java.util.Map;
 
@@ -34,6 +35,8 @@ import org.apache.brooklyn.api.objs.BrooklynObject;
 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.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.util.collections.MutableMap;
 
 import com.google.common.collect.Maps;
@@ -48,7 +51,6 @@ public class RebindContextImpl implements RebindContext {
     private final Map<String, CatalogItem<?, ?>> catalogItems = Maps.newLinkedHashMap();
     
     private final ClassLoader classLoader;
-    @SuppressWarnings("unused")
     private final ManagementContext mgmt;
     private final RebindExceptionHandler exceptionHandler;
     private final LookupContext lookupContext;
@@ -85,6 +87,10 @@ public class RebindContextImpl implements RebindContext {
     public void registerCatalogItem(String id, CatalogItem<?, ?> catalogItem) {
         catalogItems.put(id, catalogItem);
     }
+
+    public void installBundle(ManagedBundle bundle, InputStream zipInput) {
+        ((LocalManagementContext)mgmt).getOsgiManager().get().installUploadedBundle(bundle, zipInput);
+    }
     
     public void unregisterPolicy(Policy policy) {
         policies.remove(policy.getId());

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/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 cab6385..08a1eef 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
@@ -24,10 +24,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
-import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento;
-import org.apache.brooklyn.config.ConfigKey;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
@@ -36,15 +32,19 @@ import org.apache.brooklyn.api.mgmt.rebind.RebindContext;
 import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler;
 import org.apache.brooklyn.api.mgmt.rebind.RebindManager;
 import org.apache.brooklyn.api.mgmt.rebind.RebindManager.RebindFailureMode;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.EntityMemento;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 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.config.ConfigKey;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.QuorumCheck;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/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 6df8232..e12c796 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
@@ -21,6 +21,7 @@ package org.apache.brooklyn.core.mgmt.rebind;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
@@ -50,6 +51,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.api.mgmt.rebind.mementos.TreeNode;
@@ -59,6 +61,7 @@ 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.BrooklynTypeRegistry;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.BrooklynLogging;
@@ -90,6 +93,7 @@ import org.apache.brooklyn.core.objs.proxy.InternalFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalLocationFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory;
 import org.apache.brooklyn.core.policy.AbstractPolicy;
+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.core.ClassLoaderUtils;
@@ -115,7 +119,7 @@ Multi-phase deserialization:
 
 <ul>
 <li> 1. load the manifest files and populate the summaries (ID+type) in {@link BrooklynMementoManifest}
-<li> 2. instantiate and reconstruct catalog items
+<li> 2. install bundles, instantiate and reconstruct catalog items
 <li> 3. instantiate entities+locations -- so that inter-entity references can subsequently 
        be set during deserialize (and entity config/state is set).
 <li> 4. deserialize the manifests to instantiate the mementos
@@ -237,7 +241,7 @@ public abstract class RebindIteration {
     protected void doRun() throws Exception {
         loadManifestFiles();
         initPlaneId();
-        rebuildCatalog();
+        installBundlesAndRebuildCatalog();
         instantiateLocationsAndEntities();
         instantiateMementos();
         instantiateAdjuncts(instantiator); 
@@ -308,11 +312,30 @@ public abstract class RebindIteration {
     }
 
     @SuppressWarnings("deprecation")
-    protected void rebuildCatalog() {
+    protected void installBundlesAndRebuildCatalog() {
         
         // Build catalog early so we can load other things
         checkEnteringPhase(2);
         
+        // Install bundles
+        if (rebindManager.persistBundlesEnabled) {
+            logRebindingDebug("RebindManager installing bundles: {}", mementoManifest.getBundleIds());
+            for (ManagedBundleMemento bundleM : mementoManifest.getBundles().values()) {
+                logRebindingDebug("RebindManager installing bundle {}", bundleM.getId());
+                try {
+                    InputStream in = bundleM.getJarContent().openStream();
+                    rebindContext.installBundle(instantiator.newManagedBundle(bundleM), in);
+                    in.close();
+                } catch (Exception e) {
+                    exceptionHandler.onCreateFailed(BrooklynObjectType.MANAGED_BUNDLE, bundleM.getId(), bundleM.getSymbolicName(), e);
+                }
+            }
+        } else {
+            logRebindingDebug("Not rebinding bundles; feature disabled: {}", mementoManifest.getBundleIds());
+        }
+        
+        // Do legacy items
+        
         // Instantiate catalog items
         if (rebindManager.persistCatalogItemsEnabled) {
             logRebindingDebug("RebindManager instantiating catalog items: {}", mementoManifest.getCatalogItemIds());
@@ -1148,6 +1171,12 @@ public abstract class RebindIteration {
             return invokeConstructor(reflections, clazz, new Object[]{});
         }
 
+        protected ManagedBundle newManagedBundle(ManagedBundleMemento memento) {
+            ManagedBundle result = new BasicManagedBundle(memento.getSymbolicName(), memento.getVersion(), memento.getUrl());
+            FlagUtils.setFieldsFromFlags(ImmutableMap.of("id", memento.getId()), result);
+            return result;
+        }
+        
         protected <T> T invokeConstructor(Reflections reflections, Class<T> clazz, Object[]... possibleArgs) {
             for (Object[] args : possibleArgs) {
                 try {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/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 d3693e2..f7ee653 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
@@ -132,6 +132,7 @@ public class RebindManagerImpl implements RebindManager {
     final boolean persistEnrichersEnabled;
     final boolean persistFeedsEnabled;
     final boolean persistCatalogItemsEnabled;
+    final boolean persistBundlesEnabled;
     
     private RebindFailureMode danglingRefFailureMode;
     private RebindFailureMode rebindFailureMode;
@@ -185,6 +186,7 @@ public class RebindManagerImpl implements RebindManager {
         this.persistPoliciesEnabled = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_POLICY_PERSISTENCE_PROPERTY);
         this.persistEnrichersEnabled = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_ENRICHER_PERSISTENCE_PROPERTY);
         this.persistFeedsEnabled = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_FEED_PERSISTENCE_PROPERTY);
+        this.persistBundlesEnabled = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_CATALOG_PERSISTENCE_PROPERTY);
         this.persistCatalogItemsEnabled = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_CATALOG_PERSISTENCE_PROPERTY);
 
         danglingRefFailureMode = managementContext.getConfig().getConfig(DANGLING_REFERENCE_FAILURE_MODE);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
index 6fae7f5..f47f052 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
@@ -28,8 +28,8 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
 import org.apache.brooklyn.core.BrooklynVersion;
 import org.apache.brooklyn.core.config.Sanitizer;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
-import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.ImmutableMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -187,8 +187,8 @@ public abstract class AbstractMemento implements Memento, Serializable {
         return newVerboseStringHelper().toString();
     }
     
-    protected ToStringHelper newVerboseStringHelper() {
-        return Objects.toStringHelper(this).add("id", getId()).add("type", getType())
+    protected MoreObjects.ToStringHelper newVerboseStringHelper() {
+        return MoreObjects.toStringHelper(this).add("id", getId()).add("type", getType())
                 .add("displayName", getDisplayName())
                 .add("tags", getTags())
                 .add("relations", getRelations())

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractTreeNodeMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractTreeNodeMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractTreeNodeMemento.java
index a40aeca..174a22f 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractTreeNodeMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractTreeNodeMemento.java
@@ -25,7 +25,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.TreeNode;
 
-import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.Lists;
 
 public class AbstractTreeNodeMemento extends AbstractMemento implements Memento, TreeNode, Serializable {
@@ -107,7 +107,7 @@ public class AbstractTreeNodeMemento extends AbstractMemento implements Memento,
     }
 
     @Override
-    protected ToStringHelper newVerboseStringHelper() {
+    protected MoreObjects.ToStringHelper newVerboseStringHelper() {
         return super.newVerboseStringHelper().add("parent", getParent()).add("children", getChildren());
     }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java
index 3651267..33406a4 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java
@@ -32,7 +32,7 @@ import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableList;
 
 @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
@@ -273,7 +273,7 @@ public class BasicCatalogItemMemento extends AbstractMemento implements CatalogI
     }
 
     @Override
-    protected Objects.ToStringHelper newVerboseStringHelper() {
+    protected MoreObjects.ToStringHelper newVerboseStringHelper() {
         return super.newVerboseStringHelper()
                 .add("description", getDescription())
                 .add("symbolicName", getSymbolicName())

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java
index 80c502d..9f58deb 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEnricherMemento.java
@@ -24,7 +24,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.EnricherMemento;
 import org.apache.brooklyn.core.config.Sanitizer;
 
-import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.Maps;
 
 /**
@@ -86,7 +86,7 @@ public class BasicEnricherMemento extends AbstractMemento implements EnricherMem
     }
 
     @Override
-    protected ToStringHelper newVerboseStringHelper() {
+    protected MoreObjects.ToStringHelper newVerboseStringHelper() {
         return super.newVerboseStringHelper().add("config", Sanitizer.sanitize(getConfig()));
     }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
index c8fa133..bb8e133 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicEntityMemento.java
@@ -40,7 +40,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
@@ -331,7 +331,7 @@ public class BasicEntityMemento extends AbstractTreeNodeMemento implements Entit
     }
     
     @Override
-    protected ToStringHelper newVerboseStringHelper() {
+    protected MoreObjects.ToStringHelper newVerboseStringHelper() {
         return super.newVerboseStringHelper()
                 .add("members", getMembers())
                 .add("config", Sanitizer.sanitize(getConfig()))

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java
index 072756f..0957693 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicFeedMemento.java
@@ -24,7 +24,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.FeedMemento;
 import org.apache.brooklyn.core.config.Sanitizer;
 
-import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.Maps;
 
 /**
@@ -86,7 +86,7 @@ public class BasicFeedMemento extends AbstractMemento implements FeedMemento, Se
     }
 
     @Override
-    protected ToStringHelper newVerboseStringHelper() {
+    protected MoreObjects.ToStringHelper newVerboseStringHelper() {
         return super.newVerboseStringHelper().add("config", Sanitizer.sanitize(getConfig()));
     }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java
index 71ddcaa..c4835d8 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicLocationMemento.java
@@ -27,7 +27,7 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.TreeNode;
 import org.apache.brooklyn.core.config.Sanitizer;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 
-import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
@@ -98,7 +98,7 @@ public class BasicLocationMemento extends AbstractTreeNodeMemento implements Loc
     }
     
     @Override
-    protected ToStringHelper newVerboseStringHelper() {
+    protected MoreObjects.ToStringHelper newVerboseStringHelper() {
         return super.newVerboseStringHelper()
                 .add("config", Sanitizer.sanitize(getLocationConfig()))
                 .add("locationConfigDescription", getLocationConfigDescription());

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicManagedBundleMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicManagedBundleMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicManagedBundleMemento.java
new file mode 100644
index 0000000..078fb7c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicManagedBundleMemento.java
@@ -0,0 +1,130 @@
+/*
+ * 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.dto;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.brooklyn.api.mgmt.rebind.mementos.ManagedBundleMemento;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.google.common.base.Joiner;
+import com.google.common.base.MoreObjects;
+import com.google.common.io.ByteSource;
+
+@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE)
+public class BasicManagedBundleMemento extends AbstractMemento implements ManagedBundleMemento, Serializable {
+
+    private static final long serialVersionUID = -2040630288193425950L;
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder extends AbstractMemento.Builder<Builder> {
+        protected String symbolicName;
+        protected String version;
+        protected String url;
+
+        public Builder symbolicName(String symbolicName) {
+            this.symbolicName = symbolicName;
+            return self();
+        }
+        
+        public Builder version(String version) {
+            this.version = version;
+            return self();
+        }
+
+        public Builder url(String url) {
+            this.url = url;
+            return self();
+        }
+
+        public Builder from(ManagedBundleMemento other) {
+            super.from(other);
+            symbolicName = other.getSymbolicName();
+            version = other.getVersion();
+            url = other.getUrl();
+            return self();
+        }
+
+        public BasicManagedBundleMemento build() {
+            return new BasicManagedBundleMemento(this);
+        }
+    }
+
+    private String symbolicName;
+    private String version;
+    private String url;
+    private ByteSource jarContent;
+
+    @SuppressWarnings("unused") // For deserialisation
+    private BasicManagedBundleMemento() {}
+
+    protected BasicManagedBundleMemento(Builder builder) {
+        super(builder);
+        this.symbolicName = builder.symbolicName;
+        this.version = builder.version;
+        this.url = builder.url;
+    }
+
+    @Override
+    public String getSymbolicName() {
+        return symbolicName;
+    }
+
+    @Override
+    public String getVersion() {
+        return version;
+    }
+
+    @Override
+    public String getUrl() {
+        return url;
+    }
+
+    @Override
+    public ByteSource getJarContent() {
+        return jarContent;
+    }
+
+    @Override
+    protected void setCustomFields(Map<String, Object> fields) {
+        if (!fields.isEmpty()) {
+            throw new UnsupportedOperationException("Cannot set custom fields on " + this + ". " +
+                    "Fields=" + Joiner.on(", ").join(fields.keySet()));
+        }
+    }
+
+    @Override
+    public Map<String, ? extends Object> getCustomFields() {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    protected MoreObjects.ToStringHelper newVerboseStringHelper() {
+        return super.newVerboseStringHelper()
+                .add("symbolicName", getSymbolicName())
+                .add("version", getVersion())
+                .add("url", getUrl());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fbe99f1f/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java
index 87a0dfb..dfaa616 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicPolicyMemento.java
@@ -24,7 +24,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.PolicyMemento;
 import org.apache.brooklyn.core.config.Sanitizer;
 
-import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.MoreObjects;
 import com.google.common.collect.Maps;
 
 /**
@@ -86,7 +86,7 @@ public class BasicPolicyMemento extends AbstractMemento implements PolicyMemento
     }
     
     @Override
-    protected ToStringHelper newVerboseStringHelper() {
+    protected MoreObjects.ToStringHelper newVerboseStringHelper() {
         return super.newVerboseStringHelper().add("config", Sanitizer.sanitize(getConfig()));
     }
 }


[03/13] brooklyn-server git commit: osgi bundle persistence code written ... but not yet tested. need to write unit test for persistence, and do manual test against S3 or similar.

Posted by ge...@apache.org.
osgi bundle persistence code written ... but not yet tested.
need to write unit test for persistence, and do manual test against S3 or similar.

then the fun stuff, CLI push and upgrade workflow, bundles used in search path instead of catalog item id, bundles managed in REST/UI


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

Branch: refs/heads/master
Commit: e8b5fd053cd4434c66b63c9124d7aa0ef9cb1237
Parents: fbe99f1
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Apr 20 17:01:01 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Apr 21 12:45:35 2017 +0100

----------------------------------------------------------------------
 .../rebind/mementos/ManagedBundleMemento.java   |   1 +
 .../catalog/CatalogMakeOsgiBundleTest.java      |  13 ++-
 .../brooklyn/core/mgmt/ha/OsgiManager.java      |  85 ++++++++++++++-----
 .../BrooklynMementoPersisterToObjectStore.java  |  75 ++++++++++++++--
 .../mgmt/persist/BrooklynPersistenceUtils.java  |   3 +-
 .../rebind/ImmediateDeltaChangeListener.java    |   1 -
 .../rebind/dto/BasicManagedBundleMemento.java   |   7 +-
 .../core/typereg/BasicManagedBundle.java        |  30 ++++++-
 .../brooklyn/util/core/osgi/BundleMaker.java    |   7 +-
 .../HighAvailabilityManagerSplitBrainTest.java  |   2 +-
 .../ha/HighAvailabilityManagerTestFixture.java  |   2 +-
 .../brooklyn/core/mgmt/ha/HotStandbyTest.java   |   2 +-
 .../brooklyn/core/mgmt/ha/WarmStandbyTest.java  |   2 +-
 .../mgmt/osgi/OsgiVersionMoreEntityTest.java    |  17 ++++
 .../core/mgmt/rebind/RebindTestFixture.java     |   2 +-
 .../core/mgmt/rebind/RebindTestUtils.java       |   6 +-
 .../transformer/CompoundTransformerTest.java    |   4 +-
 .../util/core/osgi/BundleMakerTest.java         |   3 +-
 .../brooklyn/launcher/common/BasicLauncher.java |   4 +-
 .../CleanOrphanedLocationsIntegrationTest.java  |   4 +-
 .../rest/resources/CatalogResource.java         |  12 ++-
 .../brooklyn-test-osgi-com-example-entities.jar | Bin 22144 -> 22130 bytes
 .../osgi/brooklyn-test-osgi-entities.jar        | Bin 22075 -> 22067 bytes
 .../brooklyn-test-osgi-more-entities_0.1.0.jar  | Bin 16004 -> 15997 bytes
 .../brooklyn-test-osgi-more-entities_0.2.0.jar  | Bin 16906 -> 16903 bytes
 ...-test-osgi-more-entities_evil-twin_0.2.0.jar | Bin 13811 -> 14091 bytes
 26 files changed, 220 insertions(+), 62 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/ManagedBundleMemento.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/ManagedBundleMemento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/ManagedBundleMemento.java
index f2ec818..7e487ff 100644
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/ManagedBundleMemento.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/ManagedBundleMemento.java
@@ -28,5 +28,6 @@ public interface ManagedBundleMemento extends Memento {
     String getUrl();
     
     ByteSource getJarContent();
+    void setJarContent(ByteSource byteSource);
 
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/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 a08c7b6..6f7117e 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
@@ -20,6 +20,7 @@ package org.apache.brooklyn.camp.brooklyn.catalog;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.InputStream;
 import java.util.Collection;
 import java.util.List;
@@ -39,6 +40,7 @@ import org.apache.brooklyn.core.entity.EntityAsserts;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
@@ -169,8 +171,15 @@ public class CatalogMakeOsgiBundleTest extends AbstractYamlTest {
     }
 
     private void installBundle(File jf) {
-        Bundle bundle = bm.installBundle(jf, true);
-        bundlesToRemove.add(bundle);
+        try (FileInputStream fin = new FileInputStream(jf)) {
+            BasicManagedBundle bundleMetadata = new BasicManagedBundle();
+            Bundle bundle =
+                ((LocalManagementContext)mgmt()).getOsgiManager().get().installUploadedBundle(bundleMetadata, fin);
+            bundlesToRemove.add(bundle);
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/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 c64a131..37ba4ce 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
@@ -19,6 +19,8 @@
 package org.apache.brooklyn.core.mgmt.ha;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.Arrays;
@@ -39,6 +41,7 @@ import org.apache.brooklyn.core.BrooklynVersion;
 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.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
 import org.apache.brooklyn.util.core.osgi.Osgis;
@@ -50,6 +53,7 @@ import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.os.Os.DeletionResult;
 import org.apache.brooklyn.util.repeat.Repeater;
+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;
@@ -121,33 +125,63 @@ public class OsgiManager {
         return ImmutableMap.copyOf(managedBundles);
     }
     
-    public void installUploadedBundle(ManagedBundle bundleMetadata, InputStream zip) {
+    public Bundle installUploadedBundle(ManagedBundle bundleMetadata, InputStream zipIn) {
         try {
-            if (checkBundleInstalledThrowIfInconsistent(bundleMetadata)) {
-                return;
+            Bundle alreadyBundle = checkBundleInstalledThrowIfInconsistent(bundleMetadata, false);
+            if (alreadyBundle!=null) {
+                return alreadyBundle;
             }
 
-            Bundle bundleInstalled = framework.getBundleContext().installBundle(bundleMetadata.getOsgiUniqueUrl(), zip);
+            File zipF = Os.newTempFile("brooklyn-bundle-transient-"+bundleMetadata, "zip");
+            FileOutputStream fos = new FileOutputStream(zipF);
+            Streams.copy(zipIn, fos);
+            zipIn.close();
+            fos.close();
+            
+            Bundle bundleInstalled = framework.getBundleContext().installBundle(bundleMetadata.getOsgiUniqueUrl(), 
+                new FileInputStream(zipF));
             checkCorrectlyInstalled(bundleMetadata, bundleInstalled);
+            if (!bundleMetadata.isNameResolved()) {
+                ((BasicManagedBundle)bundleMetadata).setSymbolicName(bundleInstalled.getSymbolicName());
+                ((BasicManagedBundle)bundleMetadata).setVersion(bundleInstalled.getVersion().toString());
+            }
+            ((BasicManagedBundle)bundleMetadata).setTempLocalFileWhenJustUploaded(zipF);
             
             synchronized (managedBundles) {
                 managedBundles.put(bundleMetadata.getId(), bundleMetadata);
             }
+            mgmt.getRebindManager().getChangeListener().onChanged(bundleMetadata);
+            
+            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)
+            
+            return bundleInstalled;
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
             throw new IllegalStateException("Bundle "+bundleMetadata+" failed to install: " + e.getMessage(), e);
         }
     }
     
-    public synchronized void registerBundle(CatalogBundle bundleMetadata) {
+    // TODO uninstall bundle, and call change listener onRemoved ?
+    // TODO on snapshot install, uninstall old equivalent snapshots (items in use might stay in use though?)
+    
+    public synchronized Bundle registerBundle(CatalogBundle bundleMetadata) {
         try {
-            if (checkBundleInstalledThrowIfInconsistent(bundleMetadata)) {
-                return;
+            Bundle alreadyBundle = checkBundleInstalledThrowIfInconsistent(bundleMetadata, true);
+            if (alreadyBundle!=null) {
+                return alreadyBundle;
             }
 
             Bundle bundleInstalled = Osgis.install(framework, bundleMetadata.getUrl());
 
             checkCorrectlyInstalled(bundleMetadata, bundleInstalled);
+            return bundleInstalled;
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
             throw new IllegalStateException("Bundle from "+bundleMetadata.getUrl()+" failed to install: " + e.getMessage(), e);
@@ -166,41 +200,48 @@ public class OsgiManager {
                 .version(b.getVersion().toString())
                 .findAll();
         if (matches.isEmpty()) {
-            log.error("OSGi could not find bundle "+nv+" in search after installing it from "+bundle.getUrl());
+            log.error("OSGi could not find bundle "+nv+" in search after installing it from "+bundle);
         } else if (matches.size()==1) {
             log.debug("Bundle from "+bundle.getUrl()+" successfully installed as " + nv + " ("+b+")");
         } else {
-            log.warn("OSGi has multiple bundles matching "+nv+", when just installed from "+bundle.getUrl()+": "+matches+"; "
-                + "brooklyn will prefer the URL-based bundle for top-level references but any dependencies or "
-                + "import-packages will be at the mercy of OSGi. "
-                + "It is recommended to use distinct versions for different bundles, and the same URL for the same bundles.");
+            log.warn("OSGi has multiple bundles matching "+nv+", when installing "+bundle+"; not guaranteed which versions will be consumed");
+            // TODO for snapshot versions we should indicate which one is best to use
         }
     }
 
-    private boolean checkBundleInstalledThrowIfInconsistent(OsgiBundleWithUrl bundle) {
-        String bundleUrl = bundle.getUrl();
+    /** return already-installed bundle or null */
+    private Bundle checkBundleInstalledThrowIfInconsistent(OsgiBundleWithUrl bundleMetadata, boolean requireUrlIfNotAlreadyPresent) {
+        String bundleUrl = bundleMetadata.getUrl();
         if (bundleUrl != null) {
             Maybe<Bundle> installedBundle = Osgis.bundleFinder(framework).requiringFromUrl(bundleUrl).find();
             if (installedBundle.isPresent()) {
                 Bundle b = installedBundle.get();
                 String nv = b.getSymbolicName()+":"+b.getVersion().toString();
-                if (!isBundleNameEqualOrAbsent(bundle, b)) {
-                    throw new IllegalStateException("User requested bundle " + bundle + " but already installed as "+nv);
+                if (!isBundleNameEqualOrAbsent(bundleMetadata, b)) {
+                    throw new IllegalStateException("User requested bundle " + bundleMetadata + " but already installed as "+nv);
                 } else {
                     log.trace("Bundle from "+bundleUrl+" already installed as "+nv+"; not re-registering");
                 }
-                return true;
+                return b;
             }
         } else {
-            Maybe<Bundle> installedBundle = Osgis.bundleFinder(framework).symbolicName(bundle.getSymbolicName()).version(bundle.getVersion()).find();
+            Maybe<Bundle> installedBundle;
+            if (bundleMetadata.isNameResolved()) {
+                installedBundle = Osgis.bundleFinder(framework).symbolicName(bundleMetadata.getSymbolicName()).version(bundleMetadata.getVersion()).find();
+            } else {
+                installedBundle = Maybe.absent("Bundle metadata does not have URL nor does it have both name and version");
+            }
             if (installedBundle.isPresent()) {
-                log.trace("Bundle "+bundle+" installed from "+installedBundle.get().getLocation());
+                log.trace("Bundle "+bundleMetadata+" installed from "+installedBundle.get().getLocation());
             } else {
-                throw new IllegalStateException("Bundle "+bundle+" not previously registered, but URL is empty.");
+                if (requireUrlIfNotAlreadyPresent) {
+                    throw new IllegalStateException("Bundle "+bundleMetadata+" not previously registered, but URL is empty.",
+                        Maybe.Absent.getException(installedBundle));
+                }
             }
-            return true;
+            return installedBundle.orNull();
         }
-        return false;
+        return null;
     }
 
     public static boolean isBundleNameEqualOrAbsent(OsgiBundleWithUrl bundle, Bundle b) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/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 25ef2b0..f0af9d1 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
@@ -20,6 +20,7 @@ package org.apache.brooklyn.core.mgmt.persist;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import java.io.File;
 import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -36,6 +37,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import javax.annotation.Nullable;
 
+import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.rebind.PersistenceExceptionHandler;
 import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMemento;
@@ -47,22 +49,27 @@ import org.apache.brooklyn.api.mgmt.rebind.mementos.ManagedBundleMemento;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
 import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.objs.BrooklynObjectType;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.config.StringConfigMap;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.mgmt.classloading.ClassLoaderFromBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore.StoreObjectAccessor;
 import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore.StoreObjectAccessorWithLock;
 import org.apache.brooklyn.core.mgmt.rebind.PeriodicDeltaChangeListener;
 import org.apache.brooklyn.core.mgmt.rebind.dto.BrooklynMementoImpl;
 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;
@@ -74,6 +81,7 @@ import com.google.common.base.Objects;
 import com.google.common.base.Stopwatch;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
+import com.google.common.io.ByteSource;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
@@ -112,6 +120,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
     private volatile boolean writesAllowed = false;
     private volatile boolean writesShuttingDown = false;
     private StringConfigMap brooklynProperties;
+    private ManagementContext mgmt = null;
     
     private List<Delta> queuedDeltas = new CopyOnWriteArrayList<BrooklynMementoPersister.Delta>();
     
@@ -121,6 +130,17 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
      */
     private final ReadWriteLock lock = new ReentrantReadWriteLock(true);
 
+    public BrooklynMementoPersisterToObjectStore(PersistenceObjectStore objectStore, ManagementContext mgmt) {
+        this(objectStore, mgmt, mgmt.getCatalogClassLoader());
+    }
+    
+    public BrooklynMementoPersisterToObjectStore(PersistenceObjectStore objectStore, ManagementContext mgmt, ClassLoader classLoader) {
+        this(objectStore, ((ManagementContextInternal)mgmt).getBrooklynProperties(), classLoader);
+        this.mgmt = mgmt;
+    }
+    
+    /** @deprecated since 0.12.0 use constructor taking management context */
+    @Deprecated
     public BrooklynMementoPersisterToObjectStore(PersistenceObjectStore objectStore, StringConfigMap brooklynProperties, ClassLoader classLoader) {
         this.objectStore = checkNotNull(objectStore, "objectStore");
         this.brooklynProperties = brooklynProperties;
@@ -263,10 +283,8 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         Stopwatch stopwatch = Stopwatch.createStarted();
         try {
             for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
-                // TODO exclude bundles
                 subPathDataBuilder.putAll(type, makeIdSubPathMap(objectStore.listContentsWithSubPath(type.getSubPathName())));
             }
-            // TODO bundles
             
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
@@ -306,6 +324,11 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
                 if (!Objects.equal(id, safeXmlId))
                     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()));
+                }
                 builder.put(type, xmlId, contents);
             }
         };
@@ -329,10 +352,8 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
     }
 
     @Override
-    public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mementoData, final RebindExceptionHandler exceptionHandler) throws IOException {
-        if (mementoData==null)
-            mementoData = loadMementoRawData(exceptionHandler);
-        
+    public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mementoDataR, final RebindExceptionHandler exceptionHandler) throws IOException {
+        final BrooklynMementoRawData mementoData = mementoDataR==null ? loadMementoRawData(exceptionHandler) : mementoDataR;
         final BrooklynMementoManifestImpl.Builder builder = BrooklynMementoManifestImpl.builder();
 
         builder.planeId(mementoData.getPlaneId());
@@ -376,7 +397,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
                         try {
                             ManagedBundleMemento memento = (ManagedBundleMemento) getSerializerWithStandardClassLoader().fromString(contents);
                             builder.bundle( memento );
-                            // TODO load and set contents
+                            memento.setJarContent(mementoData.getBundleJars().get(objectId));
                         } catch (Exception e) {
                             exceptionHandler.onLoadMementoFailed(type, "memento "+objectId+" early catalog deserialization error", e);
                         }
@@ -541,8 +562,8 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             
             futures.add(asyncUpdatePlaneId(newMemento.getPlaneId(), exceptionHandler));
             for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
-                // TODO handle bundles separately
                 for (Map.Entry<String, String> entry : newMemento.getObjectsOfType(type).entrySet()) {
+                    addPersistContentIfManagedBundle(type, entry.getKey(), futures, exceptionHandler);
                     futures.add(asyncPersist(type.getSubPathName(), type, entry.getKey(), entry.getValue(), exceptionHandler));
                 }
             }
@@ -619,7 +640,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
                 for (Memento item : delta.getObjectsOfType(type)) {
                     if (!deletedIds.contains(item.getId())) {
-                        // TODO if type is bundle then persist the actual bundle first
+                        addPersistContentIfManagedBundle(type, item.getId(), futures, exceptionHandler);
                         futures.add(asyncPersist(type.getSubPathName(), item, exceptionHandler));
                     }
                 }
@@ -627,6 +648,9 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
             for (BrooklynObjectType type: BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
                 for (String id : delta.getRemovedIdsOfType(type)) {
                     futures.add(asyncDelete(type.getSubPathName(), id, exceptionHandler));
+                    if (type==BrooklynObjectType.MANAGED_BUNDLE) {
+                        futures.add(asyncDelete(type.getSubPathName(), id+".jar", exceptionHandler));
+                    }
                 }
             }
             
@@ -645,6 +669,39 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         }
     }
 
+    private void addPersistContentIfManagedBundle(BrooklynObjectType type, String id, List<ListenableFuture<?>> futures, PersistenceExceptionHandler exceptionHandler) {
+        if (type==BrooklynObjectType.MANAGED_BUNDLE) {
+            if (mgmt==null) {
+                throw new IllegalStateException("Cannot persist bundles without a mangaement context");
+            }
+            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();
+                if (f!=null) {
+                    futures.add(asyncPersist(type.getSubPathName(), type, id+".jar", jarContent, exceptionHandler));
+                    executor.submit(new Runnable() {
+                        @Override
+                        public void run() {
+                            ((BasicManagedBundle)mb).setTempLocalFileWhenJustUploaded(null);
+                            f.delete();
+                        }});
+                }
+            }
+        }
+    }
+
     @Override
     public void waitForWritesCompleted(Duration timeout) throws InterruptedException, TimeoutException {
         boolean locked = lock.readLock().tryLock(timeout.toMillisecondsRoundingUp(), TimeUnit.MILLISECONDS);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/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 7463eb0..c509208 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
@@ -108,8 +108,7 @@ public class BrooklynPersistenceUtils {
             PersistenceObjectStore destinationObjectStore) {
         BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
             destinationObjectStore,
-            ((ManagementContextInternal)managementContext).getBrooklynProperties(),
-            managementContext.getCatalogClassLoader());
+            managementContext);
         PersistenceExceptionHandler exceptionHandler = PersistenceExceptionHandlerImpl.builder().build();
         persister.enableWriteAccess();
         persister.checkpoint(memento, exceptionHandler);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java
index 2b59e7c..3d77f41 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/ImmediateDeltaChangeListener.java
@@ -70,7 +70,6 @@ public class ImmediateDeltaChangeListener implements ChangeListener {
         onChanged(instance);
     }
 
-    // TODO ensure this, and onChanged, are called
     @Override
     public void onUnmanaged(BrooklynObject instance) {
         if (running && persister != null) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicManagedBundleMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicManagedBundleMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicManagedBundleMemento.java
index 078fb7c..505e7c8 100644
--- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicManagedBundleMemento.java
+++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicManagedBundleMemento.java
@@ -74,7 +74,7 @@ public class BasicManagedBundleMemento extends AbstractMemento implements Manage
     private String symbolicName;
     private String version;
     private String url;
-    private ByteSource jarContent;
+    transient private ByteSource jarContent;
 
     @SuppressWarnings("unused") // For deserialisation
     private BasicManagedBundleMemento() {}
@@ -105,6 +105,11 @@ public class BasicManagedBundleMemento extends AbstractMemento implements Manage
     public ByteSource getJarContent() {
         return jarContent;
     }
+    
+    @Override
+    public void setJarContent(ByteSource byteSource) {
+        this.jarContent = byteSource;
+    }
 
     @Override
     protected void setCustomFields(Map<String, Object> fields) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
index 4223e79..8d92794 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.core.typereg;
 
+import java.io.File;
 import java.util.Map;
 
 import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
@@ -27,6 +28,7 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.objs.AbstractBrooklynObject;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
@@ -36,10 +38,10 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage
     private String symbolicName;
     private String version;
     private String url;
+    private transient File localFileWhenJustUploaded;
 
-    // for deserializing (not sure if needed?)
-    @SuppressWarnings("unused")
-    private BasicManagedBundle() {}
+    /** Creates an empty one, with an ID, expecting other fields will be populated. */
+    public BasicManagedBundle() {}
 
     public BasicManagedBundle(String name, String version, String url) {
         if (name == null && version == null) {
@@ -64,16 +66,38 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage
         return symbolicName;
     }
 
+    public void setSymbolicName(String symbolicName) {
+        this.symbolicName = symbolicName;
+    }
+    
     @Override
     public String getVersion() {
         return version;
     }
 
+    public void setVersion(String version) {
+        this.version = version;
+    }
+    
     @Override
     public String getUrl() {
         return url;
     }
 
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    /** This is cached on the object when just uploaded, then deleted after it has been persisted. */
+    @Beta
+    public void setTempLocalFileWhenJustUploaded(File localFileWhenJustUploaded) {
+        this.localFileWhenJustUploaded = localFileWhenJustUploaded;
+    }
+    @Beta
+    public File getTempLocalFileWhenJustUploaded() {
+        return localFileWhenJustUploaded;
+    }
+    
     @Override
     public String getOsgiUniqueUrl() {
         return "brooklyn:"+getId();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java b/core/src/main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java
index efe1d0e..b590cee 100644
--- a/core/src/main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java
+++ b/core/src/main/java/org/apache/brooklyn/util/core/osgi/BundleMaker.java
@@ -36,6 +36,7 @@ import java.util.zip.ZipOutputStream;
 import javax.annotation.Nonnull;
 
 import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
@@ -259,8 +260,10 @@ public class BundleMaker {
     }
     
     /** installs the given JAR file as an OSGi bundle; all manifest info should be already set up.
-     * bundle-start semantics are TBD. */
-    @Beta
+     * bundle-start semantics are TBD.
+     * 
+     * @deprecated since 0.12.0, use {@link OsgiManager#installUploadedBundle(org.apache.brooklyn.api.typereg.ManagedBundle, InputStream)}*/
+    @Deprecated
     public Bundle installBundle(File f, boolean start) {
         try {
             Bundle b = Osgis.install( framework, "file://"+f.getAbsolutePath() );

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java
index ef3e0a4..d7d9ac9 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java
@@ -108,7 +108,7 @@ public class HighAvailabilityManagerSplitBrainTest {
             objectStore.prepareForSharedUse(PersistMode.CLEAN, HighAvailabilityMode.DISABLED);
             persister = new ManagementPlaneSyncRecordPersisterToObjectStore(mgmt, objectStore, classLoader);
             ((ManagementPlaneSyncRecordPersisterToObjectStore)persister).preferRemoteTimestampInMemento();
-            BrooklynMementoPersisterToObjectStore persisterObj = new BrooklynMementoPersisterToObjectStore(objectStore, mgmt.getBrooklynProperties(), classLoader);
+            BrooklynMementoPersisterToObjectStore persisterObj = new BrooklynMementoPersisterToObjectStore(objectStore, mgmt, classLoader);
             mgmt.getRebindManager().setPersister(persisterObj, PersistenceExceptionHandlerImpl.builder().build());
             ha = ((HighAvailabilityManagerImpl)mgmt.getHighAvailabilityManager())
                 .setPollPeriod(Duration.PRACTICALLY_FOREVER)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerTestFixture.java
index 732ab81..506d50b 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerTestFixture.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerTestFixture.java
@@ -93,7 +93,7 @@ public abstract class HighAvailabilityManagerTestFixture {
         ((ManagementPlaneSyncRecordPersisterToObjectStore)persister).preferRemoteTimestampInMemento();
         BrooklynMementoPersisterToObjectStore persisterObj = new BrooklynMementoPersisterToObjectStore(
                 objectStore, 
-                managementContext.getBrooklynProperties(), 
+                managementContext, 
                 classLoader);
         managementContext.getRebindManager().setPersister(persisterObj, PersistenceExceptionHandlerImpl.builder().build());
         manager = ((HighAvailabilityManagerImpl)managementContext.getHighAvailabilityManager())

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java
index 4b4e446..4fefddd 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java
@@ -102,7 +102,7 @@ public class HotStandbyTest {
             objectStore.prepareForSharedUse(PersistMode.CLEAN, HighAvailabilityMode.DISABLED);
             persister = new ManagementPlaneSyncRecordPersisterToObjectStore(mgmt, objectStore, classLoader);
             ((ManagementPlaneSyncRecordPersisterToObjectStore)persister).preferRemoteTimestampInMemento();
-            BrooklynMementoPersisterToObjectStore persisterObj = new BrooklynMementoPersisterToObjectStore(objectStore, mgmt.getBrooklynProperties(), classLoader);
+            BrooklynMementoPersisterToObjectStore persisterObj = new BrooklynMementoPersisterToObjectStore(objectStore, mgmt, classLoader);
             ((RebindManagerImpl)mgmt.getRebindManager()).setPeriodicPersistPeriod(persistOrRebindPeriod);
             mgmt.getRebindManager().setPersister(persisterObj, PersistenceExceptionHandlerImpl.builder().build());
             ha = ((HighAvailabilityManagerImpl)mgmt.getHighAvailabilityManager())

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java
index 830f472..7aa7353 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java
@@ -79,7 +79,7 @@ public class WarmStandbyTest {
             objectStore.prepareForSharedUse(PersistMode.CLEAN, HighAvailabilityMode.DISABLED);
             persister = new ManagementPlaneSyncRecordPersisterToObjectStore(mgmt, objectStore, classLoader);
             ((ManagementPlaneSyncRecordPersisterToObjectStore)persister).preferRemoteTimestampInMemento();
-            BrooklynMementoPersisterToObjectStore persisterObj = new BrooklynMementoPersisterToObjectStore(objectStore, mgmt.getBrooklynProperties(), classLoader);
+            BrooklynMementoPersisterToObjectStore persisterObj = new BrooklynMementoPersisterToObjectStore(objectStore, mgmt, classLoader);
             mgmt.getRebindManager().setPersister(persisterObj, PersistenceExceptionHandlerImpl.builder().build());
             ha = ((HighAvailabilityManagerImpl)mgmt.getHighAvailabilityManager())
                 .setPollPeriod(Duration.PRACTICALLY_FOREVER)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
index 62025f5..c4b9fdf 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
@@ -23,12 +23,14 @@ import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 
 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.objs.BrooklynObject;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.catalog.internal.CatalogEntityItemDto;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemBuilder;
@@ -42,8 +44,11 @@ import org.apache.brooklyn.core.objs.proxy.InternalEntityFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
+import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.osgi.OsgiTestBase;
 import org.apache.brooklyn.util.core.osgi.Osgis;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -216,6 +221,18 @@ public class OsgiVersionMoreEntityTest {
             BROOKLYN_TEST_MORE_ENTITIES_V2_URL,
             BROOKLYN_TEST_OSGI_ENTITIES_URL);
     }
+
+    @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));
+        Assert.assertEquals(mb.getSymbolicName(), b.getSymbolicName());
+        
+        Map<String, ManagedBundle> bundles = ((ManagementContextInternal)mgmt).getOsgiManager().get().getManagedBundles();
+        Asserts.assertSize(bundles.keySet(), 1);
+        Assert.assertEquals(mb.getId(), Iterables.getOnlyElement( bundles.keySet() ));
+    }
     
     @Test
     public void testMoreEntitiesV1() throws Exception {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
index 41d51c2..4ede973 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
@@ -350,7 +350,7 @@ public abstract class RebindTestFixture<T extends StartableApplication> {
         objectStore.prepareForSharedUse(PersistMode.AUTO, HighAvailabilityMode.DISABLED);
         BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
                 objectStore,
-                ((ManagementContextInternal)newManagementContext).getBrooklynProperties(),
+                newManagementContext,
                 classLoader);
         RebindExceptionHandler exceptionHandler = new RecordingRebindExceptionHandler(RebindManager.RebindFailureMode.FAIL_AT_END, RebindManager.RebindFailureMode.FAIL_AT_END);
         BrooklynMementoManifest mementoManifest = persister.loadMementoManifest(null, exceptionHandler);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
index 4e18336..7271d3e 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestUtils.java
@@ -253,7 +253,7 @@ public class RebindTestUtils {
             objectStore.prepareForSharedUse(PersistMode.AUTO, haMode);
             BrooklynMementoPersisterToObjectStore newPersister = new BrooklynMementoPersisterToObjectStore(
                     objectStore, 
-                    unstarted.getBrooklynProperties(), 
+                    unstarted, 
                     classLoader);
             ((RebindManagerImpl) unstarted.getRebindManager()).setPeriodicPersistPeriod(persistPeriod);
             unstarted.getRebindManager().setPersister(newPersister, PersistenceExceptionHandlerImpl.builder().build());
@@ -455,7 +455,7 @@ public class RebindTestUtils {
             
             BrooklynMementoPersisterToObjectStore newPersister = new BrooklynMementoPersisterToObjectStore(
                     objectStore,
-                    newManagementContext.getBrooklynProperties(),
+                    newManagementContext,
                     classLoader);
             newManagementContext.getRebindManager().setPersister(newPersister, PersistenceExceptionHandlerImpl.builder().build());
         } else {
@@ -533,7 +533,7 @@ public class RebindTestUtils {
             store = new FileBasedObjectStore(dir);
             store.injectManagementContext(mgmt);
             store.prepareForSharedUse(PersistMode.AUTO, HighAvailabilityMode.HOT_STANDBY);
-            persister = new BrooklynMementoPersisterToObjectStore(store, BrooklynProperties.Factory.newEmpty(), RebindTestUtils.class.getClassLoader());
+            persister = new BrooklynMementoPersisterToObjectStore(store, mgmt, RebindTestUtils.class.getClassLoader());
             BrooklynMementoRawData data = persister.loadMementoRawData(RebindExceptionHandlerImpl.builder().build());
             List<BrooklynObjectType> types = ImmutableList.of(BrooklynObjectType.ENTITY, BrooklynObjectType.LOCATION, 
                     BrooklynObjectType.POLICY, BrooklynObjectType.ENRICHER, BrooklynObjectType.FEED, 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java
index f2b3418..02dfadb 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java
@@ -452,9 +452,7 @@ public class CompoundTransformerTest extends RebindTestFixtureWithApp {
         objectStore.prepareForSharedUse(PersistMode.CLEAN, HighAvailabilityMode.DISABLED);
 
         BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
-                objectStore,
-                ((ManagementContextInternal)origManagementContext).getBrooklynProperties(),
-                origManagementContext.getCatalog().getRootClassLoader());
+                objectStore, origManagementContext);
         persister.enableWriteAccess();
 
         PersistenceExceptionHandler exceptionHandler = PersistenceExceptionHandlerImpl.builder().build();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/core/src/test/java/org/apache/brooklyn/util/core/osgi/BundleMakerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/util/core/osgi/BundleMakerTest.java b/core/src/test/java/org/apache/brooklyn/util/core/osgi/BundleMakerTest.java
index 599531d..a23fab3 100644
--- a/core/src/test/java/org/apache/brooklyn/util/core/osgi/BundleMakerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/util/core/osgi/BundleMakerTest.java
@@ -36,10 +36,8 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
 
-import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
-import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.stream.Streams;
 import org.osgi.framework.Bundle;
@@ -214,6 +212,7 @@ public class BundleMakerTest extends BrooklynMgmtUnitTestSupport {
         assertJarContents(generatedJar, ImmutableMap.of(JarFile.MANIFEST_NAME, expectedManifest, "myfile.txt", "mytext", "subdir/myfile2.txt", "mytext2"));
     }
     
+    @SuppressWarnings("deprecation")
     @Test
     public void testInstallBundle() throws Exception {
         Map<String, String> manifest = ImmutableMap.of(

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
----------------------------------------------------------------------
diff --git a/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java b/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
index afad4c9..2a7a924 100644
--- a/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
+++ b/launcher-common/src/main/java/org/apache/brooklyn/launcher/common/BasicLauncher.java
@@ -584,9 +584,7 @@ public class BasicLauncher<T extends BasicLauncher<T>> {
                 RebindManager rebindManager = managementContext.getRebindManager();
                 
                 BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
-                    objectStore,
-                    ((ManagementContextInternal)managementContext).getBrooklynProperties(),
-                    managementContext.getCatalogClassLoader());
+                    objectStore, managementContext);
                 PersistenceExceptionHandler persistenceExceptionHandler = PersistenceExceptionHandlerImpl.builder().build();
                 ((RebindManagerImpl) rebindManager).setPeriodicPersistPeriod(persistPeriod);
                 rebindManager.setPersister(persister, persistenceExceptionHandler);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsIntegrationTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsIntegrationTest.java b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsIntegrationTest.java
index 4d59735..09d938d 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsIntegrationTest.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/CleanOrphanedLocationsIntegrationTest.java
@@ -131,9 +131,7 @@ public class CleanOrphanedLocationsIntegrationTest extends AbstractCleanOrphaned
                 PersistMode.AUTO, HighAvailabilityMode.HOT_STANDBY);
 
         BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
-                objectStore,
-                ((ManagementContextInternal)mgmt).getBrooklynProperties(),
-                mgmt.getCatalogClassLoader());
+                objectStore, mgmt);
 
         RebindManager rebindManager = mgmt.getRebindManager();
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
index c2e800a..677b84f 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.rest.resources;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.URI;
@@ -55,6 +56,8 @@ import org.apache.brooklyn.core.catalog.internal.CatalogItemComparator;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.StringAndArgument;
+import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
 import org.apache.brooklyn.rest.api.CatalogApi;
 import org.apache.brooklyn.rest.domain.ApiError;
@@ -226,7 +229,14 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
             
             f2 = bm.copyAddingManifest(f, mf);
             
-            Bundle bundle = bm.installBundle(f2, true);
+            BasicManagedBundle bundleMetadata = new BasicManagedBundle(bundleNameInMF, bundleVersionInMF, null);
+            Bundle bundle;
+            try (FileInputStream f2in = new FileInputStream(f2)) {
+                bundle =
+                    ((LocalManagementContext)mgmt()).getOsgiManager().get().installUploadedBundle(bundleMetadata, f2in);
+            } catch (Exception e) {
+                throw Exceptions.propagate(e);
+            }
 
             Iterable<? extends CatalogItem<?, ?>> catalogItems = MutableList.of();
             

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-com-example-entities.jar
----------------------------------------------------------------------
diff --git a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-com-example-entities.jar b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-com-example-entities.jar
index c476d9d..86dfd8b 100644
Binary files a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-com-example-entities.jar and b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-com-example-entities.jar differ

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar
----------------------------------------------------------------------
diff --git a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar
index a9a2ecc..60fece6 100644
Binary files a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar and b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-entities.jar differ

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar
----------------------------------------------------------------------
diff --git a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar
index b30775e..9994cfb 100644
Binary files a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar and b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar differ

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar
----------------------------------------------------------------------
diff --git a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar
index 0dc12b1..3d1ce7b 100644
Binary files a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar and b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar differ

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e8b5fd05/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar
----------------------------------------------------------------------
diff --git a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar
index 2c0e3a6..f00a115 100644
Binary files a/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar and b/utils/common/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar differ


[07/13] brooklyn-server git commit: minor comments, tidy, and logging

Posted by ge...@apache.org.
minor comments, tidy, and logging


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

Branch: refs/heads/master
Commit: cee8e1eed5b069dee62462e5be0d4785502328ba
Parents: 340e036
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Apr 22 00:05:41 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Apr 22 00:38:09 2017 +0100

----------------------------------------------------------------------
 .../catalog/CatalogYamlTemplateTest.java        |  3 ++-
 .../core/BrooklynFeatureEnablement.java         |  2 ++
 .../BrooklynMementoPersisterToObjectStore.java  | 28 +++++++++++---------
 .../persist/FileBasedStoreObjectAccessor.java   |  2 ++
 4 files changed, 21 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/cee8e1ee/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
index cb585e0..bf5861e 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
@@ -40,6 +40,7 @@ import org.apache.brooklyn.entity.stock.BasicApplication;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.testng.Assert;
+import org.testng.ITestNGListener;
 import org.testng.TestListenerAdapter;
 import org.testng.TestNG;
 import org.testng.annotations.Test;
@@ -269,7 +270,7 @@ public class CatalogYamlTemplateTest extends AbstractYamlTest {
 
     // convenience for running in eclipse when the TestNG plugin drags in old version of snake yaml
     public static void main(String[] args) {
-        TestListenerAdapter tla = new TestListenerAdapter();
+        ITestNGListener tla = new TestListenerAdapter();
         TestNG testng = new TestNG();
         testng.setTestClasses(new Class[] { CatalogYamlTemplateTest.class });
         testng.addListener(tla);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/cee8e1ee/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java b/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
index 466fe88..677640b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
+++ b/core/src/main/java/org/apache/brooklyn/core/BrooklynFeatureEnablement.java
@@ -126,6 +126,8 @@ public class BrooklynFeatureEnablement {
      * Whether to scan newly loaded bundles for catalog.bom and load it.
      * 
      * The functionality loads catalog items regardless of the persistence state so best used with persistence disabled.
+     * If a bundle is uploaded its BOM is scanned regardless of this property (this only applies to bundles
+     * installed through a non-brooklyn method, eg karaf.)
      */
     public static final String FEATURE_LOAD_BUNDLE_CATALOG_BOM = FEATURE_PROPERTY_PREFIX+".osgi.catalog_bom";
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/cee8e1ee/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 7707adb..ccafcc3 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
@@ -301,10 +301,10 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         }
 
         BrooklynMementoRawData subPathData = subPathDataBuilder.build();
-        LOG.debug("Loaded rebind lists; took {}: {} entities, {} locations, {} policies, {} enrichers, {} feeds, {} catalog items; from {}", new Object[]{
+        LOG.debug("Loaded rebind lists; took {}: {} entities, {} locations, {} policies, {} enrichers, {} feeds, {} catalog items, {} bundles; from {}", new Object[]{
             Time.makeTimeStringRounded(stopwatch),
             subPathData.getEntities().size(), subPathData.getLocations().size(), subPathData.getPolicies().size(), subPathData.getEnrichers().size(), 
-            subPathData.getFeeds().size(), subPathData.getCatalogItems().size(),
+            subPathData.getFeeds().size(), subPathData.getCatalogItems().size(), subPathData.getBundles().size(),
             objectStore.getSummaryName() });
         
         return subPathData;
@@ -354,10 +354,10 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         BrooklynMementoRawData result = builder.build();
 
         if (LOG.isDebugEnabled()) {
-            LOG.debug("Loaded rebind raw data; took {}; {} entities, {} locations, {} policies, {} enrichers, {} feeds, {} catalog items, from {}", new Object[]{
+            LOG.debug("Loaded rebind raw data; took {}; {} entities, {} locations, {} policies, {} enrichers, {} feeds, {} catalog items, {} bundles, from {}", new Object[]{
                      Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS)), result.getEntities().size(), 
                      result.getLocations().size(), result.getPolicies().size(), result.getEnrichers().size(),
-                     result.getFeeds().size(), result.getCatalogItems().size(),
+                     result.getFeeds().size(), result.getCatalogItems().size(), result.getBundles().size(),
                      objectStore.getSummaryName() });
         }
 
@@ -448,11 +448,11 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         BrooklynMementoManifest result = builder.build();
 
         if (LOG.isDebugEnabled()) {
-            LOG.debug("Loaded rebind manifests; took {}: {} entities, {} locations, {} policies, {} enrichers, {} feeds, {} catalog items; from {}", new Object[]{
+            LOG.debug("Loaded rebind manifests; took {}: {} entities, {} locations, {} policies, {} enrichers, {} feeds, {} catalog items, {} bundles; from {}", new Object[]{
                      Time.makeTimeStringRounded(stopwatch), 
                      result.getEntityIdToManifest().size(), result.getLocationIdToType().size(), 
                      result.getPolicyIdToType().size(), result.getEnricherIdToType().size(), result.getFeedIdToType().size(), 
-                     result.getCatalogItemMementos().size(),
+                     result.getCatalogItemMementos().size(), result.getBundles().size(),
                      objectStore.getSummaryName() });
         }
 
@@ -498,9 +498,9 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         BrooklynMemento result = builder.build();
         
         if (LOG.isDebugEnabled()) {
-            LOG.debug("Loaded rebind mementos; took {}: {} entities, {} locations, {} policies, {} enrichers, {} feeds, {} catalog items, from {}", new Object[]{
+            LOG.debug("Loaded rebind mementos; took {}: {} entities, {} locations, {} policies, {} enrichers, {} feeds, {} catalog items, {} bundles, from {}", new Object[]{
                       Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS)), result.getEntityIds().size(), 
-                      result.getLocationIds().size(), result.getPolicyIds().size(), result.getEnricherIds().size(), 
+                      result.getLocationIds().size(), result.getPolicyIds().size(), result.getEnricherIds().size(), result.getManagedBundleIds().size(),
                       result.getFeedIds().size(), result.getCatalogItemIds().size(),
                       objectStore.getSummaryName() });
         }
@@ -630,11 +630,11 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
         Stopwatch stopwatch = deltaImpl(delta, exceptionHandler);
         
         if (LOG.isDebugEnabled()) LOG.debug("Checkpointed "+(previouslyQueued ? "previously queued " : "")+"delta of memento in {}: "
-                + "updated {} entities, {} locations, {} policies, {} enrichers, {} catalog items; "
-                + "removed {} entities, {} locations, {} policies, {} enrichers, {} catalog items",
+                + "updated {} entities, {} locations, {} policies, {} enrichers, {} catalog items, {} bundles; "
+                + "removed {} entities, {} locations, {} policies, {} enrichers, {} catalog items, {} bundles",
                     new Object[] {Time.makeTimeStringRounded(stopwatch),
-                        delta.entities().size(), delta.locations().size(), delta.policies().size(), delta.enrichers().size(), delta.catalogItems().size(),
-                        delta.removedEntityIds().size(), delta.removedLocationIds().size(), delta.removedPolicyIds().size(), delta.removedEnricherIds().size(), delta.removedCatalogItemIds().size()});
+                        delta.entities().size(), delta.locations().size(), delta.policies().size(), delta.enrichers().size(), delta.catalogItems().size(), delta.bundles().size(),
+                        delta.removedEntityIds().size(), delta.removedLocationIds().size(), delta.removedPolicyIds().size(), delta.removedEnricherIds().size(), delta.removedCatalogItemIds().size(), delta.removedBundleIds().size()});
     }
     
     @Override
@@ -800,7 +800,9 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
     private void updatePlaneId(String planeId, PersistenceExceptionHandler exceptionHandler) {
         try {
             if (planeId==null) {
-                LOG.warn("Null content for planeId");
+                // can happen during initial backup creation; if happens any other time, there's a problem!
+                LOG.debug("Null content for planeId; not updating at server");
+                return;
             }
 
             String persistedPlaneId = read(PLANE_ID_FILE_NAME);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/cee8e1ee/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 a9f0613..1800a05 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
@@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Charsets;
 import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
 import com.google.common.io.ByteSource;
 import com.google.common.io.Files;
 
@@ -79,6 +80,7 @@ public class FileBasedStoreObjectAccessor implements PersistenceObjectStore.Stor
 
     @Override
     public void put(String val) {
+        Preconditions.checkNotNull(val, "Illegal attempt to write a null string");
         put(ByteSource.wrap(val.getBytes(Charsets.UTF_8)));
     }
     


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

Posted by ge...@apache.org.
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);
     }


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

Posted by ge...@apache.org.
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java
index ff1d33a..f0295cf 100644
--- a/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/plan/PlanToSpecTransformer.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
 import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
 import org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer;
+import org.apache.brooklyn.core.typereg.UnsupportedTypePlanException;
 
 import com.google.common.annotations.Beta;
 
@@ -50,20 +51,20 @@ public interface PlanToSpecTransformer extends ManagementContextInjectable {
     /** creates an {@link EntitySpec} given a complete plan textual description for a top-level application, 
      * according to the transformation rules this understands.
      * <p>
-     * should throw {@link PlanNotRecognizedException} if not supported. */
-    EntitySpec<? extends Application> createApplicationSpec(String plan) throws PlanNotRecognizedException;
+     * should throw {@link UnsupportedTypePlanException} if not supported. */
+    EntitySpec<? extends Application> createApplicationSpec(String plan) throws PlanNotRecognizedException, UnsupportedTypePlanException;
     
     /** creates an object spec given a catalog item.
      * <p>
      * the catalog item might be known by type, or its source plan fragment text might be inspected and transformed.
      * implementations will typically look at the {@link CatalogItem#getCatalogItemType()} first.
      * <p>
-     * should throw {@link PlanNotRecognizedException} if this transformer does not know what to do with the plan.
+     * should throw {@link UnsupportedTypePlanException} if this transformer does not know what to do with the plan.
      * 
      * @param item - The catalog item to convert to a spec. The item might not be fully populated (i.e. missing {@code symbolicName} if called
      *        from the catalog parser).
      * @param encounteredTypes - The {@code symbolicName}s of catalog items being resolved up the stack, but not including {@code item}.
      */
-    <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws PlanNotRecognizedException;
+    <T,SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) throws PlanNotRecognizedException, UnsupportedTypePlanException;
     
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
index 8d92794..1ee8aa5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java
@@ -25,6 +25,7 @@ import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
 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.mgmt.rebind.BasicManagedBundleRebindSupport;
 import org.apache.brooklyn.core.objs.AbstractBrooklynObject;
 import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
 
@@ -148,7 +149,7 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage
 
     @Override
     public RebindSupport<?> getRebindSupport() {
-        throw new UnsupportedOperationException();
+        return new BasicManagedBundleRebindSupport(this);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/main/java/org/apache/brooklyn/core/typereg/TypePlanTransformers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/TypePlanTransformers.java b/core/src/main/java/org/apache/brooklyn/core/typereg/TypePlanTransformers.java
index 8ca0289..ba81e07 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/TypePlanTransformers.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/TypePlanTransformers.java
@@ -120,11 +120,7 @@ public class TypePlanTransformers {
                     continue;
                 }
                 return Maybe.of(result);
-            } catch (UnsupportedTypePlanException e) {
-                transformersWhoDontSupport.add(t.getFormatCode() +
-                    (Strings.isNonBlank(e.getMessage()) ? " ("+e.getMessage()+")" : ""));
-            } catch (@SuppressWarnings("deprecation") org.apache.brooklyn.core.plan.PlanNotRecognizedException e) {
-                // just in case (shouldn't happen)
+            } catch (@SuppressWarnings("deprecation") org.apache.brooklyn.core.plan.PlanNotRecognizedException | UnsupportedTypePlanException e) {
                 transformersWhoDontSupport.add(t.getFormatCode() +
                     (Strings.isNonBlank(e.getMessage()) ? " ("+e.getMessage()+")" : ""));
             } catch (Throwable e) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java
index d7d9ac9..c3657c6 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HighAvailabilityManagerSplitBrainTest.java
@@ -37,8 +37,6 @@ import org.apache.brooklyn.api.mgmt.ha.ManagementPlaneSyncRecordPersister;
 import org.apache.brooklyn.core.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
-import org.apache.brooklyn.core.mgmt.ha.HighAvailabilityManagerImpl;
-import org.apache.brooklyn.core.mgmt.ha.ManagementPlaneSyncRecordPersisterToObjectStore;
 import org.apache.brooklyn.core.mgmt.ha.TestEntityFailingRebind.RebindException;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
@@ -71,7 +69,7 @@ public class HighAvailabilityManagerSplitBrainTest {
     private static final Logger log = LoggerFactory.getLogger(HighAvailabilityManagerSplitBrainTest.class);
     
     private List<HaMgmtNode> nodes = new MutableList<HighAvailabilityManagerSplitBrainTest.HaMgmtNode>();
-    Map<String,String> sharedBackingStore = MutableMap.of();
+    Map<String,byte[]> sharedBackingStore = MutableMap.of();
     Map<String,Date> sharedBackingStoreDates = MutableMap.of();
     private AtomicLong sharedTime; // used to set the ticker's return value
     private ClassLoader classLoader = getClass().getClassLoader();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java
index 4fefddd..abdee40 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/HotStandbyTest.java
@@ -78,7 +78,7 @@ public class HotStandbyTest {
     private static final Logger log = LoggerFactory.getLogger(HotStandbyTest.class);
     
     private List<HaMgmtNode> nodes = new MutableList<HotStandbyTest.HaMgmtNode>();
-    Map<String,String> sharedBackingStore = MutableMap.of();
+    Map<String,byte[]> sharedBackingStore = MutableMap.of();
     Map<String,Date> sharedBackingStoreDates = MutableMap.of();
     private ClassLoader classLoader = getClass().getClassLoader();
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java
index 7aa7353..c245ee2 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/WarmStandbyTest.java
@@ -55,7 +55,7 @@ public class WarmStandbyTest {
     private static final Logger log = LoggerFactory.getLogger(WarmStandbyTest.class);
     
     private List<HaMgmtNode> nodes = new MutableList<WarmStandbyTest.HaMgmtNode>();
-    Map<String,String> sharedBackingStore = MutableMap.of();
+    Map<String,byte[]> sharedBackingStore = MutableMap.of();
     Map<String,Date> sharedBackingStoreDates = MutableMap.of();
     private ClassLoader classLoader = getClass().getClassLoader();
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
index c4b9fdf..059b83d 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/osgi/OsgiVersionMoreEntityTest.java
@@ -23,14 +23,12 @@ import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
 
 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.objs.BrooklynObject;
 import org.apache.brooklyn.api.policy.PolicySpec;
-import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.catalog.internal.CatalogEntityItemDto;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemBuilder;
@@ -44,11 +42,8 @@ import org.apache.brooklyn.core.objs.proxy.InternalEntityFactory;
 import org.apache.brooklyn.core.objs.proxy.InternalPolicyFactory;
 import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.core.test.entity.TestApplication;
-import org.apache.brooklyn.core.typereg.BasicManagedBundle;
-import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.osgi.OsgiTestBase;
 import org.apache.brooklyn.util.core.osgi.Osgis;
 import org.apache.brooklyn.util.guava.Maybe;
@@ -71,20 +66,8 @@ import com.google.common.collect.Iterables;
  * Tests that OSGi entities load correctly and have the right catalog information set.
  * Note further tests done elsewhere using CAMP YAML (referring to methods in this class).
  */
-public class OsgiVersionMoreEntityTest {
+public class OsgiVersionMoreEntityTest implements OsgiTestResources {
    
-    public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
-    public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = "classpath:"+OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
-
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_PATH = OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V1_PATH;
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V1_PATH;
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_PATH = OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V2_PATH;
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V2_PATH;
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH = OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH;
-    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH;
-    
-    public static final String TEST_VERSION = "0.1.0";
-
     public static final String EXPECTED_SAY_HI_BROOKLYN_RESPONSE_FROM_V1 = "Hi BROOKLYN from V1";
     public static final String EXPECTED_SAY_HI_BROOKLYN_RESPONSE_FROM_V2 = "HI BROOKLYN FROM V2";
     public static final String EXPECTED_SAY_HI_BROOKLYN_RESPONSE_FROM_V2_EVIL_TWIN = "HO BROOKLYN FROM V2 EVIL TWIN";
@@ -223,18 +206,6 @@ public class OsgiVersionMoreEntityTest {
     }
 
     @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));
-        Assert.assertEquals(mb.getSymbolicName(), b.getSymbolicName());
-        
-        Map<String, ManagedBundle> bundles = ((ManagementContextInternal)mgmt).getOsgiManager().get().getManagedBundles();
-        Asserts.assertSize(bundles.keySet(), 1);
-        Assert.assertEquals(mb.getId(), Iterables.getOnlyElement( bundles.keySet() ));
-    }
-    
-    @Test
     public void testMoreEntitiesV1() throws Exception {
         TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), BROOKLYN_TEST_MORE_ENTITIES_V1_PATH);
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java
index 6f6d363..75dd95b 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java
@@ -38,8 +38,6 @@ import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
-import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
-import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
 import org.apache.brooklyn.core.mgmt.rebind.PersistenceExceptionHandlerImpl;
 import org.apache.brooklyn.core.mgmt.rebind.RebindContextImpl;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils;
@@ -48,11 +46,11 @@ import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.core.test.policy.TestPolicy;
 import org.apache.brooklyn.enricher.stock.Enrichers;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
 import org.testng.SkipException;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
 
 import com.google.common.collect.Iterables;
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/InMemoryObjectStore.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/InMemoryObjectStore.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/InMemoryObjectStore.java
index c842fd1..3f05e5e 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/InMemoryObjectStore.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/InMemoryObjectStore.java
@@ -18,35 +18,36 @@
  */
 package org.apache.brooklyn.core.mgmt.persist;
 
+import java.io.IOException;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
-import org.apache.brooklyn.core.mgmt.persist.PersistMode;
-import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
-import org.apache.brooklyn.core.mgmt.persist.StoreObjectAccessorLocking;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.stream.Streams;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
+import com.google.common.io.ByteSource;
 
 public class InMemoryObjectStore implements PersistenceObjectStore {
 
     private static final Logger log = LoggerFactory.getLogger(InMemoryObjectStore.class);
 
-    final Map<String,String> filesByName;
+    final Map<String,byte[]> filesByName;
     final Map<String, Date> fileModTimesByName;
     boolean prepared = false;
     
     public InMemoryObjectStore() {
-        this(MutableMap.<String,String>of(), MutableMap.<String,Date>of());
+        this(MutableMap.<String,byte[]>of(), MutableMap.<String,Date>of());
     }
     
-    public InMemoryObjectStore(Map<String,String> map, Map<String, Date> fileModTimesByName) {
+    public InMemoryObjectStore(Map<String,byte[]> map, Map<String, Date> fileModTimesByName) {
         filesByName = map;
         this.fileModTimesByName = fileModTimesByName;
         log.debug("Using memory-based objectStore");
@@ -72,24 +73,26 @@ public class InMemoryObjectStore implements PersistenceObjectStore {
     }
     
     public static class SingleThreadedInMemoryStoreObjectAccessor implements StoreObjectAccessor {
-        private final Map<String, String> map;
+        private final Map<String, byte[]> map;
         private final Map<String, Date> mapModTime;
         private final String key;
 
-        public SingleThreadedInMemoryStoreObjectAccessor(Map<String,String> map, Map<String, Date> mapModTime, String key) {
+        public SingleThreadedInMemoryStoreObjectAccessor(Map<String,byte[]> map, Map<String, Date> mapModTime, String key) {
             this.map = map;
             this.mapModTime = mapModTime;
             this.key = key;
         }
         @Override
         public String get() {
-            synchronized (map) {
-                return map.get(key);
-            }
+            byte[] b = getBytes();
+            if (b==null) return null;
+            return new String(b);
         }
         @Override
         public byte[] getBytes() {
-            return get().getBytes();
+            synchronized (map) {
+                return map.get(key);
+            }
         }
         @Override
         public boolean exists() {
@@ -99,9 +102,17 @@ public class InMemoryObjectStore implements PersistenceObjectStore {
         }
         @Override
         public void put(String val) {
-            synchronized (map) {
-                map.put(key, val);
-                mapModTime.put(key, new Date());
+            put(ByteSource.wrap(val.getBytes()));
+        }
+        @Override
+        public void put(ByteSource bytes) {
+            try {
+                synchronized (map) {
+                    map.put(key, Streams.readFullyAndClose(bytes.openStream()));
+                    mapModTime.put(key, new Date());
+                }
+            } catch (IOException e) {
+                throw Exceptions.propagate(e);
             }
         }
         @Override
@@ -111,7 +122,7 @@ public class InMemoryObjectStore implements PersistenceObjectStore {
                 if (val2==null) val2 = val;
                 else val2 = val2 + val;
 
-                map.put(key, val2);
+                put(val2);
                 mapModTime.put(key, new Date());
             }
         }
@@ -148,7 +159,7 @@ public class InMemoryObjectStore implements PersistenceObjectStore {
 
     @Override
     public String toString() {
-        return Objects.toStringHelper(this).add("size", filesByName.size()).toString();
+        return MoreObjects.toStringHelper(this).add("size", filesByName.size()).toString();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/ListeningObjectStore.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/ListeningObjectStore.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/ListeningObjectStore.java
index 436638d..5bf6a76 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/ListeningObjectStore.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/ListeningObjectStore.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.core.mgmt.persist;
 
+import java.io.IOException;
 import java.util.Date;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
@@ -27,6 +28,8 @@ import java.util.concurrent.atomic.AtomicLong;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
 import org.apache.brooklyn.util.collections.MutableList;
+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.CountdownTimer;
 import org.apache.brooklyn.util.time.Duration;
@@ -34,6 +37,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
+import com.google.common.io.ByteSource;
 
 public class ListeningObjectStore implements PersistenceObjectStore {
 
@@ -209,6 +213,20 @@ public class ListeningObjectStore implements PersistenceObjectStore {
             delegate.put(val);
         }
         @Override
+        public void put(ByteSource val) {
+            if (writesFailSilently)
+                return;
+
+            for (ObjectStoreTransactionListener listener: listeners) {
+                try {
+                    listener.recordDataOut("writing (binary) "+path, Streams.readFullyAndClose(val.openStream()).length);
+                } catch (IOException e) {
+                    throw Exceptions.propagate(e);
+                }
+            }
+            delegate.put(val);
+        }
+        @Override
         public void append(String s) {
             if (writesFailSilently)
                 return;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
index ed07b07..e8bc120 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/XmlMementoSerializerTest.java
@@ -47,6 +47,7 @@ import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 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.api.typereg.RegisteredType;
 import org.apache.brooklyn.config.ConfigInheritance;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemBuilder;
@@ -84,6 +85,7 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
@@ -292,24 +294,26 @@ public class XmlMementoSerializerTest {
         final TestApplication app = TestApplication.Factory.newManagedInstanceForTests();
         ManagementContext managementContext = app.getManagementContext();
         try {
-            serializer.setLookupContext(new LookupContextImpl(managementContext,
-                    ImmutableList.of(app), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                    ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?, ?>>of(), true));
+            serializer.setLookupContext(newEmptyLookupManagementContext(managementContext, true).add(app));
             assertSerializeAndDeserialize(app);
         } finally {
             Entities.destroyAll(managementContext);
         }
     }
 
+    private LookupContextImpl newEmptyLookupManagementContext(ManagementContext managementContext, boolean failOnDangling) {
+        return new LookupContextImpl(managementContext,
+                ImmutableList.<Entity>of(), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
+                ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?, ?>>of(), ImmutableList.<ManagedBundle>of(), failOnDangling);
+    }
+
     @Test
     public void testLocation() throws Exception {
         final TestApplication app = TestApplication.Factory.newManagedInstanceForTests();
         ManagementContext managementContext = app.getManagementContext();
         try {
             final Location loc = managementContext.getLocationManager().createLocation(LocationSpec.create(SimulatedLocation.class));
-            serializer.setLookupContext(new LookupContextImpl(managementContext,
-                    ImmutableList.<Entity>of(), ImmutableList.of(loc), ImmutableList.<Policy>of(),
-                    ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?, ?>>of(), true));
+            serializer.setLookupContext(newEmptyLookupManagementContext(managementContext, true).add(loc));
             assertSerializeAndDeserialize(loc);
         } finally {
             Entities.destroyAll(managementContext);
@@ -328,9 +332,7 @@ public class XmlMementoSerializerTest {
                     .iconUrl("iconUrl")
                     .libraries(CatalogItemDtoAbstract.parseLibraries(ImmutableList.of("library-url")))
                     .build();
-            serializer.setLookupContext(new LookupContextImpl(managementContext,
-                    ImmutableList.<Entity>of(), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                    ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.of(catalogItem), true));
+            serializer.setLookupContext(newEmptyLookupManagementContext(managementContext, true).add(catalogItem));
             assertSerializeAndDeserialize(catalogItem);
         } finally {
             Entities.destroyAll(managementContext);
@@ -381,10 +383,8 @@ public class XmlMementoSerializerTest {
         EntitySpec<DynamicCluster> spec = EntitySpec.create(DynamicCluster.class)
             .configure(DynamicCluster.INITIAL_SIZE, 1)
             .configure(DynamicCluster.MEMBER_SPEC, mgmt.getTypeRegistry().createSpec(ci, null, EntitySpec.class));
-
-        serializer.setLookupContext(new LookupContextImpl(mgmt,
-            ImmutableList.<Entity>of(), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-            ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?,?>>of(), true));
+        
+        serializer.setLookupContext(newEmptyLookupManagementContext(mgmt, true));
         assertSerializeAndDeserialize(spec);
     }
     
@@ -392,9 +392,7 @@ public class XmlMementoSerializerTest {
     public void testOsgiBundleNameNotIncludedForWhiteListed() throws Exception {
         mgmt = LocalManagementContextForTests.builder(true).disableOsgi(false).build();
 
-        serializer.setLookupContext(new LookupContextImpl(mgmt,
-            ImmutableList.<Entity>of(), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-            ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?,?>>of(), true));
+        serializer.setLookupContext(newEmptyLookupManagementContext(mgmt, true));
         
         Object obj = PersistMode.AUTO;
         
@@ -413,10 +411,7 @@ public class XmlMementoSerializerTest {
         TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), bundlePath);
         
         mgmt = LocalManagementContextForTests.builder(true).disableOsgi(false).build();
-
-        serializer.setLookupContext(new LookupContextImpl(mgmt,
-                ImmutableList.<Entity>of(), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?,?>>of(), true));
+        serializer.setLookupContext(newEmptyLookupManagementContext(mgmt, true));
         
         Bundle bundle = installBundle(mgmt, bundleUrl);
         
@@ -464,9 +459,7 @@ public class XmlMementoSerializerTest {
         serializer = new XmlMementoSerializer<Object>(mgmt.getCatalogClassLoader(),
                 ImmutableMap.<String,String>of());
         
-        serializer.setLookupContext(new LookupContextImpl(mgmt,
-                ImmutableList.<Entity>of(), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?,?>>of(), true));
+        serializer.setLookupContext(newEmptyLookupManagementContext(mgmt, true));
 
         // i.e. prepended with bundle name
         String serializedForm = Joiner.on("\n").join(
@@ -496,9 +489,7 @@ public class XmlMementoSerializerTest {
         serializer = new XmlMementoSerializer<Object>(mgmt.getCatalogClassLoader(),
                 ImmutableMap.of(oldBundlePrefix + ":" + classname, bundlePrefix + ":" + classname));
         
-        serializer.setLookupContext(new LookupContextImpl(mgmt,
-                ImmutableList.<Entity>of(), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?,?>>of(), true));
+        serializer.setLookupContext(newEmptyLookupManagementContext(mgmt, true));
 
         // i.e. prepended with bundle name
         String serializedForm = Joiner.on("\n").join(
@@ -528,10 +519,7 @@ public class XmlMementoSerializerTest {
 
         serializer = new XmlMementoSerializer<Object>(mgmt.getCatalogClassLoader(),
                 ImmutableMap.of(oldClassname, classname));
-        
-        serializer.setLookupContext(new LookupContextImpl(mgmt,
-                ImmutableList.<Entity>of(), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?,?>>of(), true));
+        serializer.setLookupContext(newEmptyLookupManagementContext(mgmt, true));
 
         // i.e. prepended with bundle name
         String serializedForm = Joiner.on("\n").join(
@@ -548,10 +536,7 @@ public class XmlMementoSerializerTest {
     @Test(groups="Broken")
     public void testOsgiBundleNamePrefixIncludedForDownstreamDependency() throws Exception {
         mgmt = LocalManagementContextForTests.builder(true).disableOsgi(false).build();
-
-        serializer.setLookupContext(new LookupContextImpl(mgmt,
-                ImmutableList.<Entity>of(), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?,?>>of(), true));
+        serializer.setLookupContext(newEmptyLookupManagementContext(mgmt, true));
         
         // Using a guava type (which is a downstream dependency of Brooklyn)
         String bundleName = "com.goole.guava";
@@ -575,9 +560,7 @@ public class XmlMementoSerializerTest {
         final TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
         ManagementContext managementContext = app.getManagementContext();
         try {
-            serializer.setLookupContext(new LookupContextImpl(managementContext,
-                    ImmutableList.of(app), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                    ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?, ?>>of(), false));
+            serializer.setLookupContext(newEmptyLookupManagementContext(managementContext, false).add(app));
             
             List<?> resultList = serializeAndDeserialize(ImmutableList.of(app, entity));
             assertEquals(resultList, ImmutableList.of(app));
@@ -599,9 +582,7 @@ public class XmlMementoSerializerTest {
         ReffingEntity reffer = new ReffingEntity(app);
         ManagementContext managementContext = app.getManagementContext();
         try {
-            serializer.setLookupContext(new LookupContextImpl(managementContext,
-                    ImmutableList.of(app), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                    ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?, ?>>of(), true));
+            serializer.setLookupContext(newEmptyLookupManagementContext(managementContext, true).add(app));
             ReffingEntity reffer2 = assertSerializeAndDeserialize(reffer);
             assertEquals(reffer2.entity, app);
         } finally {
@@ -615,9 +596,7 @@ public class XmlMementoSerializerTest {
         ReffingEntity reffer = new ReffingEntity((Object)app);
         ManagementContext managementContext = app.getManagementContext();
         try {
-            serializer.setLookupContext(new LookupContextImpl(managementContext,
-                    ImmutableList.of(app), ImmutableList.<Location>of(), ImmutableList.<Policy>of(),
-                    ImmutableList.<Enricher>of(), ImmutableList.<Feed>of(), ImmutableList.<CatalogItem<?, ?>>of(), true));
+            serializer.setLookupContext(newEmptyLookupManagementContext(managementContext, true).add(app));
             ReffingEntity reffer2 = assertSerializeAndDeserialize(reffer);
             assertEquals(reffer2.obj, app);
         } finally {
@@ -685,7 +664,7 @@ public class XmlMementoSerializerTest {
         LOG.info("serializedForm=" + serializedForm);
         return (T) serializer.fromString(serializedForm);
     }
-
+    
     static class LookupContextImpl implements LookupContext {
         private final ManagementContext mgmt;
         private final Map<String, Entity> entities;
@@ -694,11 +673,13 @@ public class XmlMementoSerializerTest {
         private final Map<String, Enricher> enrichers;
         private final Map<String, Feed> feeds;
         private final Map<String, CatalogItem<?, ?>> catalogItems;
+        private final Map<String, ManagedBundle> bundles;
         private final boolean failOnDangling;
 
         LookupContextImpl(ManagementContext mgmt, Iterable<? extends Entity> entities, Iterable<? extends Location> locations,
                 Iterable<? extends Policy> policies, Iterable<? extends Enricher> enrichers, Iterable<? extends Feed> feeds,
-                Iterable<? extends CatalogItem<?, ?>> catalogItems, boolean failOnDangling) {
+                Iterable<? extends CatalogItem<?, ?>> catalogItems, Iterable<? extends ManagedBundle> bundles,
+                    boolean failOnDangling) {
             this.mgmt = mgmt;
             this.entities = Maps.newLinkedHashMap();
             this.locations = Maps.newLinkedHashMap();
@@ -706,17 +687,20 @@ public class XmlMementoSerializerTest {
             this.enrichers = Maps.newLinkedHashMap();
             this.feeds = Maps.newLinkedHashMap();
             this.catalogItems = Maps.newLinkedHashMap();
+            this.bundles = Maps.newLinkedHashMap();
             for (Entity entity : entities) this.entities.put(entity.getId(), entity);
             for (Location location : locations) this.locations.put(location.getId(), location);
             for (Policy policy : policies) this.policies.put(policy.getId(), policy);
             for (Enricher enricher : enrichers) this.enrichers.put(enricher.getId(), enricher);
             for (Feed feed : feeds) this.feeds.put(feed.getId(), feed);
             for (CatalogItem<?, ?> catalogItem : catalogItems) this.catalogItems.put(catalogItem.getId(), catalogItem);
+            for (ManagedBundle bundle : bundles) this.bundles.put(bundle.getId(), bundle);
             this.failOnDangling = failOnDangling;
         }
         LookupContextImpl(ManagementContext mgmt, Map<String,? extends Entity> entities, Map<String,? extends Location> locations,
                 Map<String,? extends Policy> policies, Map<String,? extends Enricher> enrichers, Map<String,? extends Feed> feeds,
-                Map<String, ? extends CatalogItem<?, ?>> catalogItems, boolean failOnDangling) {
+                Map<String, ? extends CatalogItem<?, ?>> catalogItems, Map<String,? extends ManagedBundle> bundles,
+                boolean failOnDangling) {
             this.mgmt = mgmt;
             this.entities = ImmutableMap.copyOf(entities);
             this.locations = ImmutableMap.copyOf(locations);
@@ -724,6 +708,7 @@ public class XmlMementoSerializerTest {
             this.enrichers = ImmutableMap.copyOf(enrichers);
             this.feeds = ImmutableMap.copyOf(feeds);
             this.catalogItems = ImmutableMap.copyOf(catalogItems);
+            this.bundles = ImmutableMap.copyOf(bundles);
             this.failOnDangling = failOnDangling;
         }
         @Override public ManagementContext lookupManagementContext() {
@@ -783,6 +768,15 @@ public class XmlMementoSerializerTest {
             }
             return null;
         }
+        @Override public ManagedBundle lookupBundle(String id) {
+            if (bundles.containsKey(id)) {
+                return bundles.get(id);
+            }
+            if (failOnDangling) {
+                throw new NoSuchElementException("no bundle with id "+id+"; contenders are "+bundles.keySet());
+            }
+            return null;
+        }
         
         @Override
         public BrooklynObject lookup(BrooklynObjectType type, String id) {
@@ -798,6 +792,7 @@ public class XmlMementoSerializerTest {
             
             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);
@@ -807,6 +802,21 @@ public class XmlMementoSerializerTest {
             }
             throw new IllegalStateException("Unexpected type "+type+" / id "+id);
         }
+        
+        private Map<String,? extends BrooklynObject> getMapFor(BrooklynObjectType type) {
+            switch (type) {
+            case CATALOG_ITEM: return catalogItems;
+            case MANAGED_BUNDLE: return bundles;
+            case ENRICHER: return enrichers;
+            case ENTITY: return entities;
+            case FEED: return feeds;
+            case LOCATION: return locations;
+            case POLICY: return policies;
+            case UNKNOWN: return null;
+            }
+            throw new IllegalStateException("Unexpected type "+type);
+        }
+        
         @Override
         public BrooklynObject peek(BrooklynObjectType type, String id) {
             if (type==null) {
@@ -817,16 +827,18 @@ public class XmlMementoSerializerTest {
                 return null;
             }
             
-            switch (type) {
-            case CATALOG_ITEM: return catalogItems.get(id);
-            case ENRICHER: return enrichers.get(id);
-            case ENTITY: return entities.get(id);
-            case FEED: return feeds.get(id);
-            case LOCATION: return locations.get(id);
-            case POLICY: return policies.get(id);
-            case UNKNOWN: return null;
+            Map<String, ? extends BrooklynObject> map = getMapFor(type);
+            if (map==null) return null;
+            return map.get(id);
+        }
+        
+        @SuppressWarnings("unchecked")
+        @VisibleForTesting
+        public LookupContextImpl add(BrooklynObject object) {
+            if (object!=null) {
+                ((Map<String,BrooklynObject>) getMapFor(BrooklynObjectType.of(object))).put(object.getId(), object);
             }
-            throw new IllegalStateException("Unexpected type "+type+" / id "+id);
+            return this;
         }
     };
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/ManagementPlaneIdTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/ManagementPlaneIdTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/ManagementPlaneIdTest.java
index 22a2371..0fbadff 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/ManagementPlaneIdTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/ManagementPlaneIdTest.java
@@ -76,7 +76,7 @@ public class ManagementPlaneIdTest {
     @Test
     public void testUninitializedThrows() {
         ManagementContext mgmt = new LocalManagementContext(BrooklynProperties.Factory.newEmpty());
-        assertFalse(mgmt.getOptionalManagementPlaneId().isPresent(), "expected managementPlaneId to be absent");
+        assertFalse(mgmt.getManagementPlaneIdMaybe().isPresent(), "expected managementPlaneId to be absent");
     }
     
     @Test
@@ -90,13 +90,13 @@ public class ManagementPlaneIdTest {
         final LocalManagementContext mgmt = createManagementContext(PersistMode.AUTO, HighAvailabilityMode.AUTO);
 
         checkPlaneIdPersisted(mgmt);
-        final String oldPlaneId = mgmt.getOptionalManagementPlaneId().get();
+        final String oldPlaneId = mgmt.getManagementPlaneIdMaybe().get();
         mgmt.setManagementPlaneId(Strings.makeRandomId(8));
-        assertNotEquals(oldPlaneId, mgmt.getOptionalManagementPlaneId().get());
+        assertNotEquals(oldPlaneId, mgmt.getManagementPlaneIdMaybe().get());
         Asserts.succeedsEventually(new Runnable() {
             @Override
             public void run() {
-                assertEquals(oldPlaneId, mgmt.getOptionalManagementPlaneId().get());
+                assertEquals(oldPlaneId, mgmt.getManagementPlaneIdMaybe().get());
             }
         });
     }
@@ -109,7 +109,7 @@ public class ManagementPlaneIdTest {
 
         LocalManagementContext rebindMgmt = createManagementContext(PersistMode.AUTO, HighAvailabilityMode.DISABLED);
 
-        assertEquals(origMgmt.getOptionalManagementPlaneId(), rebindMgmt.getOptionalManagementPlaneId());
+        assertEquals(origMgmt.getManagementPlaneIdMaybe(), rebindMgmt.getManagementPlaneIdMaybe());
     }
 
 
@@ -131,7 +131,7 @@ public class ManagementPlaneIdTest {
         Asserts.succeedsEventually(new Runnable() {
             @Override
             public void run() {
-                assertEquals(origMgmt.getOptionalManagementPlaneId(), rebindMgmt.getOptionalManagementPlaneId());
+                assertEquals(origMgmt.getManagementPlaneIdMaybe(), rebindMgmt.getManagementPlaneIdMaybe());
             }
         });
     }
@@ -144,7 +144,7 @@ public class ManagementPlaneIdTest {
         Asserts.succeedsEventually(new Runnable() {
             @Override
             public void run() {
-                assertEquals(origMgmt.getOptionalManagementPlaneId(), rebindMgmt.getOptionalManagementPlaneId());
+                assertEquals(origMgmt.getManagementPlaneIdMaybe(), rebindMgmt.getManagementPlaneIdMaybe());
             }
         });
 
@@ -160,7 +160,7 @@ public class ManagementPlaneIdTest {
             }
         });
 
-        assertEquals(origMgmt.getOptionalManagementPlaneId(), rebindMgmt.getOptionalManagementPlaneId());
+        assertEquals(origMgmt.getManagementPlaneIdMaybe(), rebindMgmt.getManagementPlaneIdMaybe());
     }
     
     @Test
@@ -171,7 +171,7 @@ public class ManagementPlaneIdTest {
 
         LocalManagementContext rebindMgmt = createManagementContextWithBackups(PersistMode.AUTO, HighAvailabilityMode.AUTO);
 
-        assertEquals(origMgmt.getOptionalManagementPlaneId(), rebindMgmt.getOptionalManagementPlaneId());
+        assertEquals(origMgmt.getManagementPlaneIdMaybe(), rebindMgmt.getManagementPlaneIdMaybe());
 
         String backupContainer = BrooklynServerPaths.newBackupPersistencePathResolver(rebindMgmt).resolve();
         
@@ -186,7 +186,7 @@ public class ManagementPlaneIdTest {
         
         File planeIdFile = new File(promotionFolders[0], BrooklynMementoPersisterToObjectStore.PLANE_ID_FILE_NAME);
         String planeId = readFile(planeIdFile);
-        assertEquals(origMgmt.getOptionalManagementPlaneId().get(), planeId);
+        assertEquals(origMgmt.getManagementPlaneIdMaybe().get(), planeId);
     }
     
     @Test
@@ -235,7 +235,7 @@ public class ManagementPlaneIdTest {
             @Override
             public Void call() throws Exception {
                 String planeId = readFile(planeIdFile);
-                assertEquals(mgmt.getOptionalManagementPlaneId().get(), planeId);
+                assertEquals(mgmt.getManagementPlaneIdMaybe().get(), planeId);
                 return null;
             }
         });

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
index 4ede973..4c63cb1 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindTestFixture.java
@@ -43,7 +43,6 @@ import org.apache.brooklyn.core.entity.StartableApplication;
 import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.internal.BrooklynProperties;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
 import org.apache.brooklyn.core.mgmt.persist.FileBasedObjectStore;
 import org.apache.brooklyn.core.mgmt.persist.PersistMode;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java
index 02dfadb..9f8e582 100644
--- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformerTest.java
@@ -169,7 +169,7 @@ public class CompoundTransformerTest extends RebindTestFixtureWithApp {
 
         // Assert has expected config/fields
         assertEquals(newApp.getId(), origApp.getId());
-        assertEquals(origManagementContext.getOptionalManagementPlaneId(), newManagementContext.getOptionalManagementPlaneId());
+        assertEquals(origManagementContext.getManagementPlaneIdMaybe(), newManagementContext.getManagementPlaneIdMaybe());
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java b/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java
index 41b0ff9..404d4f8 100644
--- a/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java
+++ b/core/src/test/java/org/apache/brooklyn/core/plan/XmlPlanToSpecTransformer.java
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
+import org.apache.brooklyn.core.typereg.UnsupportedTypePlanException;
 import org.apache.brooklyn.entity.stock.BasicApplication;
 import org.apache.brooklyn.entity.stock.BasicEntity;
 import org.apache.brooklyn.util.exceptions.Exceptions;
@@ -79,14 +80,14 @@ public class XmlPlanToSpecTransformer implements PlanToSpecTransformer {
     @SuppressWarnings({ "unchecked" })
     @Override
     public <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createCatalogSpec(CatalogItem<T, SpecT> item, Set<String> encounteredTypes) {
-        if (item.getPlanYaml()==null) throw new PlanNotRecognizedException("Plan is null");
+        if (item.getPlanYaml()==null) throw new UnsupportedTypePlanException("Plan is null");
         if (item.getCatalogItemType()==CatalogItemType.ENTITY) {
             return (SpecT)toEntitySpec(parseXml(item.getPlanYaml()), 1);
         }
         if (item.getCatalogItemType()==CatalogItemType.TEMPLATE) {
             return (SpecT)toEntitySpec(parseXml(item.getPlanYaml()), 0);
         }
-        throw new PlanNotRecognizedException("Type "+item.getCatalogItemType()+" not supported");
+        throw new UnsupportedTypePlanException("Type "+item.getCatalogItemType()+" not supported");
     }
 
     private Document parseXml(String plan) {
@@ -102,7 +103,7 @@ public class XmlPlanToSpecTransformer implements PlanToSpecTransformer {
             
         } catch (Exception e) {
             Exceptions.propagateIfFatal(e);
-            throw new PlanNotRecognizedException(e);
+            throw new UnsupportedTypePlanException(e);
         }
         return dom;
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/locations/jclouds/src/main/java/org/apache/brooklyn/core/mgmt/persist/jclouds/JcloudsStoreObjectAccessor.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/core/mgmt/persist/jclouds/JcloudsStoreObjectAccessor.java b/locations/jclouds/src/main/java/org/apache/brooklyn/core/mgmt/persist/jclouds/JcloudsStoreObjectAccessor.java
index bc64b84..d2af5ae 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/core/mgmt/persist/jclouds/JcloudsStoreObjectAccessor.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/core/mgmt/persist/jclouds/JcloudsStoreObjectAccessor.java
@@ -18,13 +18,12 @@
  */
 package org.apache.brooklyn.core.mgmt.persist.jclouds;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.Date;
 
 import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
 import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.stream.Streams;
 import org.apache.commons.io.Charsets;
 import org.jclouds.blobstore.BlobStore;
 import org.jclouds.blobstore.domain.Blob;
@@ -32,7 +31,6 @@ import org.jclouds.util.Strings2;
 
 import com.google.common.base.Throwables;
 import com.google.common.io.ByteSource;
-import com.google.common.io.ByteStreams;
 
 /**
  * @author Andrea Turli
@@ -57,11 +55,13 @@ public class JcloudsStoreObjectAccessor implements PersistenceObjectStore.StoreO
     @Override
     public void put(String val) {
         if (val==null) val = "";
-        
+        put(ByteSource.wrap(val.getBytes(Charsets.UTF_8)));
+    }
+    
+    public void put(ByteSource payload) {
         blobStore.createContainerInLocation(null, containerName);
         // seems not needed, at least not w SoftLayer
 //        blobStore.createDirectory(containerName, directoryName);
-        ByteSource payload = ByteSource.wrap(val.getBytes(Charsets.UTF_8));
         Blob blob;
         try {
             blob = blobStore.blobBuilder(blobName).payload(payload)
@@ -104,14 +104,7 @@ public class JcloudsStoreObjectAccessor implements PersistenceObjectStore.StoreO
         try {
             Blob blob = blobStore.getBlob(containerName, blobName);
             if (blob==null) return null;
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            InputStream in = blob.getPayload().openStream();
-            try {
-                ByteStreams.copy(in, out);
-                return out.toByteArray();
-            } finally {
-                out.close();
-            }
+            return Streams.readFullyAndClose(blob.getPayload().openStream());
         } catch (IOException e) {
             Exceptions.propagateIfFatal(e);
             throw new IllegalStateException("Error reading blobstore "+containerName+" "+blobName+": "+e, e);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
index 677b84f..24bd47e 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
@@ -47,16 +47,14 @@ 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.RegisteredType;
-import org.apache.brooklyn.core.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.catalog.CatalogPredicates;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
-import org.apache.brooklyn.core.catalog.internal.CatalogBundleLoader;
 import org.apache.brooklyn.core.catalog.internal.CatalogDto;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemComparator;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.StringAndArgument;
-import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
 import org.apache.brooklyn.rest.api.CatalogApi;
@@ -83,7 +81,6 @@ import org.apache.brooklyn.util.yaml.Yamls;
 import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
 import org.apache.commons.compress.archivers.zip.ZipFile;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -232,39 +229,14 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
             BasicManagedBundle bundleMetadata = new BasicManagedBundle(bundleNameInMF, bundleVersionInMF, null);
             Bundle bundle;
             try (FileInputStream f2in = new FileInputStream(f2)) {
-                bundle =
-                    ((LocalManagementContext)mgmt()).getOsgiManager().get().installUploadedBundle(bundleMetadata, f2in);
+                bundle = ((ManagementContextInternal)mgmt()).getOsgiManager().get().installUploadedBundle(bundleMetadata, f2in, false);
             } catch (Exception e) {
                 throw Exceptions.propagate(e);
             }
 
-            Iterable<? extends CatalogItem<?, ?>> catalogItems = MutableList.of();
-            
-            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);
-                }
-            }
+            Iterable<? extends CatalogItem<?, ?>> catalogItems = MutableList.copyOf( 
+                ((ManagementContextInternal)mgmt()).getOsgiManager().get().loadCatalogBom(bundle) );
 
-            // TODO improve on this - Currently, the added items are returned ONLY if the FEATURE_LOAD_BUNDLE_CATALOG_BOM
-            // is disabled. When enabled, the above code is not executed and the catalog items addition is delegated
-            // to the CatalogBomScanner. The REST API will therefore not know what are the added catalog items and won't
-            // return them.
-            // One way to improved this would be couple agoin the CatalogBomScanner with the CatalogBundleLoader to
-            // retrieve the list of added catalog items per bundle.
             return buildCreateResponse(catalogItems);
         } catch (RuntimeException ex) {
             throw WebResourceUtils.badRequest(ex);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java b/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java
index 624613b..0f34357 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java
@@ -150,6 +150,17 @@ public class Streams {
             throw Exceptions.propagate(ioe);
         }
     }
+    
+    /** copies and closes both */
+    public static void copyClose(InputStream input, OutputStream output) {
+        try {
+            copy(input, output);
+        } catch (RuntimeException e) {
+            closeQuietly(input);
+            closeQuietly(output);
+            throw e;
+        }
+    }
 
     public static void copy(Reader input, Writer output) {
         try {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/utils/common/src/main/java/org/apache/brooklyn/util/text/StringShortener.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/text/StringShortener.java b/utils/common/src/main/java/org/apache/brooklyn/util/text/StringShortener.java
index d531f79..89cd7cc 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/text/StringShortener.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/text/StringShortener.java
@@ -66,11 +66,11 @@ public class StringShortener {
         return input;
     }
 
-    public StringShortener setAllowedCharacters(String disalowedCharacters) {
+    public StringShortener setAllowedCharacters(String allowedCharacters) {
         this.allowedCharacters = new HashSet<>();
-        for(char c : disalowedCharacters.toCharArray()) {
+        for (char c : allowedCharacters.toCharArray()) {
             this.allowedCharacters.add(c);
-            }
+        }
         return this;
     }
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java b/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
index 39ae99c..e11993a 100644
--- a/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
@@ -26,7 +26,7 @@ package org.apache.brooklyn.util.osgi;
  * Some of these bundles are also used in REST API tests, as that stretches catalog further
  * (using CAMP) and that is one area where OSGi is heavily used. 
  */
-public class OsgiTestResources {
+public interface OsgiTestResources {
 
     /**
      * brooklyn-osgi-test-a_0.1.0 -
@@ -101,5 +101,14 @@ public class OsgiTestResources {
      * at runtime.
      */
     public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH = "/brooklyn/osgi/" + BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_evil-twin_0.2.0.jar";
+
+
+    public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = "classpath:"+OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH;
+
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V1_PATH;
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V2_PATH;
+    public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH;
     
+    public static final String TEST_VERSION = "0.1.0";
+
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/abd0cb8b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringShortenerTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/text/StringShortenerTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringShortenerTest.java
index 201c3e6..592aea7 100644
--- a/utils/common/src/test/java/org/apache/brooklyn/util/text/StringShortenerTest.java
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/text/StringShortenerTest.java
@@ -44,7 +44,7 @@ public class StringShortenerTest {
     }
 
     @Test
-    public void testDisalowedCharactersShortener() {
+    public void testDisallowedCharactersShortener() {
         StringShortener ss = new StringShortener()
                 .setAllowedCharacters(Identifiers.UPPER_CASE_ALPHA+Identifiers.LOWER_CASE_ALPHA+Identifiers.NUMERIC)
                 .separator("-")


[13/13] brooklyn-server git commit: Closes #645

Posted by ge...@apache.org.
Closes #645

Persist OSGi bundles

This works to persist bundles and is ready for review.  However it has conflicts and needs to be reconciled with #338 -- both coming soon.


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

Branch: refs/heads/master
Commit: ce5ee7b866494f148d1f4af9a0c157882c9c11e9
Parents: d09b58f 6938922
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Fri Apr 28 11:31:50 2017 +0100
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Fri Apr 28 11:31:50 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/api/entity/Entity.java  |   8 +-
 .../brooklyn/api/mgmt/ManagementContext.java    |  23 +--
 .../api/mgmt/rebind/RebindExceptionHandler.java |   8 +-
 .../mgmt/rebind/mementos/BrooklynMemento.java   |   3 +
 .../mementos/BrooklynMementoManifest.java       |   7 +-
 .../mementos/BrooklynMementoPersister.java      |   4 +
 .../rebind/mementos/BrooklynMementoRawData.java |  38 +++-
 .../rebind/mementos/CatalogItemMemento.java     |   1 +
 .../rebind/mementos/ManagedBundleMemento.java   |  33 ++++
 .../brooklyn/api/objs/BrooklynObjectType.java   |   4 +-
 .../api/typereg/BrooklynTypeRegistry.java       |   2 +-
 .../brooklyn/api/typereg/ManagedBundle.java     |  32 ++++
 .../brooklyn/api/typereg/OsgiBundleWithUrl.java |   2 +-
 .../spi/creation/CampToSpecTransformer.java     |   8 +-
 .../camp/brooklyn/AbstractYamlRebindTest.java   |  13 ++
 .../catalog/CatalogMakeOsgiBundleTest.java      |  13 +-
 .../CatalogOsgiVersionMoreEntityRebindTest.java |  33 +++-
 .../CatalogOsgiVersionMoreEntityTest.java       |  30 +++-
 .../catalog/CatalogYamlTemplateTest.java        |   3 +-
 .../core/BrooklynFeatureEnablement.java         |   4 +
 .../internal/JavaCatalogToSpecTransformer.java  |  10 +-
 .../brooklyn/core/entity/AbstractEntity.java    |   8 +-
 .../mgmt/ha/HighAvailabilityManagerImpl.java    |  26 +--
 .../brooklyn/core/mgmt/ha/OsgiManager.java      | 155 +++++++++++++---
 .../internal/AbstractManagementContext.java     |   2 +-
 .../mgmt/internal/LocalManagementContext.java   |  11 +-
 .../NonDeploymentManagementContext.java         |   5 +-
 .../BrooklynMementoPersisterToObjectStore.java  | 123 +++++++++++--
 .../mgmt/persist/BrooklynPersistenceUtils.java  |  34 ++--
 .../persist/FileBasedStoreObjectAccessor.java   |  16 +-
 .../mgmt/persist/PersistenceObjectStore.java    |   2 +
 .../persist/StoreObjectAccessorLocking.java     |  24 +++
 .../core/mgmt/persist/XmlMementoSerializer.java |   5 +-
 .../AbstractBrooklynObjectRebindSupport.java    |   1 -
 .../rebind/ActivePartialRebindIteration.java    |  19 +-
 .../rebind/BasicManagedBundleRebindSupport.java |  41 +++++
 .../rebind/ImmediateDeltaChangeListener.java    |  10 +-
 .../rebind/PeriodicDeltaChangeListener.java     |  33 ++--
 .../core/mgmt/rebind/PersisterDeltaImpl.java    |  21 ++-
 .../core/mgmt/rebind/RebindContextImpl.java     |  23 ++-
 .../mgmt/rebind/RebindContextLookupContext.java |  13 ++
 .../mgmt/rebind/RebindExceptionHandlerImpl.java |  16 +-
 .../core/mgmt/rebind/RebindIteration.java       |  37 +++-
 .../core/mgmt/rebind/RebindManagerImpl.java     |   4 +-
 .../core/mgmt/rebind/dto/AbstractMemento.java   |   6 +-
 .../rebind/dto/AbstractTreeNodeMemento.java     |   4 +-
 .../rebind/dto/BasicCatalogItemMemento.java     |   4 +-
 .../mgmt/rebind/dto/BasicEnricherMemento.java   |   4 +-
 .../mgmt/rebind/dto/BasicEntityMemento.java     |   4 +-
 .../core/mgmt/rebind/dto/BasicFeedMemento.java  |   4 +-
 .../mgmt/rebind/dto/BasicLocationMemento.java   |   4 +-
 .../rebind/dto/BasicManagedBundleMemento.java   | 135 ++++++++++++++
 .../mgmt/rebind/dto/BasicPolicyMemento.java     |   4 +-
 .../mgmt/rebind/dto/BrooklynMementoImpl.java    |  25 ++-
 .../rebind/dto/BrooklynMementoManifestImpl.java |  33 +++-
 .../mgmt/rebind/dto/MementosGenerators.java     |  13 ++
 .../mgmt/rebind/dto/MutableBrooklynMemento.java |  27 +++
 .../rebind/transformer/CompoundTransformer.java |  15 ++
 .../brooklyn/core/plan/PlanToSpecFactory.java   |   6 +-
 .../core/plan/PlanToSpecTransformer.java        |   9 +-
 .../core/typereg/BasicBrooklynTypeRegistry.java |   4 +
 .../core/typereg/BasicManagedBundle.java        | 175 +++++++++++++++++++
 .../core/typereg/BasicOsgiBundleWithUrl.java    |  13 +-
 .../core/typereg/TypePlanTransformers.java      |   6 +-
 .../brooklyn/util/core/osgi/BundleMaker.java    |   7 +-
 .../HighAvailabilityManagerSplitBrainTest.java  |   6 +-
 .../ha/HighAvailabilityManagerTestFixture.java  |   2 +-
 .../brooklyn/core/mgmt/ha/HotStandbyTest.java   |   4 +-
 .../brooklyn/core/mgmt/ha/WarmStandbyTest.java  |   4 +-
 .../mgmt/osgi/OsgiVersionMoreEntityTest.java    |  16 +-
 .../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     |   3 +-
 .../core/mgmt/rebind/RebindTestUtils.java       |   8 +-
 .../rebind/RecordingRebindExceptionHandler.java |   2 +-
 .../transformer/CompoundTransformerTest.java    |   6 +-
 .../core/plan/XmlPlanToSpecTransformer.java     |   7 +-
 .../util/core/osgi/BundleMakerTest.java         |   3 +-
 .../brooklyn/launcher/common/BasicLauncher.java |   4 +-
 .../AbstractCleanOrphanedStateTest.java         |   1 +
 .../CleanOrphanedLocationsIntegrationTest.java  |   4 +-
 .../jclouds/JcloudsStoreObjectAccessor.java     |  19 +-
 .../apache/brooklyn/rest/api/CatalogApi.java    |   1 +
 .../rest/resources/CatalogResource.java         |  48 ++---
 .../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 +-
 .../brooklyn-test-osgi-com-example-entities.jar | Bin 22144 -> 22130 bytes
 .../osgi/brooklyn-test-osgi-entities.jar        | Bin 22075 -> 22067 bytes
 .../brooklyn-test-osgi-more-entities_0.1.0.jar  | Bin 16004 -> 15997 bytes
 .../brooklyn-test-osgi-more-entities_0.2.0.jar  | Bin 16906 -> 16903 bytes
 ...-test-osgi-more-entities_evil-twin_0.2.0.jar | Bin 13811 -> 14091 bytes
 96 files changed, 1401 insertions(+), 390 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/ce5ee7b8/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------


[09/13] brooklyn-server git commit: use bundle metadata from BOM file

Posted by ge...@apache.org.
use bundle metadata from BOM file


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

Branch: refs/heads/master
Commit: 99dfb6f98837dd04c7a18a5767c8537af9e3b949
Parents: c9fd077
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Apr 24 15:19:53 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Apr 24 15:21:45 2017 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/rest/resources/CatalogResource.java    | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/99dfb6f9/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
index 24bd47e..f1d8638 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
@@ -209,7 +209,8 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                     throw new IllegalArgumentException("JAR MANIFEST symbolic-name '"+bundleNameInMF+"' does not match '"+vn.getSymbolicName()+"' defined in BOM");
                 }
             } else {
-                mf.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, vn.getSymbolicName());
+                bundleNameInMF = vn.getSymbolicName();
+                mf.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, bundleNameInMF);
             }
             
             String bundleVersionInMF = mf.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
@@ -218,7 +219,8 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
                     throw new IllegalArgumentException("JAR MANIFEST version '"+bundleVersionInMF+"' does not match '"+vn.getVersion()+"' defined in BOM");
                 }
             } else {
-                mf.getMainAttributes().putValue(Constants.BUNDLE_VERSION, vn.getVersion().toString());
+                bundleVersionInMF = vn.getVersion().toString();
+                mf.getMainAttributes().putValue(Constants.BUNDLE_VERSION, bundleVersionInMF);
             }
             if (mf.getMainAttributes().getValue(Attributes.Name.MANIFEST_VERSION)==null) {
                 mf.getMainAttributes().putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0");


[06/13] brooklyn-server git commit: Merge branch 'master' into persist-osgi-bundles

Posted by ge...@apache.org.
Merge branch 'master' into persist-osgi-bundles


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

Branch: refs/heads/master
Commit: 340e036d78ed3c55317c5d38bf3d2cc9791d6b0b
Parents: abd0cb8 b08c482
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Apr 22 00:05:32 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Apr 22 00:05:32 2017 +0100

----------------------------------------------------------------------
 .../internal/AbstractBrooklynObjectSpec.java    | 211 ++++++++++----
 .../mementos/BrooklynMementoManifest.java       |  36 +--
 .../api/mgmt/rebind/mementos/Memento.java       |  33 ++-
 .../brooklyn/api/objs/BrooklynObject.java       |  19 ++
 .../brooklyn/spi/creation/CampResolver.java     |   2 +-
 .../brooklyn/camp/brooklyn/RebindOsgiTest.java  |  54 ++++
 .../catalog/CatalogOsgiYamlEntityTest.java      |  59 +++-
 .../brooklyn/catalog/CatalogYamlEntityTest.java |  79 +++---
 .../brooklyn/catalog/CatalogYamlRebindTest.java | 273 +++++++++----------
 .../src/test/yaml/python-webserver.bom          |  98 +++++++
 .../core/catalog/internal/CatalogItemDo.java    |  21 ++
 .../internal/CatalogItemDtoAbstract.java        |   5 +-
 .../core/catalog/internal/CatalogUtils.java     |  26 +-
 .../internal/JavaCatalogToSpecTransformer.java  |   8 +-
 .../apache/brooklyn/core/entity/Entities.java   |   9 +
 .../access/PortForwardManagerClient.java        |   6 +
 .../core/mgmt/EntityManagementUtils.java        |   7 +-
 .../BrooklynClassLoadingContextSequential.java  |   7 +-
 .../internal/AbstractManagementContext.java     |  17 +-
 .../BrooklynMementoPersisterToObjectStore.java  |  61 +++--
 .../core/mgmt/rebind/RebindIteration.java       | 233 ++++++++++------
 .../core/mgmt/rebind/dto/AbstractMemento.java   |  30 +-
 .../rebind/dto/BrooklynMementoManifestImpl.java |   5 +-
 .../rebind/dto/EntityMementoManifestImpl.java   |  13 +-
 .../mgmt/rebind/dto/MementosGenerators.java     |   5 +-
 .../rebind/transformer/CompoundTransformer.java |  30 +-
 .../core/objs/AbstractBrooklynObject.java       |  60 +++-
 .../core/objs/AbstractEntityAdjunct.java        |   8 +-
 .../core/objs/BrooklynObjectInternal.java       |   9 +
 .../core/objs/proxy/InternalEntityFactory.java  |  14 +-
 .../objs/proxy/InternalLocationFactory.java     |  13 +-
 .../core/objs/proxy/InternalPolicyFactory.java  |  24 +-
 .../resolve/entity/JavaEntitySpecResolver.java  |   2 +-
 .../typereg/AbstractTypePlanTransformer.java    |   3 +-
 .../brooklyn/util/core/ClassLoaderUtils.java    |  40 ++-
 .../brooklyn/util/core/xstream/XmlUtil.java     |  26 +-
 .../core/mgmt/osgi/OsgiStandaloneTest.java      |   2 +
 .../rebind/RebindConfigInheritanceTest.java     |   2 +-
 .../util/core/ClassLoaderUtilsTest.java         |   3 +-
 .../brooklyn/util/osgi/OsgiTestResources.java   |   2 +
 40 files changed, 1082 insertions(+), 473 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java
----------------------------------------------------------------------
diff --cc api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java
index 97fd91a,fa56d1d..41ca61e
--- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java
+++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/BrooklynMementoManifest.java
@@@ -32,33 -33,31 +33,34 @@@ import org.apache.brooklyn.api.objs.Ide
  public interface BrooklynMementoManifest extends Serializable {
      public interface EntityMementoManifest extends Identifiable{
          @Override
-         public String getId();
-         public String getType();
-         public String getParent();
-         public String getCatalogItemId();
+         String getId();
+         String getType();
+         String getParent();
+         String getCatalogItemId();
+         List<String> getCatalogItemIdSearchPath();
      }
  
-     public String getPlaneId();
+     String getPlaneId();
  
-     public Map<String, EntityMementoManifest> getEntityIdToManifest();
+     Map<String, EntityMementoManifest> getEntityIdToManifest();
  
-     public Map<String, String> getLocationIdToType();
+     Map<String, String> getLocationIdToType();
  
-     public Map<String, String> getPolicyIdToType();
+     Map<String, String> getPolicyIdToType();
  
-     public Map<String, String> getEnricherIdToType();
+     Map<String, String> getEnricherIdToType();
  
-     public Map<String, String> getFeedIdToType();
+     Map<String, String> getFeedIdToType();
      
-     public CatalogItemMemento getCatalogItemMemento(String id);
-     public Collection<String> getCatalogItemIds();
-     public Map<String, CatalogItemMemento> getCatalogItemMementos();
+     CatalogItemMemento getCatalogItemMemento(String id);
 -
+     Collection<String> getCatalogItemIds();
 -
+     Map<String, CatalogItemMemento> getCatalogItemMementos();
  
-     public ManagedBundleMemento getBundle(String id);
++    ManagedBundleMemento getBundle(String id);
 +    /** returns UID not symbolic name + version */
-     public Collection<String> getBundleIds();
-     public Map<String, ManagedBundleMemento> getBundles();
++    Collection<String> getBundleIds();
++    Map<String, ManagedBundleMemento> getBundles();
 +
-     public boolean isEmpty();
+     boolean isEmpty();
      
  }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
----------------------------------------------------------------------
diff --cc core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
index 2c76520,e8bb23b..4e4fcb0
--- 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
@@@ -29,9 -29,10 +29,10 @@@ import org.apache.brooklyn.api.mgmt.Man
  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.mgmt.classloading.BrooklynClassLoadingContextSequential;
  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;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/core/src/main/java/org/apache/brooklyn/core/mgmt/internal/AbstractManagementContext.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java
----------------------------------------------------------------------
diff --cc core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterToObjectStore.java
index 142bcbc,2e0b8bf..7707adb
--- 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
@@@ -55,14 -53,14 +56,16 @@@ import org.apache.brooklyn.config.Confi
  import org.apache.brooklyn.config.StringConfigMap;
  import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
  import org.apache.brooklyn.core.config.ConfigKeys;
+ import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential;
  import org.apache.brooklyn.core.mgmt.classloading.ClassLoaderFromBrooklynClassLoadingContext;
 +import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
  import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore.StoreObjectAccessor;
  import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore.StoreObjectAccessorWithLock;
  import org.apache.brooklyn.core.mgmt.rebind.PeriodicDeltaChangeListener;
  import org.apache.brooklyn.core.mgmt.rebind.dto.BrooklynMementoImpl;
  import org.apache.brooklyn.core.mgmt.rebind.dto.BrooklynMementoManifestImpl;
 +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.xstream.XmlUtil;
@@@ -354,9 -335,36 +364,35 @@@ public class BrooklynMementoPersisterTo
          return result;
      }
  
+     private static class XPathHelper {
+         private String contents;
+         private String prefix;
+ 
+         public XPathHelper(String contents, String prefix) {
+             this.contents = contents;
+             this.prefix = prefix;
+         }
+ 
+         private String get(String innerPath) {
+             return (String) XmlUtil.xpathHandlingIllegalChars(contents, prefix+innerPath);
+         }
+         private List<String> getStringList(String innerPath) {
+             List<String> result = MutableList.of();
+             final NodeList nodeList =
+                 (NodeList) XmlUtil.xpathHandlingIllegalChars(contents, prefix + innerPath + "//string", XPathConstants.NODESET);
+             for(int c = 0 ; c < nodeList.getLength() ; c++) {
+                 result.add(nodeList.item(c).getFirstChild().getNodeValue());
+             }
+             return result;
+         }
+     }
+ 
+ 
      @Override
-     public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mementoDataR, final RebindExceptionHandler exceptionHandler) throws IOException {
 -    public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mementoData,
++    public BrooklynMementoManifest loadMementoManifest(BrooklynMementoRawData mementoDataR,
+                                                        final RebindExceptionHandler exceptionHandler) throws IOException {
 -        if (mementoData==null)
 -            mementoData = loadMementoRawData(exceptionHandler);
 +        final BrooklynMementoRawData mementoData = mementoDataR==null ? loadMementoRawData(exceptionHandler) : mementoDataR;
+         
          final BrooklynMementoManifestImpl.Builder builder = BrooklynMementoManifestImpl.builder();
  
          builder.planeId(mementoData.getPlaneId());

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --cc core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
index 92a87a7,ad12c52..5ed1dd5
--- 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
@@@ -19,9 -19,11 +19,12 @@@
  package org.apache.brooklyn.core.mgmt.rebind;
  
  import static com.google.common.base.Preconditions.checkNotNull;
+ import static org.apache.brooklyn.core.BrooklynFeatureEnablement.FEATURE_AUTO_FIX_CATALOG_REF_ON_REBIND;
+ import static org.apache.brooklyn.core.BrooklynFeatureEnablement.FEATURE_BACKWARDS_COMPATIBILITY_INFER_CATALOG_ITEM_ON_REBIND;
+ import static org.apache.brooklyn.core.catalog.internal.CatalogUtils.newClassLoadingContextForCatalogItems;
  
  import java.io.IOException;
 +import java.io.InputStream;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.List;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/AbstractMemento.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BrooklynMementoManifestImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/transformer/CompoundTransformer.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/340e036d/utils/common/src/test/java/org/apache/brooklyn/util/osgi/OsgiTestResources.java
----------------------------------------------------------------------


[10/13] brooklyn-server git commit: call it `bundles/` in the persisted space, not `bundle/`

Posted by ge...@apache.org.
call it `bundles/` in the persisted space, not `bundle/`


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

Branch: refs/heads/master
Commit: 3097bb985e7a5a158acd6a4d0215e56008273498
Parents: 99dfb6f
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Apr 24 16:46:23 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Apr 24 16:46:23 2017 +0100

----------------------------------------------------------------------
 .../main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3097bb98/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java
index 1fabaf2..60021f5 100644
--- a/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java
+++ b/api/src/main/java/org/apache/brooklyn/api/objs/BrooklynObjectType.java
@@ -43,7 +43,7 @@ public enum BrooklynObjectType {
     @SuppressWarnings("unchecked") ENRICHER(Enricher.class, EnricherSpec.class, "enrichers"),
     FEED(Feed.class, null, "feeds"),
     CATALOG_ITEM(CatalogItem.class, null, "catalog"),
-    MANAGED_BUNDLE(ManagedBundle.class, null, "bundle"),
+    MANAGED_BUNDLE(ManagedBundle.class, null, "bundles"),
     UNKNOWN(null, null, "unknown");
     
     private final Class<? extends BrooklynObject> interfaceType;


[11/13] brooklyn-server git commit: Merge branch 'master' into persist-osgi-bundles

Posted by ge...@apache.org.
Merge branch 'master' into persist-osgi-bundles

conflict - minor api change passing managementContext


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

Branch: refs/heads/master
Commit: b157ff8b19643e7242651c93e46230be698c660f
Parents: 3097bb9 022fb2f
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Apr 25 21:23:29 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Apr 25 21:23:29 2017 +0100

----------------------------------------------------------------------
 .../camp/brooklyn/ConfigParametersYamlTest.java | 67 ++++++++++++++++++++
 .../mgmt/persist/BrooklynPersistenceUtils.java  | 16 +++--
 .../brooklyn/core/objs/BasicSpecParameter.java  | 26 +++++++-
 3 files changed, 104 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b157ff8b/core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynPersistenceUtils.java
----------------------------------------------------------------------
diff --cc core/src/main/java/org/apache/brooklyn/core/mgmt/persist/BrooklynPersistenceUtils.java
index b3e17c5,1219e10..0899ed1
--- 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
@@@ -107,10 -104,15 +107,14 @@@ public class BrooklynPersistenceUtils 
              PersistenceObjectStore destinationObjectStore) {
          BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
              destinationObjectStore,
 -            ((ManagementContextInternal)managementContext).getBrooklynProperties(),
 -            managementContext.getCatalogClassLoader());
 +            managementContext);
-         PersistenceExceptionHandler exceptionHandler = PersistenceExceptionHandlerImpl.builder().build();
-         persister.enableWriteAccess();
-         persister.checkpoint(memento, exceptionHandler);
+         try {
+             PersistenceExceptionHandler exceptionHandler = PersistenceExceptionHandlerImpl.builder().build();
+             persister.enableWriteAccess();
+             persister.checkpoint(memento, exceptionHandler);
+         } finally {
+             persister.stop(true);
+         }
      }
  
      public static void writeManagerMemento(ManagementContext managementContext, ManagementPlaneSyncRecord optionalPlaneRecord,


[08/13] brooklyn-server git commit: don't use the deprecated method when given json input

Posted by ge...@apache.org.
don't use the deprecated method when given json input


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

Branch: refs/heads/master
Commit: c9fd07703b7d072da2508e740be229ed7eb1e41f
Parents: cee8e1e
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Mon Apr 24 15:17:46 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Mon Apr 24 15:21:40 2017 +0100

----------------------------------------------------------------------
 .../src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java      | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/c9fd0770/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
index 12a6e93..dbdc847 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
@@ -54,6 +54,7 @@ public interface CatalogApi {
 
     /** @deprecated since 0.11.0 use {@link #createFromYaml(String)} instead */
     @Deprecated
+    @Consumes("application/json-deprecated")  // prevent this from taking things
     @POST
     @ApiOperation(
             value = "Add a catalog items (e.g. new type of entity, policy or location) by uploading YAML descriptor.",


[12/13] brooklyn-server git commit: address PR review comments

Posted by ge...@apache.org.
address PR review comments


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

Branch: refs/heads/master
Commit: 6938922da2a5e1d9327219e91c219edbbeebe1c0
Parents: b157ff8
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Apr 27 15:31:37 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Apr 27 15:31:37 2017 +0100

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/api/typereg/ManagedBundle.java | 3 +++
 .../mgmt/persist/BrooklynMementoPersisterToObjectStore.java | 6 +++++-
 .../core/mgmt/persist/BrooklynPersistenceUtils.java         | 2 +-
 .../core/mgmt/persist/FileBasedStoreObjectAccessor.java     | 3 +--
 .../apache/brooklyn/core/mgmt/rebind/RebindContextImpl.java | 9 +--------
 .../apache/brooklyn/core/mgmt/rebind/RebindIteration.java   | 4 +---
 6 files changed, 12 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6938922d/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java b/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java
index 9fe7e8a..4f975b7 100644
--- a/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java
+++ b/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java
@@ -24,6 +24,9 @@ import org.apache.brooklyn.api.objs.BrooklynObject;
 /** Describes an OSGi bundle which Brooklyn manages, including persisting */
 public interface ManagedBundle extends BrooklynObject, Rebindable, OsgiBundleWithUrl {
 
+    /** A URL-like thing that we can register with the OSGi framework
+     * to uniquely identify this bundle-instance.
+     * This typically includes the unique {@link #getId()} of this item. */
     String getOsgiUniqueUrl();
 
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6938922d/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 ccafcc3..e8bb5fc 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
@@ -704,7 +704,7 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
     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");
+                throw new IllegalStateException("Cannot persist bundles without a management context");
             }
             final ManagedBundle mb = ((ManagementContextInternal)mgmt).getOsgiManager().get().getManagedBundles().get(id);
             if (mb==null) {
@@ -719,6 +719,10 @@ public class BrooklynMementoPersisterToObjectStore implements BrooklynMementoPer
                     futures.add( executor.submit(new Runnable() {
                         @Override
                         public void run() {
+                            if (((BasicManagedBundle)mb).getTempLocalFileWhenJustUploaded()==null) {
+                                // someone else persisted this (race)
+                                return;
+                            }
                             persist(type.getSubPathName(), type, id+".jar", com.google.common.io.Files.asByteSource(f), exceptionHandler);
                             ((BasicManagedBundle)mb).setTempLocalFileWhenJustUploaded(null);
                             f.delete();

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6938922d/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 0899ed1..ca63cce 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
@@ -195,7 +195,7 @@ public class BrooklynPersistenceUtils {
         OsgiManager osgi = ((LocalManagementContext)mgmt).getOsgiManager().orNull();
         if (osgi!=null) {
             for (ManagedBundle instance: osgi.getManagedBundles().values()) {
-                result.catalogItem(instance.getId(), serializer.toString(newObjectMemento(instance)));
+                result.bundle(instance.getId(), serializer.toString(newObjectMemento(instance)));
             }
         }
         

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6938922d/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 1800a05..2028c43 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
@@ -32,7 +32,6 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Charsets;
 import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
 import com.google.common.io.ByteSource;
 import com.google.common.io.Files;
 
@@ -80,7 +79,7 @@ public class FileBasedStoreObjectAccessor implements PersistenceObjectStore.Stor
 
     @Override
     public void put(String val) {
-        Preconditions.checkNotNull(val, "Illegal attempt to write a null string");
+        if (val==null) val = "";
         put(ByteSource.wrap(val.getBytes(Charsets.UTF_8)));
     }
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6938922d/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 cc301c9..1e9cbba 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
@@ -89,10 +89,7 @@ public class RebindContextImpl implements RebindContext {
         catalogItems.put(id, catalogItem);
     }
 
-    public void registerBundle(String id, ManagedBundle bundle) {
-        bundles.put(id, bundle);
-    }
-    
+    // we don't track register/unregister of bundles; it isn't needed as it happens so early
     public void installBundle(ManagedBundle bundle, InputStream zipInput) {
         ((LocalManagementContext)mgmt).getOsgiManager().get().installUploadedBundle(bundle, zipInput, true);
     }
@@ -113,10 +110,6 @@ public class RebindContextImpl implements RebindContext {
         catalogItems.remove(item.getId());
     }
 
-    public void unregisterBundle(ManagedBundle bundle) {
-        bundles.remove(bundle.getId());
-    }
-
     public void clearCatalogItems() {
         catalogItems.clear();
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/6938922d/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 5ed1dd5..34c795c 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
@@ -328,10 +328,8 @@ public abstract class RebindIteration {
             logRebindingDebug("RebindManager installing bundles: {}", mementoManifest.getBundleIds());
             for (ManagedBundleMemento bundleM : mementoManifest.getBundles().values()) {
                 logRebindingDebug("RebindManager installing bundle {}", bundleM.getId());
-                try {
-                    InputStream in = bundleM.getJarContent().openStream();
+                try (InputStream in = bundleM.getJarContent().openStream()) {
                     rebindContext.installBundle(instantiator.newManagedBundle(bundleM), in);
-                    in.close();
                 } catch (Exception e) {
                     exceptionHandler.onCreateFailed(BrooklynObjectType.MANAGED_BUNDLE, bundleM.getId(), bundleM.getSymbolicName(), e);
                 }