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 <[email protected]>
Authored: Wed Apr 19 19:11:56 2017 +0100
Committer: Alex Heneveld <[email protected]>
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()));
     }
 }

Reply via email to