brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [1/7] brooklyn-server git commit: Support force-bundle-removal on init
Date Fri, 27 Oct 2017 10:57:03 GMT
Repository: brooklyn-server
Updated Branches:
  refs/heads/master 05d6ee096 -> 9045005dd


Support force-bundle-removal on init


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

Branch: refs/heads/master
Commit: dba226fc2aa7fa6fd8eb6569fadb3aaf6bb6b052
Parents: 98731c2
Author: Aled Sage <aled.sage@gmail.com>
Authored: Fri Oct 20 15:41:50 2017 +0100
Committer: Aled Sage <aled.sage@gmail.com>
Committed: Mon Oct 23 17:41:46 2017 +0100

----------------------------------------------------------------------
 .../catalog/internal/BundleUpgradeParser.java   | 150 ++++++++++++-------
 .../catalog/internal/CatalogInitialization.java |  57 ++++---
 .../core/mgmt/rebind/RebindIteration.java       |  13 ++
 .../internal/BundleUpgradeParserTest.java       |  79 +++++++++-
 .../AbstractBrooklynLauncherRebindTest.java     | 119 +++++++++++----
 .../BrooklynLauncherUpgradeCatalogOsgiTest.java |  78 ++++++++--
 6 files changed, 378 insertions(+), 118 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dba226fc/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParser.java
b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParser.java
index 31df462..0773014 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParser.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParser.java
@@ -21,43 +21,62 @@ package org.apache.brooklyn.core.catalog.internal;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Dictionary;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
 
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.util.osgi.VersionedName;
 import org.apache.brooklyn.util.text.BrooklynVersionSyntax;
 import org.apache.brooklyn.util.text.QuotedStringTokenizer;
 import org.apache.brooklyn.util.text.Strings;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.Version;
 import org.osgi.framework.VersionRange;
 
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 public class BundleUpgradeParser {
 
     @Beta
-    public static final String MANIFEST_HEADER_REMOVE_LEGACY_ITEMS = "brooklyn-catalog-force-remove-legacy-items";
+    public static final String MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS = "brooklyn-catalog-force-remove-legacy-items";
+
+    @Beta
+    public static final String MANIFEST_HEADER_FORCE_REMOVE_BUNDLES = "brooklyn-catalog-force-remove-bundles";
+    
+    @Beta
+    public static final String MANIFEST_HEADER_UPGRADE_BUNDLES = "brooklyn-catalog-upgrade-for-bundles";
 
-    public static class TypeUpgrades {
-        static final TypeUpgrades EMPTY = new TypeUpgrades(ImmutableSet.of());
+    /**
+     * The result from parsing bundle(s) to find their upgrade info.
+     */
+    public static class CatalogUpgrades {
+        static final CatalogUpgrades EMPTY = new CatalogUpgrades(builder());
         
         static class Builder {
             private Set<VersionRangedName> removedLegacyItems = new LinkedHashSet<>();
-            
-            public void addAll(TypeUpgrades other) {
+            private Set<VersionRangedName> removedBundles = new LinkedHashSet<>();
+
+            public Builder removedLegacyItems(Collection<VersionRangedName> vals) {
+                removedLegacyItems.addAll(vals);
+                return this;
+            }
+            public Builder removedBundles(Collection<VersionRangedName> vals) {
+                removedBundles.addAll(vals);
+                return this;
+            }
+            public Builder addAll(CatalogUpgrades other) {
                 removedLegacyItems.addAll(other.removedLegacyItems);
+                removedBundles.addAll(other.removedBundles);
+                return this;
             }
-            public TypeUpgrades build() {
-                return new TypeUpgrades(removedLegacyItems);
+            public CatalogUpgrades build() {
+                return new CatalogUpgrades(this);
             }
         }
         
@@ -65,23 +84,38 @@ public class BundleUpgradeParser {
             return new Builder();
         }
         
-        private Set<VersionRangedName> removedLegacyItems; // TODO Want version ranges
as well
+        private Set<VersionRangedName> removedLegacyItems;
+        private Set<VersionRangedName> removedBundles;
         
-        public TypeUpgrades(Iterable<? extends VersionRangedName> removedLegacyItems)
{
-            this.removedLegacyItems = ImmutableSet.copyOf(removedLegacyItems);
+        public CatalogUpgrades(Builder builder) {
+            this.removedLegacyItems = ImmutableSet.copyOf(builder.removedLegacyItems);
+            this.removedBundles = ImmutableSet.copyOf(builder.removedBundles);
         }
 
         public boolean isEmpty() {
-            return removedLegacyItems.isEmpty();
+            return removedLegacyItems.isEmpty() && removedBundles.isEmpty();
         }
 
-        public boolean isRemoved(CatalogItem<?, ?> legacyCatalogItem) {
-            String name = legacyCatalogItem.getSymbolicName();
-            String versionStr = legacyCatalogItem.getVersion();
-            Version version = Version.valueOf(BrooklynVersionSyntax.toValidOsgiVersion(versionStr
== null ? BrooklynCatalog.DEFAULT_VERSION : versionStr));
-            
-            for (VersionRangedName removedLegacyItem : removedLegacyItems) {
-                if (removedLegacyItem.getSymbolicName().equals(name) && removedLegacyItem.getOsgiVersionRange().includes(version))
{
+        public Set<VersionRangedName> getRemovedLegacyItems() {
+            return removedLegacyItems;
+        }
+        
+        public Set<VersionRangedName> getRemovedBundles() {
+            return removedBundles;
+        }
+
+        public boolean isLegacyItemRemoved(CatalogItem<?, ?> legacyCatalogItem) {
+            VersionedName name = new VersionedName(legacyCatalogItem.getSymbolicName(), legacyCatalogItem.getVersion());
+            return contains(removedLegacyItems, name);
+        }
+
+        public boolean isBundleRemoved(VersionedName bundle) {
+            return contains(removedBundles, bundle);
+        }
+        
+        public boolean contains(Iterable<VersionRangedName> names, VersionedName name)
{
+            for (VersionRangedName contender : names) {
+                if (contender.getSymbolicName().equals(name.getSymbolicName()) &&
contender.getOsgiVersionRange().includes(name.getOsgiVersion())) {
                     return true;
                 }
             }
@@ -89,12 +123,18 @@ public class BundleUpgradeParser {
         }
     }
     
-    /** Records a name (string) and version range (string),
-     * with conveniences for pretty-printing and converting to OSGi format. */
+    /**
+     * Records a name (string) and version range (string),
+     * with conveniences for pretty-printing and converting to OSGi format.
+     * 
+     * Implementation-wise, this is similar to {@link VersionedName}, but is intended
+     * as internal-only so is cut down to only what is needed.
+     */
     public static class VersionRangedName {
         private final String name;
         private final String v;
-        
+        private transient volatile VersionRange cachedOsgiVersionRange;
+
         public static VersionRangedName fromString(String val, boolean singleVersionIsOsgiRange)
{
             if (Strings.isBlank(val)) {
                 throw new IllegalArgumentException("Must not be blank");
@@ -112,13 +152,14 @@ public class BundleUpgradeParser {
             }
         }
 
-        public VersionRangedName(String name, String v) {
-            this.name = checkNotNull(name, "name");
-            this.v = v;
-        }
-        public VersionRangedName(String name, @Nullable VersionRange v) {
+        public VersionRangedName(String name, VersionRange v) {
             this.name = checkNotNull(name, "name").toString();
-            this.v = v==null ? null : v.toString();
+            this.v = checkNotNull(v, "versionRange").toString();
+        }
+        
+        private VersionRangedName(String name, String v) {
+            this.name = checkNotNull(name, "name");
+            this.v = checkNotNull(v, "versionRange");
         }
         
         @Override
@@ -130,35 +171,17 @@ public class BundleUpgradeParser {
             return name + ":" + getOsgiVersionRange();
         }
 
-        public boolean equals(String sn, String v) {
-            return name.equals(sn) && Objects.equal(this.v, v);
-        }
-
-        public boolean equals(String sn, VersionRange v) {
-            return name.equals(sn) && Objects.equal(getOsgiVersionRange(), v);
-        }
-
         public String getSymbolicName() {
             return name;
         }
 
-        private transient VersionRange cachedOsgiVersionRange;
-        @Nullable
         public VersionRange getOsgiVersionRange() {
-            if (cachedOsgiVersionRange==null && v!=null) {
-                cachedOsgiVersionRange = v==null ? null : VersionRange.valueOf(BrooklynVersionSyntax.toValidOsgiVersionRange(v));
+            if (cachedOsgiVersionRange == null) {
+                cachedOsgiVersionRange = VersionRange.valueOf(BrooklynVersionSyntax.toValidOsgiVersionRange(v));
             }
             return cachedOsgiVersionRange;
         }
 
-        @Nullable
-        public String getOsgiVersionRangeString() {
-            VersionRange ov = getOsgiVersionRange();
-            if (ov==null) return null;
-            return ov.toString();
-        }
-
-        @Nullable
         public String getVersionString() {
             return v;
         }
@@ -178,14 +201,25 @@ public class BundleUpgradeParser {
         }
     }
 
-    public static TypeUpgrades parseBundleManifestForTypeUpgrades(Bundle bundle) {
+    public static CatalogUpgrades parseBundleManifestForCatalogUpgrades(Bundle bundle) {
         Dictionary<String, String> headers = bundle.getHeaders();
-        String removedLegacyItems = headers.get(MANIFEST_HEADER_REMOVE_LEGACY_ITEMS);
-        if (removedLegacyItems != null) {
-            List<VersionRangedName> versionedItems = parseVersionRangedNameList(removedLegacyItems,
false);
-            return new TypeUpgrades(versionedItems);
-        }
-        return TypeUpgrades.EMPTY;
+        String removedLegacyItemsHeader = headers.get(MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS);
+        String removedBundlesHeader = headers.get(MANIFEST_HEADER_FORCE_REMOVE_BUNDLES);
+        List<VersionRangedName> removedLegacyItems = ImmutableList.of();
+        List<VersionRangedName> removedBundles = ImmutableList.of();
+        if (removedLegacyItemsHeader == null && removedBundlesHeader == null) {
+            return CatalogUpgrades.EMPTY;
+        }
+        if (removedLegacyItemsHeader != null) {
+            removedLegacyItems = parseVersionRangedNameList(removedLegacyItemsHeader, false);
+        }
+        if (removedBundlesHeader != null) {
+            removedBundles = parseVersionRangedNameList(removedBundlesHeader, false);
+        }
+        return CatalogUpgrades.builder()
+                .removedLegacyItems(removedLegacyItems)
+                .removedBundles(removedBundles)
+                .build();
     }
     
     @VisibleForTesting

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dba226fc/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
----------------------------------------------------------------------
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 87e52e0..9f9da67 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
@@ -25,6 +25,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -41,7 +42,7 @@ import org.apache.brooklyn.api.objs.BrooklynObjectType;
 import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
 import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.RegisteredType;
-import org.apache.brooklyn.core.catalog.internal.BundleUpgradeParser.TypeUpgrades;
+import org.apache.brooklyn.core.catalog.internal.BundleUpgradeParser.CatalogUpgrades;
 import org.apache.brooklyn.core.mgmt.ManagementContextInjectable;
 import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult;
 import org.apache.brooklyn.core.mgmt.ha.OsgiManager;
@@ -528,37 +529,59 @@ public class CatalogInitialization implements ManagementContextInjectable
{
     }
 
     private PersistedCatalogState filterPersistedState(PersistedCatalogState persistedState,
RebindLogger rebindLogger) {
-        Maybe<OsgiManager> osgiManager = ((ManagementContextInternal)managementContext).getOsgiManager();
-        if (osgiManager.isAbsent()) {
-            // Could be running tests; do no filtering
+        CatalogUpgrades catalogUpgrades = findCatalogUpgrades(rebindLogger);
+        
+        if (catalogUpgrades.isEmpty()) {
             return persistedState;
+        } else {
+            rebindLogger.info("Filtering out persisted catalog: removedBundles="+catalogUpgrades.getRemovedBundles()+";
removedLegacyItems="+catalogUpgrades.getRemovedLegacyItems());
         }
         
-        TypeUpgrades.Builder typeUpgradesBuilder = TypeUpgrades.builder();
-        Collection<ManagedBundle> managedBundles = osgiManager.get().getManagedBundles().values();
-        for (ManagedBundle managedBundle : managedBundles) {
-            Maybe<Bundle> bundle = osgiManager.get().findBundle(managedBundle);
-            if (bundle.isPresent()) {
-                typeUpgradesBuilder.addAll(BundleUpgradeParser.parseBundleManifestForTypeUpgrades(bundle.get()));
+        Map<VersionedName, InstallableManagedBundle> bundles = new LinkedHashMap<>();
+        for (Map.Entry<VersionedName, InstallableManagedBundle> entry : persistedState.getBundles().entrySet())
{
+            if (catalogUpgrades.isBundleRemoved(entry.getKey())) {
+                rebindLogger.debug("Filtering out persisted bundle "+entry.getKey());
+            } else {
+                bundles.put(entry.getKey(), entry.getValue());
             }
         }
-        TypeUpgrades typeUpgrades = typeUpgradesBuilder.build();
-        
-        if (typeUpgrades.isEmpty()) {
-            return persistedState;
-        }
-        Map<VersionedName, InstallableManagedBundle> bundles = persistedState.getBundles();
+
         List<CatalogItem<?, ?>> legacyCatalogItems = new ArrayList<>();
         for (CatalogItem<?, ?> legacyCatalogItem : persistedState.getLegacyCatalogItems())
{
-            if (!typeUpgrades.isRemoved(legacyCatalogItem)) {
+            if (catalogUpgrades.isLegacyItemRemoved(legacyCatalogItem)) {
+                rebindLogger.debug("Filtering out persisted legacy catalog item "+legacyCatalogItem.getId());
+            } else {
                 legacyCatalogItems.add(legacyCatalogItem);
             }
         }
+        
         return new PersistedCatalogState(bundles, legacyCatalogItems);
     }
 
+    private CatalogUpgrades findCatalogUpgrades(RebindLogger rebindLogger) {
+        Maybe<OsgiManager> osgiManager = ((ManagementContextInternal)managementContext).getOsgiManager();
+        if (osgiManager.isAbsent()) {
+            // Can't find any bundles to tell if there are upgrades. Could be running tests;
do no filtering.
+            return CatalogUpgrades.EMPTY;
+        }
+        
+        CatalogUpgrades.Builder catalogUpgradesBuilder = CatalogUpgrades.builder();
+        Collection<ManagedBundle> managedBundles = osgiManager.get().getManagedBundles().values();
+        for (ManagedBundle managedBundle : managedBundles) {
+            Maybe<Bundle> bundle = osgiManager.get().findBundle(managedBundle);
+            if (bundle.isPresent()) {
+                catalogUpgradesBuilder.addAll(BundleUpgradeParser.parseBundleManifestForCatalogUpgrades(bundle.get()));
+            } else {
+                rebindLogger.info("Managed bundle "+managedBundle.getId()+" not found by
OSGi Manager; "
+                        + "ignoring when calculating persisted state catalog upgrades");
+            }
+        }
+        return catalogUpgradesBuilder.build();
+    }
+    
     public interface RebindLogger {
         void debug(String message, Object... args);
+        void info(String message, Object... args);
     }
     
     public interface InstallableManagedBundle {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dba226fc/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/RebindIteration.java
index 20c20e3..3038429 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
@@ -331,6 +331,10 @@ public abstract class RebindIteration {
             public void debug(String message, Object... args) {
                 logRebindingDebug(message, args);
             }
+            @Override
+            public void info(String message, Object... args) {
+                logRebindingInfo(message, args);
+            }
         };
 
         class InstallableManagedBundleImpl implements CatalogInitialization.InstallableManagedBundle
{
@@ -1276,6 +1280,15 @@ public abstract class RebindIteration {
         }
     }
     
+    /** logs at info, except during subsequent read-only rebinds, in which it logs trace
*/
+    protected void logRebindingInfo(String message, Object... args) {
+        if (shouldLogRebinding()) {
+            LOG.info(message, args);
+        } else {
+            LOG.trace(message, args);
+        }
+    }
+    
     protected boolean shouldLogRebinding() {
         return (readOnlyRebindCount.get() < 5) || (readOnlyRebindCount.get()%1000==0);
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dba226fc/core/src/test/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParserTest.java
b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParserTest.java
index 08cc4c9..a409eaf 100644
--- a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParserTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/BundleUpgradeParserTest.java
@@ -19,15 +19,27 @@
 package org.apache.brooklyn.core.catalog.internal;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 
+import java.util.Dictionary;
+import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
 
+import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.core.catalog.internal.BundleUpgradeParser.CatalogUpgrades;
 import org.apache.brooklyn.core.catalog.internal.BundleUpgradeParser.VersionRangedName;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.osgi.VersionedName;
+import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.Version;
 import org.osgi.framework.VersionRange;
 import org.testng.annotations.Test;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 public class BundleUpgradeParserTest {
 
@@ -37,6 +49,18 @@ public class BundleUpgradeParserTest {
     private VersionRangedName barFrom0lessThan1 = new VersionRangedName("bar", from0lessThan1);
 
     @Test
+    public void testVersionRangedName() throws Exception {
+        assertEquals(VersionRangedName.fromString("foo:0.1.0", true).toOsgiString(), "foo:0.1.0");
+        assertEquals(VersionRangedName.fromString("foo:0.1.0", false).toOsgiString(), "foo:[0.1.0,0.1.0]");
+        assertEquals(VersionRangedName.fromString("foo:[0,1)", false).toOsgiString(), "foo:[0.0.0,1.0.0)");
+        
+        assertVersionRangedNameFails("foo", "'foo' must be of 'name:versionRange' syntax");
+        assertVersionRangedNameFails("foo:bar:0.1.0", "has too many parts");
+        assertVersionRangedNameFails("", "Must not be blank");
+        assertVersionRangedNameFails(null, "Must not be blank");
+    }
+    
+    @Test
     public void testParseSingleQuotedVal() throws Exception {
         String input = "\"foo:[0,1.0.0)\"";
         assertParsed(input, ImmutableList.of(fooFrom0lessThan1));
@@ -60,7 +84,51 @@ public class BundleUpgradeParserTest {
         assertParsed(input, ImmutableList.of(new VersionRangedName("foo", exactly0dot1)));
     }
 
-    protected void assertParsed(String input, List<VersionRangedName> expected) throws
Exception {
+    @Test
+    public void testParseBundleEmptyManifest() throws Exception {
+        Bundle bundle = newMockBundle(ImmutableMap.of());
+        
+        CatalogUpgrades upgrades = BundleUpgradeParser.parseBundleManifestForCatalogUpgrades(bundle);
+        assertTrue(upgrades.isEmpty());
+        assertFalse(upgrades.isBundleRemoved(new VersionedName("org.example.brooklyn.mybundle",
"0.1.0")));
+        assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("foo", "0.1.0")));
+    }
+
+    @Test
+    public void testParseBundleManifest() throws Exception {
+        Bundle bundle = newMockBundle(ImmutableMap.of(
+                BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS, "\"foo:[0,1.0.0)\",\"bar:[0,1.0.0)\"",
+                BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, "\"org.example.brooklyn.mybundle:[0,1.0.0)\""));
+        
+        CatalogUpgrades upgrades = BundleUpgradeParser.parseBundleManifestForCatalogUpgrades(bundle);
+        assertFalse(upgrades.isEmpty());
+        assertTrue(upgrades.isBundleRemoved(new VersionedName("org.example.brooklyn.mybundle",
"0.1.0")));
+        assertFalse(upgrades.isBundleRemoved(new VersionedName("org.example.brooklyn.mybundle",
"1.0.0")));
+        
+        assertTrue(upgrades.isLegacyItemRemoved(newMockCatalogItem("foo", "0.1.0")));
+        assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("foo", "1.0.0")));
+        assertTrue(upgrades.isLegacyItemRemoved(newMockCatalogItem("bar", "0.1.0")));
+        assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("bar", "1.0.0")));
+        assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("different", "0.1.0")));
+    }
+
+    private Bundle newMockBundle(Map<String, String> rawHeaders) {
+        Dictionary<String, String> headers = new Hashtable<>(rawHeaders);
+        Bundle result = Mockito.mock(Bundle.class);
+        Mockito.when(result.getHeaders()).thenReturn(headers);
+        return result;
+    }
+
+    private CatalogItem<?,?> newMockCatalogItem(String symbolicName, String version)
{
+        CatalogItem<?,?> result = Mockito.mock(CatalogItem.class);
+        Mockito.when(result.getSymbolicName()).thenReturn(symbolicName);
+        Mockito.when(result.getVersion()).thenReturn(version);
+        Mockito.when(result.getId()).thenReturn(symbolicName+":"+version);
+        Mockito.when(result.getCatalogItemId()).thenReturn(symbolicName+":"+version);
+        return result;
+    }
+    
+    private void assertParsed(String input, List<VersionRangedName> expected) throws
Exception {
         List<VersionRangedName> actual = BundleUpgradeParser.parseVersionRangedNameList(input,
false);
         assertEquals(actual.size(), expected.size(), "actual="+actual); 
         for (int i = 0; i < actual.size(); i++) {
@@ -68,4 +136,13 @@ public class BundleUpgradeParserTest {
             assertEquals(actual.get(i).getOsgiVersionRange(), expected.get(i).getOsgiVersionRange());
         }
     }
+    
+    private void assertVersionRangedNameFails(String input, String expectedFailure, String...
optionalOtherExpectedFailures) {
+        try {
+            VersionRangedName.fromString(input, false);
+            Asserts.shouldHaveFailedPreviously();
+        } catch (IllegalArgumentException e) {
+            Asserts.expectedFailureContains(e, expectedFailure, optionalOtherExpectedFailures);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dba226fc/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java
b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java
index b4b5361..0369862 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/AbstractBrooklynLauncherRebindTest.java
@@ -20,9 +20,11 @@ package org.apache.brooklyn.launcher;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.InputStream;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
@@ -53,6 +55,7 @@ import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.osgi.BundleMaker;
 import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.osgi.VersionedName;
+import org.apache.brooklyn.util.stream.Streams;
 import org.apache.brooklyn.util.text.Identifiers;
 import org.apache.brooklyn.util.time.Duration;
 import org.osgi.framework.Constants;
@@ -209,6 +212,12 @@ public abstract class AbstractBrooklynLauncherRebindTest {
         assertEquals(actualCatalogItems, expectedCatalogItems, "actual="+actualCatalogItems+";
expected="+expectedCatalogItems);
     }
 
+    protected void assertNotManagedBundle(BrooklynLauncher launcher, VersionedName bundleId)
{
+        ManagementContextInternal mgmt = (ManagementContextInternal)launcher.getManagementContext();
+        ManagedBundle bundle = mgmt.getOsgiManager().get().getManagedBundle(bundleId);
+        assertNull(bundle, bundleId+" should not exist");
+    }
+
     private static <T> boolean compareIterablesWithoutOrderMatters(Iterable<T>
a, Iterable<T> b) {
         List<T> aList = Lists.newArrayList(a);
         List<T> bList = Lists.newArrayList(b);
@@ -216,36 +225,17 @@ public abstract class AbstractBrooklynLauncherRebindTest {
         return aList.containsAll(bList) && bList.containsAll(aList);
     }
     
-    protected void initPersistedState(Map<String, String> legacyCatalogContents) throws
Exception {
-        CatalogInitialization catalogInitialization = new CatalogInitialization(CATALOG_EMPTY_INITIAL);
-        BrooklynLauncher launcher = newLauncherForTests()
-                .catalogInitialization(catalogInitialization);
-        launcher.start();
-        assertCatalogConsistsOfIds(launcher, ImmutableList.of());
-        launcher.terminate();
-        
-        for (Map.Entry<String, String> entry : legacyCatalogContents.entrySet()) {
-            addMemento(BrooklynObjectType.CATALOG_ITEM, entry.getKey(), entry.getValue());
-        }
-    }
-
-    protected void addMemento(BrooklynObjectType type, String id, String contents) throws
Exception {
-        File persistedFile = getPersistanceFile(type, id);
-        Files.write(contents.getBytes(StandardCharsets.UTF_8), persistedFile);
-    }
-
-    protected File getPersistanceFile(BrooklynObjectType type, String id) {
-        String dir;
-        switch (type) {
-            case ENTITY: dir = "entities"; break;
-            case LOCATION: dir = "locations"; break;
-            case POLICY: dir = "policies"; break;
-            case ENRICHER: dir = "enrichers"; break;
-            case FEED: dir = "feeds"; break;
-            case CATALOG_ITEM: dir = "catalog"; break;
-            default: throw new UnsupportedOperationException("type="+type);
-        }
-        return new File(persistenceDir, Os.mergePaths(dir, id));
+    protected String createPersistenceManagedBundle(String randomId, VersionedName bundleName)
{
+        return Joiner.on("\n").join(
+                "<managedBundle>",
+                "<brooklynVersion>1.0.0-SNAPSHOT</brooklynVersion>",
+                "<type>org.apache.brooklyn.core:org.apache.brooklyn.core.typereg.BasicManagedBundle</type>",
+                "<id>"+randomId+"</id>",
+                "<searchPath class=\"ImmutableList\"/>",
+                "<symbolicName>"+bundleName.getSymbolicName()+"</symbolicName>",
+                "<version>"+bundleName.getVersionString()+"</version>",
+                "<url>http://example.org/brooklyn/"+bundleName.getSymbolicName()+"/"+bundleName.getVersionString()+"</url>",
+                "</managedBundle>");
     }
     
     protected String createLegacyPersistenceCatalogItem(VersionedName itemName) {
@@ -293,4 +283,73 @@ public abstract class AbstractBrooklynLauncherRebindTest {
         }
         return result.toString();
     }
+    
+    public PersistedStateInitializer newPersistedStateInitializer() {
+        return new PersistedStateInitializer();
+    }
+    
+    public class PersistedStateInitializer {
+        private final Map<String, String> legacyCatalogContents = new LinkedHashMap<>();
+        private final Map<VersionedName, File> bundles = new LinkedHashMap<>();
+
+        public PersistedStateInitializer legacyCatalogItems(Map<String, String> vals)
throws Exception {
+            legacyCatalogContents.putAll(vals);
+            return this;
+        }
+        
+        public PersistedStateInitializer bundle(VersionedName bundleName, File file) throws
Exception {
+            bundles.put(bundleName, file);
+            return this;
+        }
+        
+        public PersistedStateInitializer bundles(Map<VersionedName, File> vals) throws
Exception {
+            bundles.putAll(vals);
+            return this;
+        }
+        
+        public void initState() throws Exception {
+            initEmptyState();
+            
+            for (Map.Entry<String, String> entry : legacyCatalogContents.entrySet())
{
+                addMemento(BrooklynObjectType.CATALOG_ITEM, entry.getKey(), entry.getValue().getBytes(StandardCharsets.UTF_8));
+            }
+            for (Map.Entry<VersionedName, File> entry : bundles.entrySet()) {
+                VersionedName bundleName = entry.getKey();
+                String randomId = Identifiers.makeRandomId(8);
+                String managedBundleXml = createPersistenceManagedBundle(randomId, bundleName);
+                addMemento(BrooklynObjectType.MANAGED_BUNDLE, randomId, managedBundleXml.getBytes(StandardCharsets.UTF_8));
+                addMemento(BrooklynObjectType.MANAGED_BUNDLE, randomId+".jar", Streams.readFullyAndClose(new
FileInputStream(entry.getValue())));
+            }
+        }
+
+        private void addMemento(BrooklynObjectType type, String id, byte[] contents) throws
Exception {
+            File persistedFile = getPersistanceFile(type, id);
+            Files.createParentDirs(persistedFile);
+            Files.write(contents, persistedFile);
+        }
+
+        private File getPersistanceFile(BrooklynObjectType type, String id) {
+            String dir;
+            switch (type) {
+                case ENTITY: dir = "entities"; break;
+                case LOCATION: dir = "locations"; break;
+                case POLICY: dir = "policies"; break;
+                case ENRICHER: dir = "enrichers"; break;
+                case FEED: dir = "feeds"; break;
+                case CATALOG_ITEM: dir = "catalog"; break;
+                case MANAGED_BUNDLE: dir = "bundles"; break;
+                default: throw new UnsupportedOperationException("type="+type);
+            }
+            return new File(persistenceDir, Os.mergePaths(dir, id));
+        }
+        
+        private void initEmptyState() {
+            CatalogInitialization catalogInitialization = new CatalogInitialization(CATALOG_EMPTY_INITIAL);
+            BrooklynLauncher launcher = newLauncherForTests()
+                    .catalogInitialization(catalogInitialization);
+            launcher.start();
+            assertCatalogConsistsOfIds(launcher, ImmutableList.of());
+            launcher.terminate();
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/dba226fc/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
----------------------------------------------------------------------
diff --git a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
index 1922d72..8ef3466 100644
--- a/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
+++ b/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherUpgradeCatalogOsgiTest.java
@@ -18,13 +18,16 @@
  */
 package org.apache.brooklyn.launcher;
 
+import static org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.CATALOG_BOM;
+import static org.apache.brooklyn.core.catalog.internal.BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_BUNDLES;
+import static org.apache.brooklyn.core.catalog.internal.BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS;
+
 import java.io.File;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
-import org.apache.brooklyn.core.catalog.internal.BundleUpgradeParser;
 import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
 import org.apache.brooklyn.util.osgi.VersionedName;
 import org.testng.annotations.BeforeMethod;
@@ -67,20 +70,21 @@ public class BrooklynLauncherUpgradeCatalogOsgiTest extends AbstractBrooklynLaun
         VersionedName three_0_2_0 = VersionedName.fromString("three:0.2.0");
         VersionedName four_0_1_0 = VersionedName.fromString("four:0.1.0");
         
-        initPersistedState(ImmutableMap.<String, String>builder()
-                .put("one_0.1.0", createLegacyPersistenceCatalogItem(one_0_1_0))
-                .put("two_0.1.0", createLegacyPersistenceCatalogItem(two_0_1_0))
-                .put("two_1.0.0", createLegacyPersistenceCatalogItem(two_1_0_0))
-                .put("three_0.1.0", createLegacyPersistenceCatalogItem(three_0_1_0))
-                .put("three_0.2.0", createLegacyPersistenceCatalogItem(three_0_2_0))
-                .put("four_0.1.0", createLegacyPersistenceCatalogItem(four_0_1_0))
-                .build());
+        newPersistedStateInitializer()
+                .legacyCatalogItems(ImmutableMap.<String, String>builder()
+                    .put("one_0.1.0", createLegacyPersistenceCatalogItem(one_0_1_0))
+                    .put("two_0.1.0", createLegacyPersistenceCatalogItem(two_0_1_0))
+                    .put("two_1.0.0", createLegacyPersistenceCatalogItem(two_1_0_0))
+                    .put("three_0.1.0", createLegacyPersistenceCatalogItem(three_0_1_0))
+                    .put("three_0.2.0", createLegacyPersistenceCatalogItem(three_0_2_0))
+                    .put("four_0.1.0", createLegacyPersistenceCatalogItem(four_0_1_0))
+                    .build())
+                .initState();
         
         String bundleBom = createCatalogYaml(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of());
         VersionedName bundleName = new VersionedName("org.example.testRemoveLegacyItems",
"1.0.0");
-        String removedLegacyItems = "\"one:[0,1.0.0)\",\"two:[0,1.0.0)\",\"three:0.1.0\"";
-        Map<String, String> bundleManifest = ImmutableMap.of(BundleUpgradeParser.MANIFEST_HEADER_REMOVE_LEGACY_ITEMS,
removedLegacyItems);
-        File bundleFile = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM,
bundleBom.getBytes(StandardCharsets.UTF_8)), bundleName, bundleManifest);
+        Map<String, String> bundleManifest = ImmutableMap.of(MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS,
"\"one:[0,1.0.0)\",\"two:[0,1.0.0)\",\"three:0.1.0\"");
+        File bundleFile = newTmpBundle(ImmutableMap.of(CATALOG_BOM, bundleBom.getBytes(StandardCharsets.UTF_8)),
bundleName, bundleManifest);
         File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile.toURI()),
ImmutableList.of()));
         
         BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath());
@@ -90,4 +94,54 @@ public class BrooklynLauncherUpgradeCatalogOsgiTest extends AbstractBrooklynLaun
 
         launcher.terminate();
     }
+    
+    @Test
+    public void testForceUpgradeBundle() throws Exception {
+        VersionedName one_1_0_0 = VersionedName.fromString("one:1.0.0");
+        VersionedName one_2_0_0 = VersionedName.fromString("one:2.0.0");
+        
+        String bundleSymbolicName = "org.example.testForceUpgradeBundle";
+        VersionedName bundleVersionedName1 = new VersionedName(bundleSymbolicName, "1.0.0");
+        String bundleBom1 = createCatalogYaml(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_1_0_0));
+        File bundleFile1 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM,
bundleBom1.getBytes(StandardCharsets.UTF_8)), bundleVersionedName1);
+
+        newPersistedStateInitializer()
+                .bundle(bundleVersionedName1, bundleFile1)
+                .initState();
+        
+        VersionedName bundleVersionedName2 = new VersionedName(bundleSymbolicName, "2.0.0");
+        String bundleBom2 = createCatalogYaml(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_2_0_0));
+        Map<String, String> bundleManifest2 = ImmutableMap.of(MANIFEST_HEADER_FORCE_REMOVE_BUNDLES,
"\""+bundleSymbolicName+":[0.0.0,2.0.0)\"");
+        File bundleFile2 = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM,
bundleBom2.getBytes(StandardCharsets.UTF_8)), bundleVersionedName2, bundleManifest2);
+
+        File initialBomFile = newTmpFile(createCatalogYaml(ImmutableList.of(bundleFile2.toURI()),
ImmutableList.of()));
+
+        BrooklynLauncher launcher = newLauncherForTests(initialBomFile.getAbsolutePath());
+        launcher.start();
+        assertCatalogConsistsOfIds(launcher, ImmutableList.of(one_2_0_0));
+        assertManagedBundle(launcher, bundleVersionedName2, ImmutableSet.<VersionedName>of(one_2_0_0));
+        assertNotManagedBundle(launcher, bundleVersionedName1);
+        launcher.terminate();
+    }
+    
+    // Simple test (no upgrade), important for validating that other tests really do as expected!
+    @Test
+    public void testLoadsBundleFromPersistedState() throws Exception {
+        VersionedName one_1_0_0 = VersionedName.fromString("one:1.0.0");
+        
+        String bundleSymbolicName = "org.example.testForceUpgradeBundle";
+        VersionedName bundleVersionedName = new VersionedName(bundleSymbolicName, "1.0.0");
+        String bundleBom = createCatalogYaml(ImmutableList.<URI>of(), ImmutableSet.<VersionedName>of(one_1_0_0));
+        File bundleFile = newTmpBundle(ImmutableMap.of(BasicBrooklynCatalog.CATALOG_BOM,
bundleBom.getBytes(StandardCharsets.UTF_8)), bundleVersionedName);
+
+        newPersistedStateInitializer()
+                .bundle(bundleVersionedName, bundleFile)
+                .initState();
+        
+        BrooklynLauncher launcher = newLauncherForTests(CATALOG_EMPTY_INITIAL);
+        launcher.start();
+        assertCatalogConsistsOfIds(launcher, ImmutableList.of(one_1_0_0));
+        assertManagedBundle(launcher, bundleVersionedName, ImmutableSet.<VersionedName>of(one_1_0_0));
+        launcher.terminate();
+    }
 }


Mime
View raw message