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 9a58578db159fb3a45e3051b349c3afddd938311
Author: Alex Heneveld <a...@cloudsoft.io>
AuthorDate: Thu Mar 28 21:55:03 2024 +0000

    store whether a bundle comes from the initial catalog, and don't persist 
those
    
    change previous commit so that we don't exclude persisting of things from 
URL's,
    but we do exclude persisting of things from the catalog by default.
    
    we needed to persist things from URL's because we might manually install 
bundle A with libraries B,
    and we need to persist a record that those libraries B are installed and 
persisted,
    because if we remove A, we don't remove B, but if we haven't persisted a 
record of B, then B is removed after rebind.
    
    we could record an XML record without storing the JAR, but that is more 
work;
    and it makes more sense that things in the catalog we expect to be defined 
in the catalog;
    if you want to keep those on a restart, they need to stay in the catalog 
(or have upgrade instructions in catalog),
    or be installed manually prior to restarting, if you want to remove it from 
the catalog while it is in use,
    
    installing manually causes things to be persisted even if they are already 
in the catalog.
---
 .../catalog/internal/BasicBrooklynCatalog.java     |  69 ++++++++----
 .../core/catalog/internal/CatalogBundleLoader.java |   3 +
 .../catalog/internal/CatalogInitialization.java    |   2 +-
 .../core/catalog/internal/CatalogUtils.java        |   6 +-
 .../mgmt/ha/BrooklynBomOsgiArchiveInstaller.java   |  81 +++++++++-----
 .../apache/brooklyn/core/mgmt/ha/OsgiManager.java  |  11 ++
 .../BrooklynMementoPersisterToObjectStore.java     |   4 +-
 .../brooklyn/core/server/BrooklynServerConfig.java |   8 +-
 .../brooklyn/core/typereg/BasicManagedBundle.java  |  35 ++++--
 .../BrooklynBomYamlCatalogBundleResolver.java      |   2 +-
 .../typereg/BrooklynCatalogBundleResolver.java     |   8 ++
 .../BrooklynLauncherRebindCatalogOsgiTest.java     | 121 ++++++++++++++-------
 12 files changed, 243 insertions(+), 107 deletions(-)

diff --git 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
index e3a9208bf0..7fafe0db71 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
@@ -18,12 +18,9 @@
  */
 package org.apache.brooklyn.core.catalog.internal;
 
-import com.google.common.base.*;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.reflect.TypeToken;
-import java.io.*;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -36,13 +33,27 @@ import java.util.Set;
 import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.reflect.TypeToken;
 import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogItemType;
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
-import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.api.objs.BrooklynObject;
@@ -63,11 +74,19 @@ import 
org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult;
 import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
 import org.apache.brooklyn.core.mgmt.internal.CampYamlParser;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.typereg.*;
+import org.apache.brooklyn.core.typereg.BasicBrooklynTypeRegistry;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
+import org.apache.brooklyn.core.typereg.BasicRegisteredType;
+import org.apache.brooklyn.core.typereg.BasicTypeImplementationPlan;
+import org.apache.brooklyn.core.typereg.BrooklynBomYamlCatalogBundleResolver;
+import org.apache.brooklyn.core.typereg.BrooklynTypePlanTransformer;
+import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts;
+import org.apache.brooklyn.core.typereg.RegisteredTypeNaming;
+import org.apache.brooklyn.core.typereg.RegisteredTypes;
+import org.apache.brooklyn.core.typereg.UnsupportedTypePlanException;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
-import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import 
org.apache.brooklyn.util.core.flags.BrooklynTypeNameResolution.BrooklynTypeNameResolver;
 import org.apache.brooklyn.util.core.flags.TypeCoercions;
@@ -95,14 +114,8 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.Yaml;
 
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /* TODO the complex tree-structured catalogs are only useful when we are 
relying on those separate catalog classloaders
  * to isolate classpaths. with osgi everything is just put into the "manual 
additions" catalog. Deprecate/remove this. */
@@ -684,7 +697,8 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
         // `libraries` is supported in some places as a legacy syntax; it 
should always be `brooklyn.libraries` for new apps
         List<?> librariesAddedHereNames = 
MutableList.copyOf(getFirstAs(itemMetadataWithoutItemDef, List.class, 
"brooklyn.libraries", "libraries").orNull());
         Collection<CatalogBundle> librariesAddedHereBundles = 
CatalogItemDtoAbstract.parseLibraries(librariesAddedHereNames);
-        
+        boolean fromInitialCatalog = containingBundle instanceof 
BasicManagedBundle && Boolean.TRUE.equals( 
((BasicManagedBundle)containingBundle).getFromInitialCatalog() );
+
         MutableSet<Object> librariesCombinedNames = MutableSet.of();
         if (!isNoBundleOrSimpleWrappingBundle(mgmt, containingBundle)) {
             // ensure containing bundle is declared, first, for search purposes
@@ -700,7 +714,7 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
         // TODO this may take a while if downloading; ideally the REST call 
would be async
         // but this load is required for resolving YAML in this BOM (and if 
java-scanning);
         // need to think through how we expect dependencies to be installed
-        CatalogUtils.installLibraries(mgmt, librariesAddedHereBundles);
+        CatalogUtils.installLibraries(mgmt, librariesAddedHereBundles, true, 
fromInitialCatalog);
         
         // use resolved bundles
         librariesAddedHereBundles = resolveWherePossible(mgmt, 
librariesAddedHereBundles);
@@ -1810,10 +1824,14 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
     
     @Override
     public List<? extends CatalogItem<?,?>> addItems(String yaml, boolean 
validate, boolean forceUpdate) {
+        return addItems(yaml, validate, forceUpdate, false);
+    }
+
+    public List<? extends CatalogItem<?,?>> addItems(String yaml, boolean 
validate, boolean forceUpdate, boolean fromCatalog) {
         Maybe<OsgiManager> osgiManager = 
((ManagementContextInternal)mgmt).getOsgiManager();
         if (osgiManager.isPresent() && AUTO_WRAP_CATALOG_YAML_AS_BUNDLE) {
             // wrap in a bundle to be managed; need to get bundle and version 
from yaml
-            OsgiBundleInstallationResult result = addItemsOsgi(yaml, 
forceUpdate, osgiManager.get());
+            OsgiBundleInstallationResult result = addItemsOsgi(yaml, 
forceUpdate, osgiManager.get(), fromCatalog);
             // above will have done validation and supertypes recorded
             return toLegacyCatalogItems(result.getTypesInstalled());
 
@@ -1831,7 +1849,7 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
         Maybe<OsgiManager> osgiManager = 
((ManagementContextInternal)mgmt).getOsgiManager();
         if (osgiManager.isPresent() && AUTO_WRAP_CATALOG_YAML_AS_BUNDLE) {
             // wrap in a bundle to be managed; need to get bundle and version 
from yaml
-            return addItemsOsgi(yaml, forceUpdate, osgiManager.get());
+            return addItemsOsgi(yaml, forceUpdate, osgiManager.get(), false);
 
             // if all items pertaining to an older anonymous catalog.bom 
bundle have been overridden
             // we delete those later; see list of wrapper bundles kept in 
OsgiManager
@@ -1847,7 +1865,10 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
     }
 
     protected OsgiBundleInstallationResult addItemsOsgi(String yaml, boolean 
forceUpdate, OsgiManager osgiManager) {
-        return osgiManager.install(InputStreamSource.of("addItemsOsgi supplied 
yaml", yaml.getBytes()), BrooklynBomYamlCatalogBundleResolver.FORMAT, 
forceUpdate).get();
+        return addItemsOsgi(yaml, forceUpdate, osgiManager, false);
+    }
+    protected OsgiBundleInstallationResult addItemsOsgi(String yaml, boolean 
forceUpdate, OsgiManager osgiManager, boolean fromCatalog) {
+        return osgiManager.install(InputStreamSource.of("addItemsOsgi supplied 
yaml", yaml.getBytes()), BrooklynBomYamlCatalogBundleResolver.FORMAT, 
forceUpdate, !fromCatalog, fromCatalog).get();
     }
     
     @SuppressWarnings("deprecation")
@@ -1913,7 +1934,7 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
         Maybe<OsgiManager> osgiManager = 
((ManagementContextInternal)mgmt).getOsgiManager();
         if (osgiManager.isPresent() && AUTO_WRAP_CATALOG_YAML_AS_BUNDLE) {
             // wrap in a bundle to be managed; need to get bundle and version 
from yaml
-            return addItemsOsgi(catalogYaml, forceUpdate, 
osgiManager.get()).getTypesInstalled();
+            return addItemsOsgi(catalogYaml, forceUpdate, osgiManager.get(), 
false).getTypesInstalled();
             // above will have done validation and supertypes recorded
         }
 
@@ -2271,7 +2292,7 @@ public class BasicBrooklynCatalog implements 
BrooklynCatalog {
         log.debug("Adding manual catalog item to "+mgmt+": "+item);
         checkNotNull(item, "item");
         //don't activate bundles; only intended for legacy tests where that 
might not work
-        CatalogUtils.installLibraries(mgmt, item.getLibraries(), false);
+        CatalogUtils.installLibraries(mgmt, item.getLibraries(), false, false);
         if (manualAdditionsCatalog==null) loadManualAdditionsCatalog();
         manualAdditionsCatalog.addEntry(getAbstractCatalogItem(item));
     }
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java
 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java
index 88e160aa98..5eaaf1d9c3 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBundleLoader.java
@@ -27,11 +27,14 @@ import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import javax.annotation.Nullable;
+
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableSet;
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
index 5050977767..75dcb0bd5d 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
@@ -491,7 +491,7 @@ public class CatalogInitialization implements 
ManagementContextInjectable {
             String contents = new 
ResourceUtils(this).getResourceAsString(catalogUrl);
 
             catalog.reset(MutableList.<CatalogItem<?,?>>of());
-            Object result = catalog.addItems(contents);
+            Object result = catalog.addItems(contents, true, false, true);
             
             log.debug("Loaded initial catalog from {}: {}", catalogUrl, 
result);
             
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
index c4aaa9185e..fa2b90fdd1 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogUtils.java
@@ -171,6 +171,8 @@ public class CatalogUtils {
     /** As {@link #installLibraries(ManagementContext, Collection)} but 
letting caller suppress the deferred start/install
      * (for use in tests where bundles' BOMs aren't resolvable). */
     public static void installLibraries(ManagementContext managementContext, 
@Nullable Collection<CatalogBundle> libraries, boolean 
startBundlesAndInstallToBrooklyn) {
+    }
+    public static void installLibraries(ManagementContext managementContext, 
@Nullable Collection<CatalogBundle> libraries, boolean 
startBundlesAndInstallToBrooklyn, boolean fromInitialCatalog) {
         if (libraries == null) return;
 
         ManagementContextInternal mgmt = (ManagementContextInternal) 
managementContext;
@@ -186,7 +188,9 @@ public class CatalogUtils {
             Stopwatch timer = Stopwatch.createStarted();
             List<OsgiBundleInstallationResult> results = MutableList.of();
             for (CatalogBundle bundle : libraries) {
-                ReferenceWithError<OsgiBundleInstallationResult> result = 
osgi.get().installDeferredStart(BasicManagedBundle.of(bundle), null, true);
+                BasicManagedBundle mb = (BasicManagedBundle) 
BasicManagedBundle.of(bundle);
+                if (fromInitialCatalog) mb.setFromInitialCatalog(true);
+                ReferenceWithError<OsgiBundleInstallationResult> result = 
osgi.get().installDeferredStart(mb, null, true);
                 if (log.isDebugEnabled()) {
                     logDebugOrTraceIfRebinding(log, "Installation of library 
"+bundle+": "+result);
                 }
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstaller.java
 
b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstaller.java
index cf47f230eb..011abd316b 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstaller.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstaller.java
@@ -27,8 +27,6 @@ import com.google.common.collect.Iterables;
 import java.io.*;
 import java.net.URL;
 import java.util.*;
-import java.util.function.BiConsumer;
-import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.jar.Attributes;
 import java.util.jar.Manifest;
@@ -37,8 +35,6 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import javax.annotation.Nullable;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
-import org.apache.brooklyn.api.mgmt.rebind.ChangeListener;
-import org.apache.brooklyn.api.objs.BrooklynObject;
 import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.BrooklynVersion;
@@ -301,10 +297,12 @@ public class BrooklynBomOsgiArchiveInstaller {
                         throw new IllegalArgumentException("No input stream 
available and no URL could be found: no way to install " + 
suppliedKnownBundleMetadata);
                     }
 
+                    boolean shouldReplaceExistingBundle = force || 
replacingInitialCatalogBundle(suppliedKnownBundleMetadata, 
existingBrooklynInstalledBundle.orNull());
+
                     if (zipIn != null) {
                         // found input stream for existing osgi bundle
 
-                    } else if (existingBrooklynInstalledBundle.isAbsent() || 
force) {
+                    } else if (existingBrooklynInstalledBundle.isAbsent() || 
shouldReplaceExistingBundle) {
                         // reload
                         String url = suppliedKnownBundleMetadata.getUrl();
                         if (url == null) {
@@ -375,6 +373,19 @@ public class BrooklynBomOsgiArchiveInstaller {
         return prepareInstallResult;
     }
 
+    private static boolean replacingInitialCatalogBundle(ManagedBundle 
suppliedKnownBundleMetadata, @Nullable ManagedBundle 
existingBrooklynInstalledBundle) {
+        boolean shouldReplaceExistingBundle = false;
+        if (existingBrooklynInstalledBundle instanceof BasicManagedBundle && 
suppliedKnownBundleMetadata instanceof BasicManagedBundle) {
+            if 
(Boolean.TRUE.equals(((BasicManagedBundle)existingBrooklynInstalledBundle).getFromInitialCatalog()))
 {
+                if (!Boolean.TRUE.equals(((BasicManagedBundle) 
suppliedKnownBundleMetadata).getFromInitialCatalog())) {
+                    // we should replace if we are manually installing an 
identical bundle, so it is persisted
+                    shouldReplaceExistingBundle = true;
+                }
+            }
+        }
+        return shouldReplaceExistingBundle;
+    }
+
     private void discoverManifestFromCatalogBom(boolean isCatalogBomRequired) {
         discoveredManifest = new 
BundleMaker(mgmt()).getManifest(zipFile.getFile());
 
@@ -514,35 +525,49 @@ public class BrooklynBomOsgiArchiveInstaller {
                 result.bundle = 
osgiManager.getFramework().getBundleContext().getBundle(result.getMetadata().getOsgiUniqueUrl());
 
                 // Check if exactly this bundle is already installed
+                boolean replacingInitialCatalogBundleWithMatchingChecksums = 
false;
                 if (result.bundle != null && 
checksumsMatch(result.getMetadata(), inferredMetadata)) {
-                    // e.g. repeatedly installing the same bundle
-                    log.trace("Bundle "+inferredMetadata+" matches already 
installed managed bundle "+result.getMetadata()
-                            +"; install is no-op");
-                    result.setIgnoringAlreadyInstalled();
-                    return ReferenceWithError.newInstanceWithoutError(result);
-
+                    if (replacingInitialCatalogBundle(inferredMetadata, 
result.getMetadata())) {
+                        replacingInitialCatalogBundleWithMatchingChecksums = 
true;
+                        // mark it not from initial catalog (but leave it as 
not deletable)
+                        ((BasicManagedBundle) 
result.getMetadata()).setFromInitialCatalog(false);
+                    } else {
+                        // e.g. repeatedly installing the same bundle
+                        log.trace("Bundle " + inferredMetadata + " matches 
already installed managed bundle " + result.getMetadata()
+                                + "; install is no-op");
+                        result.setIgnoringAlreadyInstalled();
+                        return 
ReferenceWithError.newInstanceWithoutError(result);
+                    }
                 }
 
                 List<Bundle> matchingVsnBundles = 
findBundlesBySymbolicNameAndVersion(osgiManager, inferredMetadata);
-
-                List<Bundle> sameContentBundles = 
matchingVsnBundles.stream().filter(b -> isBundleSameOsgiUrlOrSameContents(b, 
inferredMetadata, zipFile.getFile())).collect(Collectors.toList());
-                if (!sameContentBundles.isEmpty()) {
-                    // e.g. happens if pre-installed bundle is brought under 
management, and then add it again via a mvn-style url.
-                    // We wouldn't know the checksum from the pre-installed 
bundle, the osgi locations might be different,
-                    // but the contents are the same
-                    log.trace("Bundle "+inferredMetadata+" matches metadata of 
managed bundle "+result.getMetadata()
-                            +" (but not OSGi bundle location 
"+result.getMetadata().getOsgiUniqueUrl()+"), "
-                            + "and identified as equivalent to installed OSGi 
bundle; ; install is no-op");
-                    result.setIgnoringAlreadyInstalled();
-                    result.bundle = sameContentBundles.iterator().next();
-                    return ReferenceWithError.newInstanceWithoutError(result);
+                if (!replacingInitialCatalogBundleWithMatchingChecksums) {
+                    List<Bundle> sameContentBundles = 
matchingVsnBundles.stream().filter(b -> isBundleSameOsgiUrlOrSameContents(b, 
inferredMetadata, zipFile.getFile())).collect(Collectors.toList());
+                    if (!sameContentBundles.isEmpty()) {
+                        // e.g. happens if pre-installed bundle is brought 
under management, and then add it again via a mvn-style url.
+                        // We wouldn't know the checksum from the 
pre-installed bundle, the osgi locations might be different,
+                        // but the contents are the same
+                        log.trace("Bundle " + inferredMetadata + " matches 
metadata of managed bundle " + result.getMetadata()
+                                + " (but not OSGi bundle location " + 
result.getMetadata().getOsgiUniqueUrl() + "), "
+                                + "and identified as equivalent to installed 
OSGi bundle; ; install is no-op");
+                        result.setIgnoringAlreadyInstalled();
+                        result.bundle = sameContentBundles.iterator().next();
+                        return 
ReferenceWithError.newInstanceWithoutError(result);
+                    }
                 }
 
-                if (canUpdate()) {
-                    if (result.bundle == null && 
!matchingVsnBundles.isEmpty()) {
-                        // if we are updating a snapshot bundle or forcing, 
and somehow we did not manage to preserve the original OSGi location
-                        log.info("Updating existing brooklyn-managed bundle 
"+result+" with "+inferredMetadata+" with different OSGi location and different 
contents");
-                        result.bundle = matchingVsnBundles.iterator().next();
+                if (replacingInitialCatalogBundleWithMatchingChecksums || 
canUpdate()) {
+                    if (result.bundle == null) {
+                        if 
(replacingInitialCatalogBundleWithMatchingChecksums) {
+                            log.info("Updating existing brooklyn-managed 
bundle " + result + " with " + inferredMetadata + ", same contents, but 
post-initial-catalog installation means it must be persisted");
+                            result.bundle = 
matchingVsnBundles.iterator().next();
+                        } else if (!matchingVsnBundles.isEmpty()) {
+                            // if we are updating a snapshot bundle or 
forcing, and somehow we did not manage to preserve the original OSGi location
+                            log.info("Updating existing brooklyn-managed 
bundle " + result + " with " + inferredMetadata + " with different OSGi 
location and different contents");
+                            result.bundle = 
matchingVsnBundles.iterator().next();
+                        } else {
+                            // will set updating=false and warn below
+                        }
                     }
 
                     if (result.getBundle() == null) {
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 4455028291..c6b1e23be7 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
@@ -59,6 +59,7 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import 
org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult.ResultCode;
 import org.apache.brooklyn.core.server.BrooklynServerConfig;
 import org.apache.brooklyn.core.server.BrooklynServerPaths;
+import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.core.typereg.BrooklynBomBundleCatalogBundleResolver;
 import 
org.apache.brooklyn.core.typereg.BrooklynCatalogBundleResolver.BundleInstallationOptions;
 import org.apache.brooklyn.core.typereg.BrooklynCatalogBundleResolvers;
@@ -110,6 +111,7 @@ public class OsgiManager {
     public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_EXCLUDE_REGEX = 
BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_EXCLUDE_REGEX;
     public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_URL_EXCLUDE_REGEX = 
BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_URL_EXCLUDE_REGEX;
     public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_INCLUDE_REGEX = 
BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_INCLUDE_REGEX;
+    public static final ConfigKey<Boolean> 
PERSIST_MANAGED_BUNDLES_FROM_INITIAL_CATALOG = 
BrooklynServerConfig.PERSIST_MANAGED_BUNDLES_FROM_INITIAL_CATALOG;
 
     /* see `Osgis` class for info on starting framework etc */
     
@@ -471,10 +473,14 @@ public class OsgiManager {
         return install(input, format, force, null);
     }
     public ReferenceWithError<OsgiBundleInstallationResult> 
install(Supplier<InputStream> input, String format, boolean force, Boolean 
deleteable) {
+        return install(input, format, force, deleteable, false);
+    }
+    public ReferenceWithError<OsgiBundleInstallationResult> 
install(Supplier<InputStream> input, String format, boolean force, Boolean 
deleteable, Boolean fromInitialCatalog) {
         BundleInstallationOptions options = new BundleInstallationOptions();
         options.setFormat(format);
         options.setForceUpdateOfNonSnapshots(force);
         options.setDeleteable(deleteable);
+        options.setFromInitialCatalog(fromInitialCatalog);
         return BrooklynCatalogBundleResolvers.install(getManagementContext(), 
input, options);
     }
 
@@ -898,6 +904,11 @@ public class OsgiManager {
         // But we don't want to persist the entire brooklyn distro! Therefore 
default is to exclude those from persistence.
         // Similarly for anything installed via mvn or classpath.
 
+        if (managedBundle instanceof BasicManagedBundle && 
Boolean.TRUE.equals(((BasicManagedBundle)managedBundle).getFromInitialCatalog()))
 {
+            Boolean persistInitialCatalogBundles = 
mgmt.getConfig().getConfig(PERSIST_MANAGED_BUNDLES_FROM_INITIAL_CATALOG);
+            if (Boolean.FALSE.equals(persistInitialCatalogBundles)) return 
true;
+        }
+
         if (bundlePersistenceExclusionFilterCache == null) {
             String regexSymnameInclude = 
mgmt.getConfig().getConfig(PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_INCLUDE_REGEX);
             String regexSymnameIncludeLegacy = 
mgmt.getConfig().getConfig(BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX);
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 ed769ad390..00603ae7d7 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
@@ -826,7 +826,7 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
                                 // someone else persisted this (race)
                                 return;
                             }
-                            if (!isBundleOmittedFromPersistence(mb)) {
+                            if (!isBundleExcludedFromPersistence(mb)) {
                                 persist(type.getSubPathName(), type, id + 
".jar", com.google.common.io.Files.asByteSource(
                                         ((ManagementContextInternal) 
mgmt).getOsgiManager().get().getBundleFile(mb)), exceptionHandler);
                             }
@@ -837,7 +837,7 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
         }
     }
 
-    private boolean isBundleOmittedFromPersistence(ManagedBundle mb) {
+    private boolean isBundleExcludedFromPersistence(ManagedBundle mb) {
         return 
((ManagementContextInternal)mgmt).getOsgiManager().get().isExcludedFromPersistence(mb);
     }
 
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java 
b/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java
index 7ecfdc386c..d4c853eefc 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/server/BrooklynServerConfig.java
@@ -146,7 +146,7 @@ public class BrooklynServerConfig {
     public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_URL_EXCLUDE_REGEX = ConfigKeys.newStringConfigKey(
             "brooklyn.persistence.bundle.exclude.url.regex",
             "Regex for bundle URLs explicitly excluded from persistence, 
unless symbolic name is in explicit include list",
-            "(mvn|classpath):.*");
+            null);
 
     public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_EXCLUDE_REGEX = 
ConfigKeys.newStringConfigKey(
             "brooklyn.persistence.bundle.exclude.symbolicName.regex",
@@ -154,6 +154,12 @@ public class BrooklynServerConfig {
                     + "if not explicitly excluded by this or the URL 
exclusion, managed bundles will by default be peristed",
             "org\\.apache\\.brooklyn\\..*");
 
+    public static final ConfigKey<Boolean> 
PERSIST_MANAGED_BUNDLES_FROM_INITIAL_CATALOG = ConfigKeys.newBooleanConfigKey(
+            "brooklyn.persistence.bundle.initialCatalog",
+            "Whether bundles installed by the startup catalog file(s) are 
persisted; " +
+                "historically defaulted to true, but now not as it was 
wasteful, but can be overridden here",
+            false);
+
     @Deprecated /** @deprecated in favour of {@link 
#PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_INCLUDE_REGEX} */
     public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX = ConfigKeys.newStringConfigKey(
             "brooklyn.persistence.bundle.whitelist",
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 e053daaaba..fb02b28c49 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
@@ -47,10 +47,12 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
     private String format;
     private String url;
     private Credentials credentials;
+    private Boolean fromInitialCatalog;
 
     /** pretty much redundant as it is put in the delta if changed, and 
included even if not needed when full checkpoint requested */
     private transient boolean persistenceNeeded = false;
 
+
     /** Creates an empty one, with an ID, expecting other fields will be 
populated. */
     public BasicManagedBundle() {}
 
@@ -65,14 +67,17 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
 
     /** @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, null);
+        init(name, version, url, format, credentials, checksum, null, 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);
+        init(name, version, url, format, credentials, checksum, deleteable, 
null);
+    }
+    public BasicManagedBundle(String name, String version, String url, String 
format, Credentials credentials, @Nullable String checksum, @Nullable Boolean 
deleteable, @Nullable Boolean fromInitialCatalog) {
+        init(name, version, url, format, credentials, checksum, deleteable, 
fromInitialCatalog);
     }
 
-    private void init(String name, String version, String url, String format, 
Credentials credentials, @Nullable String checksum, @Nullable Boolean 
deleteable) {
+    private void init(String name, String version, String url, String format, 
Credentials credentials, @Nullable String checksum, @Nullable Boolean 
deleteable, @Nullable Boolean fromInitialCatalog) {
         if (name == null && version == null) {
             Preconditions.checkNotNull(url, "Either a URL or both name and 
version are required");
         } else {
@@ -86,18 +91,20 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
         this.credentials = credentials;
         this.checksum = checksum;
         this.deleteable = deleteable;
+        this.fromInitialCatalog = fromInitialCatalog;
     }
 
-    private BasicManagedBundle(String id, String name, String version, String 
url, String format, Credentials credentials, @Nullable String checksum, 
@Nullable Boolean deleteable) {
+    private BasicManagedBundle(String id, String name, String version, String 
url, String format, Credentials credentials, @Nullable String checksum, 
@Nullable Boolean deleteable, @Nullable Boolean fromInitialCatalog) {
         super(id);
-        init(name, version, url, format, credentials, checksum, deleteable);
+        init(name, version, url, format, credentials, checksum, deleteable, 
fromInitialCatalog);
     }
 
     /** 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(), update.getDeleteable());
+        BasicManagedBundle result = new 
BasicManagedBundle(oldOneForCoordinates.getId(), update.getSymbolicName(), 
update.getSuppliedVersionString(), update.getUrl(), update.getFormat(), 
update.getUrlCredential(), update.getChecksum(), update.getDeleteable(),
+                update instanceof BasicManagedBundle ? 
((BasicManagedBundle)update).getFromInitialCatalog() : null);
         result.tags().addTags(update.tags().getTags());
         // we have secondary logic which should accept a change in the OSGi 
unique URL,
         // but more efficient if we use the original URL
@@ -110,6 +117,9 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
         return symbolicName != null && version != null;
     }
 
+    public void setDeleteable(Boolean deleteable) {
+        this.deleteable = deleteable;
+    }
     @Override
     public Boolean getDeleteable() {
         return deleteable;
@@ -271,7 +281,7 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
         throw new UnsupportedOperationException();
     }
 
-    public static ManagedBundle of(CatalogBundle bundle) {
+    public static ManagedBundle of(OsgiBundleWithUrl bundle) {
         String checksum = (bundle instanceof ManagedBundle) ? 
((ManagedBundle)bundle).getChecksum() : null;
         return new BasicManagedBundle(
                 bundle.getSymbolicName(),
@@ -280,7 +290,8 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
                 null,
                 bundle.getUrlCredential(),
                 checksum,
-                bundle instanceof ManagedBundle ? 
((ManagedBundle)bundle).getDeleteable() : null);
+                bundle.getDeleteable(),
+                (bundle instanceof BasicManagedBundle ? 
((BasicManagedBundle)bundle).getFromInitialCatalog() : null));
     }
 
     public void setPersistenceNeeded(boolean val) {
@@ -290,5 +301,11 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
         return persistenceNeeded;
         
     }
-    
+
+    public Boolean getFromInitialCatalog() {
+        return fromInitialCatalog;
+    }
+    public void setFromInitialCatalog(Boolean fromInitialCatalog) {
+        this.fromInitialCatalog = fromInitialCatalog;
+    }
 }
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 aeb726f05b..faa51f875c 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
@@ -130,7 +130,7 @@ public class BrooklynBomYamlCatalogBundleResolver extends 
AbstractCatalogBundleR
 
             BasicManagedBundle basicManagedBundle = new 
BasicManagedBundle(vn.getSymbolicName(), vn.getVersionString(),
                     null, BrooklynBomBundleCatalogBundleResolver.FORMAT,
-                    null, null, options.getDeleteable());
+                    null, null, options.getDeleteable(), 
options.getFromInitialCatalog());
             // 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 5ee5286191..2c33f70c54 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
@@ -100,6 +100,7 @@ public interface BrooklynCatalogBundleResolver extends 
ManagementContextInjectab
         protected boolean start = true;
         protected boolean loadCatalogBom = true;
         protected Boolean deleteable = null;
+        protected Boolean fromInitialCatalog = null;
         protected ManagedBundle knownBundleMetadata = null;
 
         public void setFormat(String format) {
@@ -163,6 +164,13 @@ public interface BrooklynCatalogBundleResolver extends 
ManagementContextInjectab
         public void setDeleteable(Boolean deleteable) {
             this.deleteable = deleteable;
         }
+
+        public Boolean getFromInitialCatalog() {
+            return fromInitialCatalog;
+        }
+        public void setFromInitialCatalog(Boolean fromInitialCatalog) {
+            this.fromInitialCatalog = fromInitialCatalog;
+        }
     }
 
 }
diff --git 
a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java
 
b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java
index 255d95a417..d16aa61a4a 100644
--- 
a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java
+++ 
b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogOsgiTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.brooklyn.launcher;
 
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.server.BrooklynServerConfig;
 import org.apache.brooklyn.util.stream.InputStreamSource;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
@@ -322,7 +324,8 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest 
extends AbstractBroo
             // Should bring it under brooklyn-management (without 
re-installing it).
             startT1(newLauncherForTests(initialBomFile.getAbsolutePath()));
 
-            // Launch brooklyn again (because will have persisted both those 
bundles)
+            alsoPersistBundlesInstalledToCatalog();
+            // Launch brooklyn again (because with the above, it will have 
persisted both those bundles)
             startT2(newLauncherForTests(CATALOG_EMPTY_INITIAL));
             
             launcherT2.terminate();
@@ -333,12 +336,12 @@ public abstract class 
BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo
             
runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(false);
         }
         
-        // Aled thought we supported version ranges in 'brooklyn.libraries', 
but doesn't work here.
-        // Alex confirms nope, not supported there yet (2017-10).
-        @Test(groups="Broken")
-        public void 
testInstallPreexistingBundleViaInitialBomBrooklynLibrariesReferenceWithVersionRange()
 throws Exception {
-            
runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(true);
-        }
+//        // Aled thought we supported version ranges in 'brooklyn.libraries', 
but doesn't work here.
+//        // Alex confirms nope, not supported there yet (2017-10).
+//        @Test(groups="Broken")
+//        public void 
testInstallPreexistingBundleViaInitialBomBrooklynLibrariesReferenceWithVersionRange()
 throws Exception {
+//            
runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(true);
+//        }
         
         protected void 
runInstallPreexistingBundleViaInitialBomBrooklynLibrariesReference(boolean 
useVersionRange) throws Exception {
             Set<VersionedName> bundleItems = 
ImmutableSet.of(VersionedName.fromString("one:1.0.0"));
@@ -368,6 +371,7 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest 
extends AbstractBroo
             // Should bring it under brooklyn-management (without 
re-installing it).
             startT1(newLauncherForTests(initialBomFile.getAbsolutePath()));
 
+            alsoPersistBundlesInstalledToCatalog();
             // Launch brooklyn again (because will have persisted both those 
bundles)
             startT2(newLauncherForTests(CATALOG_EMPTY_INITIAL));
             launcherT2.terminate();
@@ -479,6 +483,7 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest 
extends AbstractBroo
             }
         };
         startT1(newLauncherForTests(initialBomFileV1.getAbsolutePath()));
+        alsoPersistBundlesInstalledToCatalog();
         startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
         assertManagedBundle(launcherLast, bundleNameV2, bundleItems);
         promoteT2IfStandby();
@@ -519,6 +524,7 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest 
extends AbstractBroo
             }
         };
         startT1(newLauncherForTests(initialBomFileV1.getAbsolutePath()));
+        alsoPersistBundlesInstalledToCatalog();
         startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
         promoteT2IfStandby();
     }
@@ -608,6 +614,7 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest 
extends AbstractBroo
         // First launcher should persist the bundle
         startT1(newLauncherForTests(initialBomFile.getAbsolutePath()));
         String bundlePersistenceId1 = findManagedBundle(launcherT1, 
bundleName).getId();
+        alsoPersistBundlesInstalledToCatalog();
         
         if (!isT1KeptRunningWhenT2Starts()) {
             launcherT1.terminate();
@@ -639,23 +646,55 @@ public abstract class 
BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo
     }
     
     @Test
-    public void testRebindRemovedItemButLeavingJavaSucceeds() throws Exception 
{
+    public void testRebindRemovedItemAlsoRemovesLibrary() throws Exception {
         File initialBomFileV2 = 
prepForRebindRemovedItemTestReturningBomV2(false, false);
         createAndStartApplication(launcherLast.getManagementContext(), 
             "services: [ { type: 'simple-entity:1' } ]");
         
-        // should start and promote fine, even though original catalog item ID 
not available
-        
-        // when we switch to loading from type registry types instead of 
persisted java type (see RebindIteration.load)
-        // T2 startup may fail like 
testRebindRemovedItemIAlsoRemovingJavaDependencyCausesFailure does,
-        // or it may fall back to the java type and succeed (but note this 
test does NOT allow the type to be upgraded)
+        // failover here fails, because we depend on the java library which is 
removed
+        startupAssertions = null;
+        startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()), 
false);
+    }
+
+    @Test
+    public void testRebindRemovedKeepsLibraryIfInstalledExplicitly() throws 
Exception {
+        File initialBomFileV2 = 
prepForRebindRemovedItemTestReturningBomV2(false, false);
+        createAndStartApplication(launcherLast.getManagementContext(),
+                "services: [ { type: 'simple-entity:1' } ]");
+
+        // as before, but if we install the java library explicitly (directly 
or as a dependendency), then it _is_ persisted
+        // (we mark it v2 so that it replaces what startT2 installs, as the 
bom file on its own otherwise has no version, and the tests assert 1.0 or 2.0)
+        
launcherLast.getManagementContext().getCatalog().addItems(initialBomV1+"\n  id: 
org.example.testRebindGetsInitialOsgiCatalog:2.0.0\n");
+
         startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
         promoteT2IfStandby();
-        
+
         Entity entity = Iterables.getOnlyElement( 
Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren()
 );
         Assert.assertEquals(entity.getCatalogItemId(), "simple-entity:1.0.0");
     }
-    
+
+    @Test
+    public void 
testRebindRemovedKeepsLibraryIfPersistFromInitialCatalogEnabled() throws 
Exception {
+        File initialBomFileV2 = 
prepForRebindRemovedItemTestReturningBomV2(false, false);
+        alsoPersistBundlesInstalledToCatalog();
+
+        createAndStartApplication(launcherLast.getManagementContext(),
+                "services: [ { type: 'simple-entity:1' } ]");
+
+        // here rebind/failover should start and promote fine, and it should 
be able to load the entity from the java type
+        startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
+        promoteT2IfStandby();
+
+        Entity entity = Iterables.getOnlyElement( 
Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren()
 );
+        Assert.assertEquals(entity.getCatalogItemId(), "simple-entity:1.0.0");
+    }
+
+    protected void alsoPersistBundlesInstalledToCatalog() {
+        
((ManagementContextInternal)launcherLast.getManagementContext()).getBrooklynProperties().put(
+                
BrooklynServerConfig.PERSIST_MANAGED_BUNDLES_FROM_INITIAL_CATALOG, true);
+        
launcherLast.getManagementContext().getRebindManager().forcePersistNow(true, 
null);
+    }
+
     @Test
     public void testRebindRemovedItemAndRemovingJavaDependencyCausesFailure() 
throws Exception {
         File initialBomFileV2 = 
prepForRebindRemovedItemTestReturningBomV2(true, false);
@@ -686,18 +725,18 @@ public abstract class 
BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo
             Asserts.assertSize( 
Iterables.getOnlyElement(launcherLast.getManagementContext().getApplications()).getChildren(),
 0 );
         }
     }
-    
+
+    private final String initialBomV1 = Joiner.on("\n").join(
+            "brooklyn.catalog:",
+            "  brooklyn.libraries:",
+            "    - " + 
OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_URL,
+            "  items:",
+            "    - id: simple-entity",
+            "      item:",
+            "        type: 
com.example.brooklyn.test.osgi.entities.SimpleEntity");
     private File prepForRebindRemovedItemTestReturningBomV2(boolean 
removeSourceJavaBundle, boolean upgradeEntity) throws Exception {
         
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), 
OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_PATH);
         
-        String initialBomV1 = Joiner.on("\n").join(
-                "brooklyn.catalog:",
-                "  brooklyn.libraries:",
-                "    - " + 
OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_URL,
-                "  items:",
-                "    - id: simple-entity",
-                "      item:",
-                "        type: 
com.example.brooklyn.test.osgi.entities.SimpleEntity");
         VersionedName bundleNameV1 = new 
VersionedName("org.example.testRebindGetsInitialOsgiCatalog", "1.0.0");
         File bundleFileV1 = 
newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, 
initialBomV1.getBytes()), bundleNameV1);
         File initialBomFileV1 = 
newTmpFile(createCatalogYaml(ImmutableList.of(bundleFileV1.toURI()), 
ImmutableList.of()));
@@ -740,7 +779,8 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest 
extends AbstractBroo
         File initialBomFileV2 = 
prepForRebindRemovedItemTestReturningBomV2(CatalogUpgrades.markerForCodeThatLoadsJavaTypesButShouldLoadRegisteredType(),
 true);
         createAndStartApplication(launcherLast.getManagementContext(), 
             "services: [ { type: 'simple-entity:1' } ]");
-        
+
+        alsoPersistBundlesInstalledToCatalog();
         startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
         promoteT2IfStandby();
         
@@ -790,7 +830,7 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest 
extends AbstractBroo
         createAndStartApplication(launcherLast.getManagementContext(), 
             "services: [ { type: references-simple-entity } ]");
         
-
+        alsoPersistBundlesInstalledToCatalog();
         startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
         promoteT2IfStandby();
         
@@ -836,7 +876,8 @@ public abstract class BrooklynLauncherRebindCatalogOsgiTest 
extends AbstractBroo
         Entity cluster = Iterables.getOnlyElement( app.getChildren() );
         ((DynamicCluster)cluster).resize(0);
         // at size 0 it should always persist and rebind, even with the 
dependent java removed (args to prep method above)
-              
+
+        alsoPersistBundlesInstalledToCatalog();
         startT2(newLauncherForTests(initialBomFileV2.getAbsolutePath()));
         promoteT2IfStandby();
         
@@ -953,17 +994,17 @@ public abstract class 
BrooklynLauncherRebindCatalogOsgiTest extends AbstractBroo
         return newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM, 
bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName);
     }
 
-    // convenience for testing just a single test (TestNG plugin otherwise 
runs lots of them)
-    public static void main(String[] args) throws Exception {
-        try {
-            BrooklynLauncherRebindCatalogOsgiTest fixture = new 
LauncherRebindSubTests();
-            fixture.setUp();
-            fixture.testRebindUpgradeSpecUsedInDeployedApp();
-            fixture.tearDown();
-        } catch (Throwable e) {
-            e.printStackTrace();
-            System.exit(1);
-        } 
-        System.exit(0);
-    }
+//    // convenience for testing just a single test (TestNG plugin otherwise 
runs lots of them)
+//    public static void main(String[] args) throws Exception {
+//        try {
+//            BrooklynLauncherRebindCatalogOsgiTest fixture = new 
LauncherRebindSubTests();
+//            fixture.setUp();
+//            fixture.testRebindUpgradeSpecUsedInDeployedApp();
+//            fixture.tearDown();
+//        } catch (Throwable e) {
+//            e.printStackTrace();
+//            System.exit(1);
+//        }
+//        System.exit(0);
+//    }
 }

Reply via email to