This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git

commit f689b8196f8fa90e90d347e322d4aee470456dad
Author: Alex Heneveld <[email protected]>
AuthorDate: Fri Oct 1 17:24:52 2021 +0100

    record that user-installed bundles are deleteable
    
    this saves it in persisted state and returns it via the rest api
---
 .../mgmt/rebind/mementos/ManagedBundleMemento.java |  4 +++
 .../brooklyn/api/typereg/OsgiBundleWithUrl.java    |  4 +++
 .../brooklyn/camp/brooklyn/AbstractYamlTest.java   |  2 +-
 .../camp/brooklyn/test/lite/CampYamlLiteTest.java  |  2 +-
 .../core/catalog/internal/CatalogBundleDto.java    | 14 ++++++++-
 .../catalog/internal/CatalogItemDtoAbstract.java   |  3 +-
 .../apache/brooklyn/core/mgmt/ha/OsgiManager.java  |  5 ++++
 .../brooklyn/core/mgmt/rebind/RebindIteration.java |  2 +-
 .../core/mgmt/rebind/RebindManagerImpl.java        | 33 ++++++++++------------
 .../mgmt/rebind/dto/BasicManagedBundleMemento.java | 19 +++++++++++--
 .../core/mgmt/rebind/dto/MementosGenerators.java   |  2 ++
 .../core/typereg/BasicBrooklynTypeRegistry.java    |  2 +-
 .../brooklyn/core/typereg/BasicManagedBundle.java  | 27 +++++++++++++-----
 .../core/typereg/BasicOsgiBundleWithUrl.java       | 16 +++++++++--
 .../BrooklynBomYamlCatalogBundleResolver.java      |  4 +--
 .../typereg/BrooklynCatalogBundleResolver.java     |  7 +++++
 .../apache/brooklyn/rest/domain/BundleSummary.java | 11 ++++++--
 .../brooklyn/rest/resources/BundleResource.java    |  2 +-
 .../brooklyn/rest/resources/CatalogResource.java   |  2 +-
 .../brooklyn/rest/resources/ServerResource.java    | 25 +++++++++++-----
 20 files changed, 136 insertions(+), 50 deletions(-)

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 dba3c1c..e608608 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
@@ -37,4 +37,8 @@ public interface ManagedBundleMemento extends Memento {
     ByteSource getJarContent();
     void setJarContent(ByteSource byteSource);
 
+    @Nullable
+    /** whether the bundle is known to be able to be permanently deleteable 
(eg it was installed by a user) */
+    Boolean getDeleteable();
+
 }
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 8e245c1..9080c74 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
@@ -44,6 +44,10 @@ public interface OsgiBundleWithUrl {
     /** @return true if we have a name and version for this bundle;
      * false if not, e.g. if we only know the URL and we haven't loaded it yet 
*/
     public boolean isNameResolved();
+
+    /** @return whether this is known to be deleteable (eg installed by user) 
or known not to be (eg installed at boot and will be reinstalled)
+     * or unknown (null, probably installed at boot or before this info was 
kept) */
+    public Boolean getDeleteable();
     
     /** @return the {@link VersionedName} for this bundle, or null if not 
available */
     public VersionedName getVersionedName();
diff --git 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
index 34e18d1..9f4d7f5 100644
--- 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
+++ 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
@@ -269,7 +269,7 @@ public abstract class AbstractYamlTest {
             File bf = bundleMaker.createTempZip("test", MutableMap.of(
                 new ZipEntry(BasicBrooklynCatalog.CATALOG_BOM), new 
ByteArrayInputStream(catalogYaml.getBytes())));
             ReferenceWithError<OsgiBundleInstallationResult> b = 
((ManagementContextInternal)mgmt).getOsgiManager().get().installDeferredStart(
-                new BasicManagedBundle(bundleName.getSymbolicName(), 
bundleName.getVersionString(), null, null, null, null),
+                new BasicManagedBundle(bundleName.getSymbolicName(), 
bundleName.getVersionString(), null, null, null, null, true),
                 InputStreamSource.of("tests:"+bundleName+":"+bf, bf),
                 false);
             
diff --git 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
index 299b200..32114eb 100644
--- 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
+++ 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/test/lite/CampYamlLiteTest.java
@@ -213,7 +213,7 @@ public class CampYamlLiteTest {
         // install bundle for class access but without loading its 
catalog.bom, 
         // since we only have mock matchers here
         // (if we don't do this, the default routines install it and try to 
process the catalog.bom, failing)
-        
((ManagementContextInternal)mgmt).getOsgiManager().get().installDeferredStart(new
 BasicManagedBundle(null, null, bundleUrl, null, null, null), null, 
false).get();
+        
((ManagementContextInternal)mgmt).getOsgiManager().get().installDeferredStart(new
 BasicManagedBundle(null, null, bundleUrl, null, null, null, true), null, 
false).get();
     }
 
     private void assertMgmtHasSampleMyCatalogApp(String symbolicName, String 
bundleUrl) {
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleDto.java
 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleDto.java
index 654a3f0..296a367 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleDto.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleDto.java
@@ -39,14 +39,20 @@ public class CatalogBundleDto implements CatalogBundle {
     private String version;
     private String url;
     private Credentials credential;
+    private Boolean deleteable;
 
     public CatalogBundleDto() {}
 
+    @Deprecated /** @deprecated since 1.1 use larger constructor */
     public CatalogBundleDto(String name, String version, String url) {
         this(name, version, url, null);
     }
 
+    @Deprecated /** @deprecated since 1.1 use larger constructor */
     public CatalogBundleDto(String name, String version, String url, @Nullable 
Credentials credential) {
+        this(name, version, url, credential, null);
+    }
+    public CatalogBundleDto(String name, String version, String url, @Nullable 
Credentials credential, @Nullable Boolean deleteable) {
         if (name == null && version == null) {
             Preconditions.checkNotNull(url, "url to an OSGi bundle is 
required");
         } else {
@@ -58,6 +64,7 @@ public class CatalogBundleDto implements CatalogBundle {
         this.version = version==null ? null : 
BrooklynVersionSyntax.toValidOsgiVersion(version);
         this.url = url;
         this.credential = credential;
+        this.deleteable = deleteable;
     }
 
     @Override
@@ -97,6 +104,11 @@ public class CatalogBundleDto implements CatalogBundle {
     }
 
     @Override
+    public Boolean getDeleteable() {
+        return deleteable;
+    }
+
+    @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
                 .add("symbolicName", symbolicName)
@@ -128,7 +140,7 @@ public class CatalogBundleDto implements CatalogBundle {
         if (osgi==null) return Maybe.absent("No OSGi manager");
         Maybe<Bundle> b2 = osgi.findBundle(b);
         if (b2.isAbsent()) return Maybe.absent("Nothing installed for "+b);
-        return Maybe.of(new CatalogBundleDto(b2.get().getSymbolicName(), 
b2.get().getVersion().toString(), b.getUrl()));
+        return Maybe.of(new CatalogBundleDto(b2.get().getSymbolicName(), 
b2.get().getVersion().toString(), b.getUrl(), b.getUrlCredential(), 
b.getDeleteable()));
     }
     
 }
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
index 99c43a5..7292bc4 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
@@ -441,7 +441,8 @@ public abstract class CatalogItemDtoAbstract<T, SpecT> 
extends AbstractBrooklynO
                         bwu.getSymbolicName(),
                         bwu.getSuppliedVersionString(),
                         bwu.getUrl(),
-                        bwu.getUrlCredential()));
+                        bwu.getUrlCredential(),
+                        bwu.getDeleteable()));
             } else if (object instanceof VersionedName) {
                 dto.add(new CatalogBundleDto(((VersionedName) 
object).getSymbolicName(), ((VersionedName) object).getVersionString(), null));
             } else {
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 5fe3eec..273cdb0 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
@@ -443,10 +443,15 @@ public class OsgiManager {
         return BrooklynCatalogBundleResolvers.install(getManagementContext(), 
zipIn, options);
     }
 
+    @Deprecated /** @deprecated since 1.1 use larger variant of method */
     public ReferenceWithError<OsgiBundleInstallationResult> 
install(Supplier<InputStream> input, String format, boolean force) {
+        return install(input, format, force, null);
+    }
+    public ReferenceWithError<OsgiBundleInstallationResult> 
install(Supplier<InputStream> input, String format, boolean force, Boolean 
deleteable) {
         BundleInstallationOptions options = new BundleInstallationOptions();
         options.setFormat(format);
         options.setForceUpdateOfNonSnapshots(force);
+        options.setDeleteable(deleteable);
         return BrooklynCatalogBundleResolvers.install(getManagementContext(), 
input, options);
     }
 
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 cf96700..367e5ff 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
@@ -1379,7 +1379,7 @@ public abstract class RebindIteration {
 
         protected ManagedBundle newManagedBundle(ManagedBundleMemento memento) 
{
             ManagedBundle result = new 
BasicManagedBundle(memento.getSymbolicName(), memento.getVersion(), 
memento.getUrl(),
-                    memento.getFormat(), null, memento.getChecksum());
+                    memento.getFormat(), null, memento.getChecksum(), 
memento.getDeleteable());
             FlagUtils.setFieldsFromFlags(ImmutableMap.of("id", 
memento.getId()), result);
             return result;
         }
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 c45c96f..81c254e 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
@@ -504,15 +504,7 @@ public class RebindManagerImpl implements RebindManager {
         // failure at various points should leave proxies in a sensible state,
         // either pointing at old or at new, though this is relatively 
untested,
         // and some things e.g. policies might not be properly started
-        final RebindExceptionHandler exceptionHandler = 
-            RebindExceptionHandlerImpl.builder()
-                .danglingRefFailureMode(danglingRefFailureMode)
-                
.danglingRefQuorumRequiredHealthy(danglingRefsQuorumRequiredHealthy)
-                .rebindFailureMode(rebindFailureMode)
-                .addConfigFailureMode(addConfigFailureMode)
-                .addPolicyFailureMode(addPolicyFailureMode)
-                .loadPolicyFailureMode(loadPolicyFailureMode)
-                .build();
+        final RebindExceptionHandler exceptionHandler = newExceptionHandler();
         final ManagementNodeState mode = getRebindMode();
 
         ActivePartialRebindIteration iteration = new 
ActivePartialRebindIteration(this, mode, classLoader, exceptionHandler,
@@ -597,14 +589,7 @@ public class RebindManagerImpl implements RebindManager {
         final ClassLoader classLoader = classLoaderO!=null ? classLoaderO :
             managementContext.getCatalogClassLoader();
         final RebindExceptionHandler exceptionHandler = 
exceptionHandlerO!=null ? exceptionHandlerO :
-            RebindExceptionHandlerImpl.builder()
-                .danglingRefFailureMode(danglingRefFailureMode)
-                
.danglingRefQuorumRequiredHealthy(danglingRefsQuorumRequiredHealthy)
-                .rebindFailureMode(rebindFailureMode)
-                .addConfigFailureMode(addConfigFailureMode)
-                .addPolicyFailureMode(addPolicyFailureMode)
-                .loadPolicyFailureMode(loadPolicyFailureMode)
-                .build();
+                newExceptionHandler();
         final ManagementNodeState mode = modeO!=null ? modeO : getRebindMode();
         
         if (mode!=ManagementNodeState.MASTER && 
mode!=ManagementNodeState.HOT_STANDBY && mode!=ManagementNodeState.HOT_BACKUP)
@@ -619,7 +604,19 @@ public class RebindManagerImpl implements RebindManager {
             return rebindImpl(classLoader, exceptionHandler, mode);
         }
     }
-    
+
+    @Beta
+    public RebindExceptionHandler newExceptionHandler() {
+        return RebindExceptionHandlerImpl.builder()
+                .danglingRefFailureMode(danglingRefFailureMode)
+                
.danglingRefQuorumRequiredHealthy(danglingRefsQuorumRequiredHealthy)
+                .rebindFailureMode(rebindFailureMode)
+                .addConfigFailureMode(addConfigFailureMode)
+                .addPolicyFailureMode(addPolicyFailureMode)
+                .loadPolicyFailureMode(loadPolicyFailureMode)
+                .build();
+    }
+
     @Override
     public BrooklynMementoRawData retrieveMementoRawData() {
         RebindExceptionHandler exceptionHandler = 
RebindExceptionHandlerImpl.builder()
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 6d74587..a1d7d7f 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
@@ -44,7 +44,8 @@ public class BasicManagedBundleMemento extends 
AbstractMemento implements Manage
         protected String format;
         protected String url;
         protected String checksum;
-        
+        protected Boolean deleteable;
+
         public Builder symbolicName(String symbolicName) {
             this.symbolicName = symbolicName;
             return self();
@@ -70,6 +71,11 @@ public class BasicManagedBundleMemento extends 
AbstractMemento implements Manage
             return self();
         }
 
+        public Builder deleteable(Boolean deleteable) {
+            this.deleteable = deleteable;
+            return self();
+        }
+
         public Builder from(ManagedBundleMemento other) {
             super.from(other);
             symbolicName = other.getSymbolicName();
@@ -77,6 +83,7 @@ public class BasicManagedBundleMemento extends 
AbstractMemento implements Manage
             format = other.getFormat();
             url = other.getUrl();
             checksum = other.getChecksum();
+            deleteable = other.getDeleteable();
             return self();
         }
 
@@ -90,6 +97,7 @@ public class BasicManagedBundleMemento extends 
AbstractMemento implements Manage
     private String format;
     private String url;
     private String checksum;
+    private Boolean deleteable;
     transient private ByteSource jarContent;
 
     @SuppressWarnings("unused") // For deserialisation
@@ -102,6 +110,7 @@ public class BasicManagedBundleMemento extends 
AbstractMemento implements Manage
         this.format = builder.format;
         this.url = builder.url;
         this.checksum = builder.checksum;
+        this.deleteable = builder.deleteable;
     }
 
     @Override
@@ -130,10 +139,13 @@ public class BasicManagedBundleMemento extends 
AbstractMemento implements Manage
     }
 
     @Override
+    public Boolean getDeleteable() { return deleteable; }
+
+    @Override
     public ByteSource getJarContent() {
         return jarContent;
     }
-    
+
     @Override
     public void setJarContent(ByteSource byteSource) {
         this.jarContent = byteSource;
@@ -159,7 +171,8 @@ public class BasicManagedBundleMemento extends 
AbstractMemento implements Manage
                 .add("version", getVersion())
                 .add("format", getFormat())
                 .add("url", getUrl())
-                .add("checksum", getChecksum());
+                .add("checksum", getChecksum())
+                .add("deleteable", getDeleteable());
     }
 
     @Override
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 51e3e6f..187c1ac 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
@@ -355,6 +355,8 @@ public class MementosGenerators {
         builder.url(bundle.getUrl())
             .symbolicName(bundle.getSymbolicName())
             .version(bundle.getSuppliedVersionString())
+            .checksum(bundle.getChecksum())
+            .deleteable(bundle.getDeleteable())
             .format(bundle.getFormat());
         return builder.build();
     }
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 c47f808..0e8431a 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
@@ -515,7 +515,7 @@ public class BasicBrooklynTypeRegistry implements 
BrooklynTypeRegistry {
         // if not osgi, everything is treated as a wrapper bundle
         if (osgi.isAbsent()) return true;
         VersionedName vn = VersionedName.fromString(bundleNameVersion);
-        Maybe<Bundle> b = osgi.get().findBundle(new 
BasicOsgiBundleWithUrl(vn.getSymbolicName(), vn.getOsgiVersionString(), null));
+        Maybe<Bundle> b = osgi.get().findBundle(new 
BasicOsgiBundleWithUrl(vn.getSymbolicName(), vn.getOsgiVersionString(), null, 
null, null));
         // if bundle not found it is an error or a race; we don't fail, but we 
shouldn't treat it as a wrapper
         if (b.isAbsent()) return false;
         
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 c921a31..826db9a 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
@@ -42,6 +42,7 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
     private String symbolicName;
     private String version;
     private String checksum;
+    private Boolean deleteable;
     private String osgiUniqueUrl;
     private String format;
     private String url;
@@ -60,11 +61,16 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
         this(name, version, url, null, credentials, checksum);
     }
 
+    /** @deprecated since 1.1 use larger constructor */ @Deprecated
     public BasicManagedBundle(String name, String version, String url, String 
format, Credentials credentials, @Nullable String checksum) {
-        init(name, version, url, format, credentials, checksum);
+        init(name, version, url, format, credentials, checksum, null);
+    }
+
+    public BasicManagedBundle(String name, String version, String url, String 
format, Credentials credentials, @Nullable String checksum, @Nullable Boolean 
deleteable) {
+        init(name, version, url, format, credentials, checksum, deleteable);
     }
 
-    private void init(String name, String version, String url, String format, 
Credentials credentials, @Nullable String checksum) {
+    private void init(String name, String version, String url, String format, 
Credentials credentials, @Nullable String checksum, @Nullable Boolean 
deleteable) {
         if (name == null && version == null) {
             Preconditions.checkNotNull(url, "Either a URL or both name and 
version are required");
         } else {
@@ -77,18 +83,19 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
         this.format = format;
         this.credentials = credentials;
         this.checksum = checksum;
+        this.deleteable = deleteable;
     }
 
-    private BasicManagedBundle(String id, String name, String version, String 
url, String format, Credentials credentials, @Nullable String checksum) {
+    private BasicManagedBundle(String id, String name, String version, String 
url, String format, Credentials credentials, @Nullable String checksum, 
@Nullable Boolean deleteable) {
         super(id);
-        init(name, version, url, format, credentials, checksum);
+        init(name, version, url, format, credentials, checksum, deleteable);
     }
 
     /** used when updating a persisted bundle, we want to use the coords (ID 
and OSGI unique URL) of the second with the checksum of the former;
      * the other fields should be the same between the two but if in doubt use 
the first argument
      */
     public static BasicManagedBundle copyFirstWithCoordsOfSecond(ManagedBundle 
update, ManagedBundle oldOneForCoordinates) {
-        BasicManagedBundle result = new 
BasicManagedBundle(oldOneForCoordinates.getId(), update.getSymbolicName(), 
update.getSuppliedVersionString(), update.getUrl(), update.getFormat(), 
update.getUrlCredential(), update.getChecksum());
+        BasicManagedBundle result = new 
BasicManagedBundle(oldOneForCoordinates.getId(), update.getSymbolicName(), 
update.getSuppliedVersionString(), update.getUrl(), update.getFormat(), 
update.getUrlCredential(), update.getChecksum(), update.getDeleteable());
         // we have secondary logic which should accept a change in the OSGi 
unique URL,
         // but more efficient if we use the original URL
         result.osgiUniqueUrl = oldOneForCoordinates.getOsgiUniqueUrl();
@@ -99,7 +106,12 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
     public boolean isNameResolved() {
         return symbolicName != null && version != null;
     }
-    
+
+    @Override
+    public Boolean getDeleteable() {
+        return deleteable;
+    }
+
     @Override
     public String getSymbolicName() {
         return symbolicName;
@@ -264,7 +276,8 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
                 bundle.getUrl(),
                 null,
                 bundle.getUrlCredential(),
-                checksum);
+                checksum,
+                bundle instanceof ManagedBundle ? 
((ManagedBundle)bundle).getDeleteable() : null);
     }
 
     public void setPersistenceNeeded(boolean val) {
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 a644224..e218fdd 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
@@ -34,17 +34,23 @@ public class BasicOsgiBundleWithUrl implements 
CatalogBundle, OsgiBundleWithUrl
     private String symbolicName;
     private String version;
     private String url;
+    private Boolean deleteable;
     private Credentials credential;
 
     // for deserializing (not sure if needed?)
     @SuppressWarnings("unused")
     private BasicOsgiBundleWithUrl() {}
 
+    @Deprecated /** @deprecated since 1.1 use larger constructor */
     public BasicOsgiBundleWithUrl(String name, String version, String url) {
         this(name, version, url, null);
     }
-
+    @Deprecated /** @deprecated since 1.1 use larger constructor */
     public BasicOsgiBundleWithUrl(String name, String version, String url, 
@Nullable Credentials cred) {
+        this(name, version, url, cred, null);
+    }
+
+    public BasicOsgiBundleWithUrl(String name, String version, String url, 
@Nullable Credentials cred, @Nullable Boolean deleteable) {
         if (name == null && version == null) {
             Preconditions.checkNotNull(url, "Either a URL or both name and 
version are required");
         } else {
@@ -56,10 +62,11 @@ public class BasicOsgiBundleWithUrl implements 
CatalogBundle, OsgiBundleWithUrl
         this.version = version;
         this.url = url;
         this.credential = cred;
+        this.deleteable = deleteable;
     }
     
     public BasicOsgiBundleWithUrl(OsgiBundleWithUrl b) {
-        this(b.getSymbolicName(), b.getSuppliedVersionString(), b.getUrl());
+        this(b.getSymbolicName(), b.getSuppliedVersionString(), b.getUrl(), 
b.getUrlCredential(), b.getDeleteable());
     }
 
     @Override
@@ -99,6 +106,11 @@ public class BasicOsgiBundleWithUrl implements 
CatalogBundle, OsgiBundleWithUrl
     }
 
     @Override
+    public Boolean getDeleteable() {
+        return deleteable;
+    }
+
+    @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
                 .add("symbolicName", symbolicName)
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynBomYamlCatalogBundleResolver.java
 
b/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynBomYamlCatalogBundleResolver.java
index f7203d2..110533c 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynBomYamlCatalogBundleResolver.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynBomYamlCatalogBundleResolver.java
@@ -31,9 +31,7 @@ import 
org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.osgi.BundleMaker;
-import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.exceptions.ReferenceWithError;
-import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.osgi.VersionedName;
 import org.apache.brooklyn.util.stream.InputStreamSource;
 import org.apache.brooklyn.util.stream.Streams;
@@ -118,7 +116,7 @@ public class BrooklynBomYamlCatalogBundleResolver extends 
AbstractCatalogBundleR
 
             BasicManagedBundle basicManagedBundle = new 
BasicManagedBundle(vn.getSymbolicName(), vn.getVersionString(),
                     null, BrooklynBomBundleCatalogBundleResolver.FORMAT,
-                    null, null);
+                    null, null, options.getDeleteable());
             // if the submitted blueprint contains tags, we set them on the 
bundle, so they can be picked up and used to tag the plan.
             if( cm.containsKey("tags") && cm.get("tags") instanceof Iterable) {
                 basicManagedBundle.tags().addTags((Iterable<?>)cm.get("tags"));
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynCatalogBundleResolver.java
 
b/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynCatalogBundleResolver.java
index 685037b..5ee5286 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynCatalogBundleResolver.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynCatalogBundleResolver.java
@@ -99,6 +99,7 @@ public interface BrooklynCatalogBundleResolver extends 
ManagementContextInjectab
         protected boolean deferredStart = false;
         protected boolean start = true;
         protected boolean loadCatalogBom = true;
+        protected Boolean deleteable = null;
         protected ManagedBundle knownBundleMetadata = null;
 
         public void setFormat(String format) {
@@ -156,6 +157,12 @@ public interface BrooklynCatalogBundleResolver extends 
ManagementContextInjectab
         public boolean isValidateTypes() {
             return validateTypes;
         }
+
+        public Boolean getDeleteable() { return deleteable; }
+
+        public void setDeleteable(Boolean deleteable) {
+            this.deleteable = deleteable;
+        }
     }
 
 }
diff --git 
a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/BundleSummary.java
 
b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/BundleSummary.java
index c8f442b..bb93fb0 100644
--- 
a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/BundleSummary.java
+++ 
b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/BundleSummary.java
@@ -49,7 +49,10 @@ public class BundleSummary implements 
Comparable<BundleSummary> {
 
     @JsonInclude(value=Include.ALWAYS)
     private final List<TypeSummary> types = MutableList.of();
-    
+
+    @JsonInclude(value=Include.NON_NULL)
+    private final Boolean deleteable;
+
     // not exported directly, but used to provide other top-level json fields
     // for specific types
     @JsonIgnore
@@ -59,11 +62,13 @@ public class BundleSummary implements 
Comparable<BundleSummary> {
     BundleSummary() {
         symbolicName = null;
         version = null;
+        deleteable = null;
     }
     
     public BundleSummary(OsgiBundleWithUrl bundle) {
         symbolicName = bundle.getSymbolicName();
         version = bundle.getSuppliedVersionString();
+        deleteable = bundle.getDeleteable();
     }
     
     /** Mutable map of other top-level metadata included on this DTO (eg 
listing config keys or effectors) */ 
@@ -98,7 +103,9 @@ public class BundleSummary implements 
Comparable<BundleSummary> {
     public List<TypeSummary> getTypes() {
         return types;
     }
-    
+
+    public Boolean getDeleteable() { return deleteable; }
+
     @Override
     public String toString() {
         return 
JavaClassNames.cleanSimpleClassName(this)+"["+symbolicName+":"+version+"]";
diff --git 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/BundleResource.java
 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/BundleResource.java
index 04bfbca..1b8cd13 100644
--- 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/BundleResource.java
+++ 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/BundleResource.java
@@ -222,7 +222,7 @@ public class BundleResource extends 
AbstractBrooklynRestResource implements Bund
         if (force==null) force = false;
 
         ReferenceWithError<OsgiBundleInstallationResult> result = 
((ManagementContextInternal)mgmt()).getOsgiManager().get()
-                .install(source, format, force);
+                .install(source, format, force, true);
 
         if (result.hasError()) {
             // (rollback already done as part of install, if necessary)
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 7fc43d7..f3187c1 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
@@ -153,7 +153,7 @@ public class CatalogResource extends 
AbstractBrooklynRestResource implements Cat
         }
 
         ReferenceWithError<OsgiBundleInstallationResult> result = 
((ManagementContextInternal)mgmt()).getOsgiManager().get()
-                .install(source, format, forceUpdate);
+                .install(source, format, forceUpdate, true);
 
         if (result.hasError()) {
             // (rollback already done as part of install, if necessary)
diff --git 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
index 1706b80..33f4ef3 100644
--- 
a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
+++ 
b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
@@ -44,7 +44,9 @@ import 
org.apache.brooklyn.api.mgmt.ha.ManagementPlaneSyncRecord;
 import org.apache.brooklyn.api.mgmt.ha.MementoCopyMode;
 import org.apache.brooklyn.api.mgmt.rebind.PersistenceExceptionHandler;
 import org.apache.brooklyn.api.mgmt.rebind.RebindManager;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoManifest;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.ManagedBundleMemento;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.BrooklynVersion;
 import org.apache.brooklyn.core.config.ConfigKeys;
@@ -61,6 +63,7 @@ import 
org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.mgmt.persist.*;
 import org.apache.brooklyn.core.mgmt.rebind.PersistenceExceptionHandlerImpl;
+import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
 import org.apache.brooklyn.core.server.BrooklynServerPaths;
 import org.apache.brooklyn.rest.api.ServerApi;
 import org.apache.brooklyn.rest.domain.*;
@@ -588,16 +591,18 @@ public class ServerResource extends 
AbstractBrooklynRestResource implements Serv
 
             // create raw memento of persisted state to be imported
             BrooklynMementoRawData newMementoRawData = 
tempMgmt.getRebindManager().retrieveMementoRawData();
+            BrooklynMementoManifest mementoManifest = 
persister.loadMementoManifest(newMementoRawData,
+                    ((RebindManagerImpl)rebindManager).newExceptionHandler());
 
             // install bundles to active management context
             for (Map.Entry<String, ByteSource> bundleJar : 
newMementoRawData.getBundleJars().entrySet()){
+                ManagedBundleMemento memento = 
mementoManifest.getBundle(bundleJar.getKey());
+                log.debug("Installing "+memento+" as part of persisted state 
import");
                 ReferenceWithError<OsgiBundleInstallationResult> 
bundleInstallResult = ((ManagementContextInternal)mgmt()).getOsgiManager().get()
-                        .install(InputStreamSource.of("Persistence import - 
bundle install", bundleJar.getValue().read()), "", false);
+                        .install(InputStreamSource.of("Persistence import - 
bundle install - "+memento, bundleJar.getValue().read()), "", false, 
memento.getDeleteable());
 
                 if (bundleInstallResult.hasError()) {
-                    if (log.isTraceEnabled()) {
-                        log.trace("Unable to create, format '', returning 400: 
"+bundleInstallResult.getError().getMessage(), bundleInstallResult.getError());
-                    }
+                    log.debug("Unable to create "+memento+", format '', 
throwing: "+bundleInstallResult.getError().getMessage(), 
bundleInstallResult.getError());
                     String errorMsg = "";
                     if (bundleInstallResult.getWithoutError()!=null) {
                         errorMsg = 
bundleInstallResult.getWithoutError().getMessage();
@@ -607,20 +612,26 @@ public class ServerResource extends 
AbstractBrooklynRestResource implements Serv
                     throw new Exception(errorMsg);
                 }
                 if 
(!OsgiBundleInstallationResult.ResultCode.IGNORING_BUNDLE_AREADY_INSTALLED.equals(bundleInstallResult.get().getCode())
 && 
!OsgiBundleInstallationResult.ResultCode.UPDATED_EXISTING_BUNDLE.equals(bundleInstallResult.get().getCode()))
 {
-                    
TypeTransformer.bundleInstallationResult(bundleInstallResult.get(), mgmt(), 
brooklyn(), ui);
+                    BundleInstallationRestResult result = 
TypeTransformer.bundleInstallationResult(bundleInstallResult.get(), mgmt(), 
brooklyn(), ui);
+                    log.debug("Installed "+memento+" as part of persisted 
state import: "+result);
+                } else {
+                    log.debug("Installation of " + memento + " reported: " + 
bundleInstallResult.get());
                 }
             }
 
 
-            // write persisted items and rebind to load applications
+            // store persisted items and rebind to load applications
             BrooklynMementoRawData.Builder result = 
BrooklynMementoRawData.builder();
+
+            // bundles already initialized
+//            result.bundles(newMementoRawData.getBundles());
+
             result.planeId(mgmt().getManagementPlaneIdMaybe().orNull());
             result.entities(newMementoRawData.getEntities());
             result.locations(newMementoRawData.getLocations());
             result.policies(newMementoRawData.getPolicies());
             result.enrichers(newMementoRawData.getEnrichers());
             result.feeds(newMementoRawData.getFeeds());
-            result.feeds(newMementoRawData.getFeeds());
             result.catalogItems(newMementoRawData.getCatalogItems());
 
             PersistenceObjectStore currentPersistenceStore = 
((BrooklynMementoPersisterToObjectStore) 
mgmt().getRebindManager().getPersister()).getObjectStore();

Reply via email to