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 2738ecb64e8efadd0bd33426befbc0ae2a1e16ec
Author: Alex Heneveld <a...@cloudsoft.io>
AuthorDate: Thu Mar 28 14:11:04 2024 +0000

    exclude mvn: and classpath: url bundles from persistence, and related tweaks
    
    - change {white,black}list to include/exclude list, for bundles
    - add ability to exclude bundles based on url prefix, now defaulting to 
mvn: and classpath:
    - fix bug where setPersistenceNeeded never cleared it, so it persisted more 
often than it should
    - also prevent persistence when rebinding, as there is no point
---
 .../CatalogOsgiVersionMoreEntityRebindTest.java    | 13 ++--
 .../catalog/internal/CatalogInitialization.java    |  1 +
 .../mgmt/ha/BrooklynBomOsgiArchiveInstaller.java   | 57 ++++-----------
 .../core/mgmt/ha/OsgiBundleInstallationResult.java |  5 ++
 .../apache/brooklyn/core/mgmt/ha/OsgiManager.java  | 82 ++++++++++++++++++----
 .../BrooklynMementoPersisterToObjectStore.java     | 20 ++++--
 .../brooklyn/core/server/BrooklynServerConfig.java | 40 +++++++----
 .../brooklyn/core/typereg/BasicManagedBundle.java  |  4 +-
 .../ha/BrooklynBomOsgiArchiveInstallerTest.java    | 30 ++++----
 9 files changed, 149 insertions(+), 103 deletions(-)

diff --git 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java
 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java
index 29b33f322b..a710d5243d 100644
--- 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java
+++ 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java
@@ -18,11 +18,12 @@
  */
 package org.apache.brooklyn.camp.brooklyn.catalog;
 
-import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
-import static org.testng.Assert.assertEquals;
-
 import java.util.Map;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
 import org.apache.brooklyn.api.effector.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
@@ -50,6 +51,7 @@ import 
org.apache.brooklyn.test.support.TestResourceUnavailableException;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ClassLoaderUtils;
 import org.apache.brooklyn.util.core.ResourceUtils;
+import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
 import org.apache.brooklyn.util.exceptions.ReferenceWithError;
 import org.apache.brooklyn.util.javalang.Reflections;
 import org.apache.brooklyn.util.osgi.OsgiTestResources;
@@ -61,10 +63,7 @@ import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
+import static org.testng.Assert.assertEquals;
 
 /** Many of the same tests as per {@link OsgiVersionMoreEntityTest} but using 
YAML for catalog and entities, so catalog item ID is set automatically */
 public class CatalogOsgiVersionMoreEntityRebindTest extends 
AbstractYamlRebindTest implements OsgiTestResources {
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 7b24cec778..5050977767 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
@@ -555,6 +555,7 @@ public class CatalogInitialization implements 
ManagementContextInjectable {
         Set<OsgiBundleInstallationResult> bundlesToRemove = MutableSet.of();
         installs.values().stream().forEach(candidate -> {
             if 
(filteredPersistedState.getBundles().containsKey(candidate.getVersionedName())) 
{
+                candidate.setRebinding(true);
                 bundlesInOrder.add(candidate);
             } else {
                 log.debug("Skipping start of persisted bundle "+candidate+" 
due to catalog upgrade metadata instructions");
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 237249de57..cf47f230eb 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,26 +27,25 @@ 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;
-import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 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.OsgiBundleWithUrl;
 import org.apache.brooklyn.api.typereg.RegisteredType;
-import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.BrooklynVersion;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
 import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
 import 
org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult.ResultCode;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
-import org.apache.brooklyn.core.server.BrooklynServerConfig;
 import org.apache.brooklyn.core.typereg.*;
 import org.apache.brooklyn.core.typereg.BundleUpgradeParser.CatalogUpgrades;
 import org.apache.brooklyn.util.collections.MutableList;
@@ -76,9 +75,6 @@ public class BrooklynBomOsgiArchiveInstaller {
 
     private static final Logger log = 
LoggerFactory.getLogger(BrooklynBomOsgiArchiveInstaller.class);
     
-    public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX = 
BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX;
-    public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX = 
BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX;
-
     final private OsgiManager osgiManager;
     private ManagedBundle suppliedKnownBundleMetadata;
     private InputStream zipIn;
@@ -117,8 +113,6 @@ public class BrooklynBomOsgiArchiveInstaller {
     private ManagedBundle inferredMetadata;
     private final boolean inputStreamSupplied;
     
-    private volatile Predicate<ManagedBundle> 
blacklistBundlePersistencePredicate;
-    
     public BrooklynBomOsgiArchiveInstaller(OsgiManager osgiManager, 
ManagedBundle knownBundleMetadata, InputStream zipIn) {
         this.osgiManager = osgiManager;
         this.suppliedKnownBundleMetadata = knownBundleMetadata;
@@ -709,11 +703,12 @@ public class BrooklynBomOsgiArchiveInstaller {
                             log.error("Error rolling back following failed 
install of updated "+result.getVersionedName()+"; "
                                 + "installation will likely be corrupted and 
correct version should be manually installed.", e);
                         }
-                        
-                        if 
(!isBlacklistedForPersistence(result.getMetadata())) {
-                            
((BasicManagedBundle)result.getMetadata()).setPersistenceNeeded(true);
-                            
mgmt().getRebindManager().getChangeListener().onChanged(result.getMetadata());
+
+                        if (!isExcludedFromPersistence(oldManagedBundle)) {
+                            
((BasicManagedBundle)oldManagedBundle).setPersistenceNeeded(true);
+                            
mgmt().getRebindManager().getChangeListener().onChanged(oldManagedBundle);
                         }
+
                     } else {
                         if 
(isBringingExistingOsgiInstalledBundleUnderBrooklynManagement) {
                             log.debug("Uninstalling bundle 
"+result.getVersionedName()+" from Brooklyn management only (rollback needed 
but it was already installed to OSGi)");
@@ -721,7 +716,7 @@ public class BrooklynBomOsgiArchiveInstaller {
                             log.debug("Uninstalling bundle 
"+result.getVersionedName()+" (roll back of failed fresh install, no previous 
version to revert to)");
                         }                        
                         
osgiManager.uninstallUploadedBundle(result.getMetadata(), false, 
isBringingExistingOsgiInstalledBundleUnderBrooklynManagement);
-                        if 
(!isBlacklistedForPersistence(result.getMetadata())) {
+                        if (!isExcludedFromPersistence(result.getMetadata())) {
                             
((BasicManagedBundle)result.getMetadata()).setPersistenceNeeded(true);
                             
mgmt().getRebindManager().getChangeListener().onUnmanaged(result.getMetadata());
                         }
@@ -731,7 +726,7 @@ public class BrooklynBomOsgiArchiveInstaller {
                     if (start) {
                         try {
                             log.debug("Starting bundle 
"+result.getVersionedName());
-                            if 
(!isBlacklistedForPersistence(result.getMetadata())) {
+                            if 
(!isExcludedFromPersistence(result.getMetadata()) && 
!Boolean.TRUE.equals(result.rebinding)) {
                                 
((BasicManagedBundle)result.getMetadata()).setPersistenceNeeded(true);
                                 if (updating) {
                                     
mgmt().getRebindManager().getChangeListener().onChanged(result.getMetadata());
@@ -914,36 +909,8 @@ public class BrooklynBomOsgiArchiveInstaller {
     }
 
     @VisibleForTesting
-    boolean isBlacklistedForPersistence(ManagedBundle managedBundle) {
-        // We treat as "managed bundles" (to extract their catalog.bom) the 
contents of:
-        //   - org.apache.brooklyn.core
-        //   - org.apache.brooklyn.policy
-        //   - org.apache.brooklyn.test-framework
-        //   - org.apache.brooklyn.software-*
-        //   - org.apache.brooklyn.library-catalog
-        //   - org.apache.brooklyn.karaf-init (not sure why this one could end 
up in persisted state!)
-        // We don't want to persist the entire brooklyn distro! Therefore 
default is to blacklist those.
-        
-        if (blacklistBundlePersistencePredicate == null) {
-            String whitelistRegex = 
mgmt().getConfig().getConfig(PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX);
-            String blacklistRegex = 
mgmt().getConfig().getConfig(PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX);
-            
-            final Pattern whitelistPattern = (whitelistRegex != null) ? 
Pattern.compile(whitelistRegex) : null;
-            final Pattern blacklistPattern = (blacklistRegex != null) ? 
Pattern.compile(blacklistRegex) : null;
-
-            blacklistBundlePersistencePredicate = input -> {
-                    String bundleName = input.getSymbolicName();
-                    if (whitelistPattern != null && 
whitelistPattern.matcher(bundleName).matches()) {
-                        return false;
-                    }
-                    if (blacklistPattern != null && 
blacklistPattern.matcher(bundleName).matches()) {
-                        return true;
-                    }
-                    return false;
-            };
-        }
-        
-        return blacklistBundlePersistencePredicate.test(managedBundle);
+    boolean isExcludedFromPersistence(ManagedBundle managedBundle) {
+        return osgiManager.isExcludedFromPersistence(managedBundle);
     }
     
     private static List<Bundle> 
findBundlesBySymbolicNameAndVersion(OsgiManager osgiManager, ManagedBundle 
desired) {
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java
 
b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java
index dbb48c46f3..f6c16b3c02 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java
@@ -37,6 +37,7 @@ public class OsgiBundleInstallationResult {
     Bundle bundle;
     ResultCode code;
     Runnable deferredStart;
+    Boolean rebinding;
     
     public enum ResultCode { 
         INSTALLED_NEW_BUNDLE(false),
@@ -117,4 +118,8 @@ public class OsgiBundleInstallationResult {
         typesInstalled.add(ci);
         catalogItemsInstalled.add(ci.getId());        
     }
+
+    public void setRebinding(Boolean rebinding) {
+        this.rebinding = rebinding;
+    }
 }
\ No newline at end of file
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 32588c6ee7..4455028291 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
@@ -18,24 +18,34 @@
  */
 package org.apache.brooklyn.core.mgmt.ha;
 
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.Callable;
-import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Predicate;
 import java.util.function.Supplier;
+import java.util.regex.Pattern;
 import javax.annotation.Nullable;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
 import org.apache.brooklyn.api.framework.FrameworkLookup;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
@@ -46,12 +56,14 @@ import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.BrooklynVersion;
 import org.apache.brooklyn.core.catalog.internal.CatalogBundleLoader;
 import org.apache.brooklyn.core.config.ConfigKeys;
-import org.apache.brooklyn.core.typereg.*;
-import 
org.apache.brooklyn.core.typereg.BrooklynCatalogBundleResolver.BundleInstallationOptions;
 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.BrooklynBomBundleCatalogBundleResolver;
+import 
org.apache.brooklyn.core.typereg.BrooklynCatalogBundleResolver.BundleInstallationOptions;
+import org.apache.brooklyn.core.typereg.BrooklynCatalogBundleResolvers;
 import org.apache.brooklyn.core.typereg.BundleUpgradeParser.CatalogUpgrades;
+import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.collections.MutableSet;
@@ -75,7 +87,6 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
-import org.osgi.framework.FrameworkEvent;
 import org.osgi.framework.launch.Framework;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -96,6 +107,10 @@ public class OsgiManager {
 
     public static final ConfigKey<Boolean> OSGI_STARTUP_COMPLETE = 
ConfigKeys.newBooleanConfigKey("brooklyn.osgi.startup.complete");
 
+    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;
+
     /* see `Osgis` class for info on starting framework etc */
     
     final ManagementContext mgmt;
@@ -870,4 +885,43 @@ public class OsgiManager {
         return managedBundlesRecord.fileFor(mb);
     }
 
+    private volatile Predicate<ManagedBundle> 
bundlePersistenceExclusionFilterCache;
+    public boolean isExcludedFromPersistence(ManagedBundle managedBundle) {
+        // We treat as "managed bundles" (to extract their catalog.bom) the 
contents of:
+        //   - org.apache.brooklyn.core
+        //   - org.apache.brooklyn.policy
+        //   - org.apache.brooklyn.test-framework
+        //   - org.apache.brooklyn.software-*
+        //   - org.apache.brooklyn.library-catalog
+        //   - org.apache.brooklyn.karaf-init (not sure why this one could end 
up in persisted state!)
+
+        // 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 (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);
+            String regexSymnameExclude = 
mgmt.getConfig().getConfig(PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_EXCLUDE_REGEX);
+            String regexSymnameExcludeLegacy = 
mgmt.getConfig().getConfig(BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX);
+            String regexUrlExclude = 
mgmt.getConfig().getConfig(PERSIST_MANAGED_BUNDLE_URL_EXCLUDE_REGEX);
+
+            final Pattern patternSymnameInclude = (regexSymnameInclude != 
null) ? Pattern.compile(regexSymnameInclude) : null;
+            final Pattern patternSymnameIncludeLegacy = 
(regexSymnameIncludeLegacy != null) ? 
Pattern.compile(regexSymnameIncludeLegacy) : null;
+            final Pattern patternUrlExclude = (regexUrlExclude != null) ? 
Pattern.compile(regexUrlExclude) : null;
+            final Pattern patternSymnameExclude = (regexSymnameExclude != 
null) ? Pattern.compile(regexSymnameExclude) : null;
+            final Pattern patternSymnameExcludeLegacy = 
(regexSymnameExcludeLegacy != null) ? 
Pattern.compile(regexSymnameExcludeLegacy) : null;
+
+            bundlePersistenceExclusionFilterCache = input -> {
+                String bundleName = input.getSymbolicName();
+                if (patternSymnameInclude != null && 
patternSymnameInclude.matcher(bundleName).matches()) return false;
+                if (patternSymnameIncludeLegacy != null && 
patternSymnameIncludeLegacy.matcher(bundleName).matches()) return false;
+                if (patternUrlExclude != null && input.getUrl()!=null && 
patternUrlExclude.matcher(input.getUrl()).matches()) return true;
+                if (patternSymnameExclude != null && 
patternSymnameExclude.matcher(bundleName).matches()) return true;
+                if (patternSymnameExcludeLegacy != null && 
patternSymnameExcludeLegacy.matcher(bundleName).matches()) return true;
+                return false;
+            };
+        }
+
+        return bundlePersistenceExclusionFilterCache.test(managedBundle);
+    }
 }
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 82fd7c5cda..ed769ad390 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
@@ -684,7 +684,7 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
             futures.add(asyncUpdatePlaneId(newMemento.getPlaneId(), 
exceptionHandler));
             for (BrooklynObjectType type: 
BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
                 for (Map.Entry<String, String> entry : 
newMemento.getObjectsOfType(type).entrySet()) {
-                    addPersistContentIfManagedBundle(type, entry.getKey(), 
entry.getValue(), futures, exceptionHandler, contextDetails);
+                    addPersistContentIfManagedBundle(type, false, 
entry.getKey(), entry.getValue(), futures, exceptionHandler, contextDetails);
                     futures.add(asyncPersist(type.getSubPathName(), type, 
entry.getKey(), entry.getValue(), exceptionHandler));
                 }
             }
@@ -770,7 +770,7 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
             for (BrooklynObjectType type: 
BrooklynPersistenceUtils.STANDARD_BROOKLYN_OBJECT_TYPE_PERSISTENCE_ORDER) {
                 for (Memento item : delta.getObjectsOfType(type)) {
                     if (!deletedIds.contains(item.getId())) {
-                        addPersistContentIfManagedBundle(type, item.getId(), 
""+item.getCatalogItemId()+"/"+item.getDisplayName(), futures, 
exceptionHandler, null);
+                        addPersistContentIfManagedBundle(type, true, 
item.getId(), ""+item.getCatalogItemId()+"/"+item.getDisplayName(), futures, 
exceptionHandler, null);
                         futures.add(asyncPersist(type.getSubPathName(), item, 
exceptionHandler));
                     }
                 }
@@ -800,7 +800,7 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
         return lastErrors;
     }
 
-    private void addPersistContentIfManagedBundle(final BrooklynObjectType 
type, final String id, final String summaryOrContents, 
List<ListenableFuture<?>> futures, final PersistenceExceptionHandler 
exceptionHandler, final @Nullable RebindManager deltaContext) {
+    private void addPersistContentIfManagedBundle(final BrooklynObjectType 
type, final boolean isDelta, final String id, final String summaryOrContents, 
List<ListenableFuture<?>> futures, final PersistenceExceptionHandler 
exceptionHandler, final @Nullable RebindManager deltaContext) {
         if (type==BrooklynObjectType.MANAGED_BUNDLE) {
             if (mgmt==null) {
                 throw new IllegalStateException("Cannot persist bundles 
without a management context");
@@ -818,16 +818,18 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
             }
             
             if (mb instanceof BasicManagedBundle) {
-                if (((BasicManagedBundle)mb).getPersistenceNeeded()) {
+                if (!isDelta || 
((BasicManagedBundle)mb).getPersistenceNeeded()) {
                     futures.add( executor.submit(new Runnable() {
                         @Override
                         public void run() {
-                            if 
(!((BasicManagedBundle)mb).getPersistenceNeeded()) {
+                            if (isDelta && 
!((BasicManagedBundle)mb).getPersistenceNeeded()) {
                                 // someone else persisted this (race)
                                 return;
                             }
-                            persist(type.getSubPathName(), type, id+".jar", 
com.google.common.io.Files.asByteSource(
-                                
((ManagementContextInternal)mgmt).getOsgiManager().get().getBundleFile(mb)), 
exceptionHandler);
+                            if (!isBundleOmittedFromPersistence(mb)) {
+                                persist(type.getSubPathName(), type, id + 
".jar", com.google.common.io.Files.asByteSource(
+                                        ((ManagementContextInternal) 
mgmt).getOsgiManager().get().getBundleFile(mb)), exceptionHandler);
+                            }
                             
((BasicManagedBundle)mb).setPersistenceNeeded(false);
                         } }) );
                 }
@@ -835,6 +837,10 @@ public class BrooklynMementoPersisterToObjectStore 
implements BrooklynMementoPer
         }
     }
 
+    private boolean isBundleOmittedFromPersistence(ManagedBundle mb) {
+        return 
((ManagementContextInternal)mgmt).getOsgiManager().get().isExcludedFromPersistence(mb);
+    }
+
     @Override
     public void waitForWritesCompleted(Duration timeout) throws 
InterruptedException, TimeoutException {
         boolean locked = 
lock.readLock().tryLock(timeout.toMillisecondsRoundingUp(), 
TimeUnit.MILLISECONDS);
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 b1d7331455..7ecfdc386c 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
@@ -18,13 +18,12 @@
  */
 package org.apache.brooklyn.core.server;
 
-import static org.apache.brooklyn.core.config.ConfigKeys.newBooleanConfigKey;
-import static org.apache.brooklyn.core.config.ConfigKeys.newStringConfigKey;
-
 import java.net.URI;
 import java.util.List;
 import java.util.Map;
 
+import com.google.common.collect.ImmutableList;
+import com.google.common.reflect.TypeToken;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.config.StringConfigMap;
@@ -36,8 +35,8 @@ import org.apache.brooklyn.util.time.Duration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.reflect.TypeToken;
+import static org.apache.brooklyn.core.config.ConfigKeys.newBooleanConfigKey;
+import static org.apache.brooklyn.core.config.ConfigKeys.newStringConfigKey;
 
 /** Config keys for the brooklyn server */
 public class BrooklynServerConfig {
@@ -97,7 +96,7 @@ public class BrooklynServerConfig {
             "Whether a backup of in-memory state should be made to the backup 
persistence location on node demotion, "
             + "in case other nodes might write conflicting state", true);
 
-    /** @deprecated since 0.7.0, use {@link #PERSISTENCE_BACKUPS_ON_PROMOTION} 
and {@link #PERSISTENCE_BACKUPS_ON_DEMOTION},
+    /** @deprecated since 0.7.0, use {@link 
#PERSISTENCE_BACKUPS_REQUIRED_ON_PROMOTION} and {@link 
#PERSISTENCE_BACKUPS_REQUIRED_ON_DEMOTION},
      * which allow using a different target location and are supported on more 
environments (and now default to true) */
     @Deprecated
     public static final ConfigKey<Boolean> PERSISTENCE_BACKUPS_REQUIRED =
@@ -138,18 +137,31 @@ public class BrooklynServerConfig {
     public static final ConfigKey<Boolean> OSGI_CACHE_CLEAN = 
ConfigKeys.newBooleanConfigKey("brooklyn.osgi.cache.clean",
         "Whether to delete the OSGi directory before and after use; if unset, 
it will delete if the node ID forms part of the cache dir path (which by 
default it does) to avoid file leaks");
 
+    public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_INCLUDE_REGEX = 
ConfigKeys.newStringConfigKey(
+            "brooklyn.persistence.bundle.include.symbolicName.regex",
+            "Regex for bundle symbolic names explicitly allowed to be 
persisted, taking precedence over exclude list; " +
+                    "bundles are included by default unless excluded, so 
things only need to be listed here if they want to override an exclusion",
+            null);
+
+    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):.*");
+
+    public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_EXCLUDE_REGEX = 
ConfigKeys.newStringConfigKey(
+            "brooklyn.persistence.bundle.exclude.symbolicName.regex",
+            "Regex for bundle symbolic names explicitly excluded from 
persistence (but include list takes precedence); "
+                    + "if not explicitly excluded by this or the URL 
exclusion, managed bundles will by default be peristed",
+            "org\\.apache\\.brooklyn\\..*");
+
+    @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",
-            "Regex for bundle symbolic names explicitly allowed to be 
persisted (taking precedence over blacklist); "
-                    + "managed bundles will by default be peristed if not 
blacklisted; "
-                    + "they do not need to be explicitly whitelisted.",
-            null);
-    
+            "Legacy name for 
"+PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_INCLUDE_REGEX.getName());
+    @Deprecated /** @deprecated in favour of {@link 
#PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_EXCLUDE_REGEX} */
     public static final ConfigKey<String> 
PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX = ConfigKeys.newStringConfigKey(
             "brooklyn.persistence.bundle.blacklist",
-            "Regex for bundle symbolic names explicitly excluded from 
persistence (but whitelist takes precedence); "
-                    + "if not explicitly blacklisted, managed bundles will by 
default be peristed",
-            "org\\.apache\\.brooklyn\\..*");
+            "Legacy name for 
"+PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_EXCLUDE_REGEX.getName());
 
     /** @see BrooklynServerPaths#getMgmtBaseDir(ManagementContext) */
     public static String getMgmtBaseDir(ManagementContext mgmt) {
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 42f7dbd96d..e053daaaba 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,6 +47,8 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
     private String format;
     private String url;
     private Credentials credentials;
+
+    /** 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. */
@@ -282,7 +284,7 @@ public class BasicManagedBundle extends 
AbstractBrooklynObject implements Manage
     }
 
     public void setPersistenceNeeded(boolean val) {
-        persistenceNeeded |= val;
+        persistenceNeeded = val;
     }
     public boolean getPersistenceNeeded() {
         return persistenceNeeded;
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstallerTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstallerTest.java
index 8bd142e139..b37457eeb8 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstallerTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/mgmt/ha/BrooklynBomOsgiArchiveInstallerTest.java
@@ -38,33 +38,33 @@ public class BrooklynBomOsgiArchiveInstallerTest extends 
BrooklynMgmtUnitTestSup
     // BrooklynMgmtUnitTestSupport, which does not expose `useOsgi` or 
`osgiReuse`
     
     @Test
-    public void testBlacklistPersistingOrgApacheBrooklyn() throws Exception {
-        OsgiManager osgiManager = newMockOsgiManager(mgmt);
+    public void testBundlePersistenceExclusionOrgApacheBrooklyn() throws 
Exception {
+        OsgiManager osgiManager = new OsgiManager(mgmt);
         BrooklynBomOsgiArchiveInstaller installer = new 
BrooklynBomOsgiArchiveInstaller(osgiManager, Mockito.mock(ManagedBundle.class), 
new ByteArrayInputStream(new byte[0]));
         
-        
assertTrue(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.core",
 "1.0.0")));
-        
assertTrue(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.mybundle",
 "1.0.0")));
-        
assertFalse(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.different",
 "1.0.0")));
+        
assertTrue(installer.isExcludedFromPersistence(newMockManagedBundle("org.apache.brooklyn.core",
 "1.0.0")));
+        
assertTrue(installer.isExcludedFromPersistence(newMockManagedBundle("org.apache.brooklyn.mybundle",
 "1.0.0")));
+        
assertFalse(installer.isExcludedFromPersistence(newMockManagedBundle("org.apache.different",
 "1.0.0")));
     }
 
     @Test
-    public void testWhitelistPersistingBundle() throws Exception {
-        
mgmt.getBrooklynProperties().put(BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_WHITELIST_REGEX,
 "org\\.apache\\.brooklyn\\.mywhitelistedbundle");
-        OsgiManager osgiManager = newMockOsgiManager(mgmt);
+    public void testBundlePersistenceExclusionExplicitInclusion() throws 
Exception {
+        
mgmt.getBrooklynProperties().put(BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_INCLUDE_REGEX,
 "org\\.apache\\.brooklyn\\.myincludebundle");
+        OsgiManager osgiManager = new OsgiManager(mgmt);
         BrooklynBomOsgiArchiveInstaller installer = new 
BrooklynBomOsgiArchiveInstaller(osgiManager, Mockito.mock(ManagedBundle.class), 
new ByteArrayInputStream(new byte[0]));
         
-        
assertTrue(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.core",
 "1.0.0")));
-        
assertFalse(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.mywhitelistedbundle",
 "1.0.0")));
+        
assertTrue(installer.isExcludedFromPersistence(newMockManagedBundle("org.apache.brooklyn.core",
 "1.0.0")));
+        
assertFalse(installer.isExcludedFromPersistence(newMockManagedBundle("org.apache.brooklyn.myincludebundle",
 "1.0.0")));
     }
 
     @Test
-    public void testCustomBlacklistPersistingBundle() throws Exception {
-        
mgmt.getBrooklynProperties().put(BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_BLACKLIST_REGEX,
 "org\\.example\\.myblacklistprefix.*");
-        OsgiManager osgiManager = newMockOsgiManager(mgmt);
+    public void testBundlePersistenceExclusionCustom() throws Exception {
+        
mgmt.getBrooklynProperties().put(BrooklynServerConfig.PERSIST_MANAGED_BUNDLE_SYMBOLIC_NAME_EXCLUDE_REGEX,
 "org\\.example\\.myexcludeprefix.*");
+        OsgiManager osgiManager = new OsgiManager(mgmt);
         BrooklynBomOsgiArchiveInstaller installer = new 
BrooklynBomOsgiArchiveInstaller(osgiManager, Mockito.mock(ManagedBundle.class), 
new ByteArrayInputStream(new byte[0]));
         
-        
assertTrue(installer.isBlacklistedForPersistence(newMockManagedBundle("org.example.myblacklistprefix.mysuffix",
 "1.0.0")));
-        
assertFalse(installer.isBlacklistedForPersistence(newMockManagedBundle("org.apache.brooklyn.core",
 "1.0.0")));
+        
assertTrue(installer.isExcludedFromPersistence(newMockManagedBundle("org.example.myexcludeprefix.mysuffix",
 "1.0.0")));
+        
assertFalse(installer.isExcludedFromPersistence(newMockManagedBundle("org.apache.brooklyn.core",
 "1.0.0")));
     }
 
     @Test


Reply via email to