Add checksum to managed bundle so we can tell if it changes and fail accordingly
This permits us to allow the same BOM YAML to be added multiple times (whether or not bundles are declared), except where it's a non-snapshot BOM that doesn't declare a bundle, because the containing bundle will be different there. This also fixes a bug where containingBundle wasn't persisted; not a big problem as we re-read bundle items, but cleaner to have it working. Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/e7dc875a Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/e7dc875a Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/e7dc875a Branch: refs/heads/master Commit: e7dc875af19138261f95994c5da08a2187ee64c7 Parents: 2165778 Author: Alex Heneveld <[email protected]> Authored: Tue Jun 27 15:38:15 2017 +0100 Committer: Alex Heneveld <[email protected]> Committed: Tue Jun 27 15:39:28 2017 +0100 ---------------------------------------------------------------------- .../rebind/mementos/CatalogItemMemento.java | 2 ++ .../brooklyn/api/typereg/ManagedBundle.java | 6 +++- .../CatalogOsgiVersionMoreEntityRebindTest.java | 32 +++++++++++++---- .../catalog/CatalogOsgiYamlEntityTest.java | 13 ++++--- .../catalog/internal/BasicBrooklynCatalog.java | 6 ++-- .../core/mgmt/ha/OsgiArchiveInstaller.java | 8 +++++ .../mgmt/ha/OsgiBundleInstallationResult.java | 1 - .../brooklyn/core/mgmt/ha/OsgiManager.java | 2 ++ .../rebind/BasicCatalogItemRebindSupport.java | 1 + .../rebind/dto/BasicCatalogItemMemento.java | 14 ++++++++ .../mgmt/rebind/dto/MementosGenerators.java | 2 ++ .../core/typereg/BasicManagedBundle.java | 16 ++++++++- .../main/resources/brooklyn/empty.catalog.bom | 4 ++- .../apache/brooklyn/util/stream/Streams.java | 21 ++++++++++++ .../brooklyn/util/stream/StreamsTest.java | 36 ++++++++++++++++++++ .../TestResourceUnavailableException.java | 6 ++-- 16 files changed, 149 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java index 0ab7bc8..11b301a 100644 --- a/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java +++ b/api/src/main/java/org/apache/brooklyn/api/mgmt/rebind/mementos/CatalogItemMemento.java @@ -30,6 +30,8 @@ public interface CatalogItemMemento extends Memento { String getSymbolicName(); + String getContainingBundle(); + String getIconUrl(); String getVersion(); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java b/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java index 66ca592..49f5d7f 100644 --- a/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java +++ b/api/src/main/java/org/apache/brooklyn/api/typereg/ManagedBundle.java @@ -27,9 +27,13 @@ public interface ManagedBundle extends BrooklynObject, Rebindable, OsgiBundleWit /** A URL-like thing that we can register with the OSGi framework * to uniquely identify this bundle-instance. - * This typically includes the unique {@link #getId()} of this item. */ + * This typically includes the unique {@link #getId()} of this item. + * This will not normally be a URL that can be loaded. */ String getOsgiUniqueUrl(); VersionedName getVersionedName(); + /** MD5 checksum of the contents of bundle as installed to OSGi */ + String getChecksum(); + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityRebindTest.java ---------------------------------------------------------------------- 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 b881ec7..54c1efa 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 @@ -50,6 +50,7 @@ import org.apache.brooklyn.util.core.ClassLoaderUtils; import org.apache.brooklyn.util.core.ResourceUtils; import org.apache.brooklyn.util.javalang.Reflections; import org.apache.brooklyn.util.osgi.OsgiTestResources; +import org.apache.brooklyn.util.osgi.VersionedName; import org.apache.brooklyn.util.text.Strings; import org.osgi.framework.Bundle; import org.slf4j.Logger; @@ -72,24 +73,41 @@ public class CatalogOsgiVersionMoreEntityRebindTest extends AbstractYamlRebindTe protected boolean useOsgi() { return true; } - + @Test - public void testRebindAppIncludingBundle() throws Exception { - TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_COM_EXAMPLE_PATH); + public void testRebindAppIncludingBundleAllWorksAndPreservesChecksum() throws Exception { + TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V1_PATH); ((ManagementContextInternal)mgmt()).getOsgiManager().get().install( new ResourceUtils(getClass()).getResourceFromUrl(BROOKLYN_TEST_MORE_ENTITIES_V1_URL) ); + RegisteredType item = mgmt().getTypeRegistry().get(BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY); + Assert.assertNotNull(item); + Assert.assertEquals(item.getContainingBundle(), OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL+":"+"0.1.0"); + + ManagedBundle mb = ((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundle(VersionedName.fromString(item.getContainingBundle())); + Assert.assertNotNull(mb); + String c1 = mb.getChecksum(); + Assert.assertTrue(Strings.isNonBlank(c1), "Missing checksum for bundle"); + + Map<String, ManagedBundle> bundles1 = ((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundles(); + createAndStartApplication("services: [ { type: "+BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY+" } ]"); StartableApplication newApp = rebind(); // bundles installed Map<String, ManagedBundle> bundles = ((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundles(); - Asserts.assertSize(bundles.keySet(), 1); + Asserts.assertEquals(bundles, bundles1); + + //item installed + item = mgmt().getTypeRegistry().get(BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY); + Assert.assertNotNull(item); + Assert.assertEquals(item.getContainingBundle(), OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL+":"+"0.1.0"); - // types installed - RegisteredType t = mgmt().getTypeRegistry().get("org.apache.brooklyn.test.osgi.entities.more.MoreEntity"); - Assert.assertNotNull(t); + // containing bundle set, matches, and checksum matches + mb = ((ManagementContextInternal)mgmt()).getOsgiManager().get().getManagedBundle(VersionedName.fromString(item.getContainingBundle())); + Assert.assertEquals(mb, bundles.get(mb.getId())); + Assert.assertEquals(mb.getChecksum(), c1, "checksums should be the same after rebinding"); Assert.assertNotNull(newApp); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java index a1bd800..6d7df19 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiYamlEntityTest.java @@ -236,7 +236,7 @@ public class CatalogOsgiYamlEntityTest extends AbstractYamlTest { try { addCatalogItems( "brooklyn.catalog:", - " id: my.catalog.app.id.non_existing.ref", + " id: my.catalog.app.id.non_existing.ref.1", " version: " + TEST_VERSION, " itemType: entity", " libraries:", @@ -250,7 +250,7 @@ public class CatalogOsgiYamlEntityTest extends AbstractYamlTest { try { addCatalogItems( "brooklyn.catalog:", - " id: my.catalog.app.id.non_existing.ref", + " id: my.catalog.app.id.non_existing.ref.2", " version: " + TEST_VERSION, " itemType: entity", " libraries:", @@ -323,13 +323,18 @@ public class CatalogOsgiYamlEntityTest extends AbstractYamlTest { addCatalogOSGiEntity(id); } - @Test(expectedExceptions = IllegalStateException.class) + @Test public void testUpdatingItemFailsIfDifferent() { TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH); String id = "my.catalog.app.id.duplicate"; addCatalogOSGiEntity(id); - addCatalogOSGiEntity(id, SIMPLE_ENTITY_TYPE, true); + try { + addCatalogOSGiEntity(id, SIMPLE_ENTITY_TYPE, true); + Asserts.shouldHaveFailedPreviously(); + } catch (Exception e) { + Asserts.expectedFailureContainsIgnoreCase(e, id, "already installed", "cannot install a different bundle at a same non-snapshot version"); + } } @Test http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java ---------------------------------------------------------------------- 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 c0e2e07..9d40e2f 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 @@ -1173,7 +1173,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog { public List<? extends CatalogItem<?,?>> addItems(String yaml, boolean forceUpdate) { Maybe<OsgiManager> osgiManager = ((ManagementContextInternal)mgmt).getOsgiManager(); if (osgiManager.isPresent() && AUTO_WRAP_CATALOG_YAML_AS_BUNDLE) { - // TODO wrap in a bundle to be managed; need to get bundle and version from yaml + // wrap in a bundle to be managed; need to get bundle and version from yaml Map<?, ?> cm = BasicBrooklynCatalog.getCatalogMetadata(yaml); VersionedName vn = BasicBrooklynCatalog.getVersionedName( cm, false ); if (vn==null) { @@ -1202,9 +1202,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog { throw Exceptions.propagate(e); } bf.delete(); - if (result.getCode().isError() || result.getCode()==ResultCode.IGNORING_BUNDLE_AREADY_INSTALLED) { - // if we're wrapping YAML then we don't allow equivalent YAML to be pasted - // TODO remove this once we have better bundle equivalence checks + if (result.getCode().isError()) { throw new IllegalStateException(result.getMessage()); } return toItems(result.getCatalogItemsInstalled()); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java index 9ef04c8..d15a036 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiArchiveInstaller.java @@ -271,6 +271,8 @@ class OsgiArchiveInstaller { updateManifestFromAllSourceInformation(); if (result.code!=null) return ReferenceWithError.newInstanceWithoutError(result); assert inferredMetadata.isNameResolved() : "Should have resolved "+inferredMetadata; + assert inferredMetadata instanceof BasicManagedBundle : "Only BasicManagedBundles supported"; + ((BasicManagedBundle)inferredMetadata).setChecksum(Streams.getMd5Checksum(new FileInputStream(zipFile))); final boolean updating; result.metadata = osgiManager.getManagedBundle(inferredMetadata.getVersionedName()); @@ -296,6 +298,12 @@ class OsgiArchiveInstaller { } updating = true; } else { + if (result.getMetadata().getChecksum()==null || inferredMetadata.getChecksum()==null) { + log.warn("Missing bundle checksum data for "+result+"; assuming bundle replacement is permitted"); + } else if (!Objects.equal(result.getMetadata().getChecksum(), inferredMetadata.getChecksum())) { + throw new IllegalArgumentException("Bundle "+result.getMetadata().getVersionedName()+" already installed; " + + "cannot install a different bundle at a same non-snapshot version"); + } result.setIgnoringAlreadyInstalled(); return ReferenceWithError.newInstanceWithoutError(result); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiBundleInstallationResult.java ---------------------------------------------------------------------- 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 9e845ad..e0e7456 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 @@ -39,7 +39,6 @@ public class OsgiBundleInstallationResult { public enum ResultCode { INSTALLED_NEW_BUNDLE(false), UPDATED_EXISTING_BUNDLE(false), - // TODO if bundle installed is different to bundle supplied we should flag an error IGNORING_BUNDLE_AREADY_INSTALLED(false), ERROR_PREPARING_BUNDLE(true), ERROR_INSTALLING_BUNDLE(true); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java index dcabe00..34a5d0b 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 @@ -251,10 +251,12 @@ public class OsgiManager { framework = null; } + /** Map of bundles by UID */ public Map<String, ManagedBundle> getManagedBundles() { return managedBundlesRecord.getManagedBundles(); } + /** Gets UID given a name, or null */ public String getManagedBundleId(VersionedName vn) { return managedBundlesRecord.getManagedBundleId(vn); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicCatalogItemRebindSupport.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicCatalogItemRebindSupport.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicCatalogItemRebindSupport.java index 614b085..8cea7b2 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicCatalogItemRebindSupport.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/BasicCatalogItemRebindSupport.java @@ -43,6 +43,7 @@ public class BasicCatalogItemRebindSupport extends AbstractBrooklynObjectRebindS super.reconstruct(rebindContext, memento); FlagUtils.setFieldsFromFlags(MutableMap.builder() .put("symbolicName", memento.getSymbolicName()) + .put("containingBundle", memento.getContainingBundle()) .put("javaType", memento.getJavaType()) .put("displayName", memento.getDisplayName()) .put("description", memento.getDescription()) http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java index 33406a4..72447a7 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/BasicCatalogItemMemento.java @@ -47,6 +47,7 @@ public class BasicCatalogItemMemento extends AbstractMemento implements CatalogI public static class Builder extends AbstractMemento.Builder<Builder> { protected String description; protected String symbolicName; + protected String containingBundle; protected String iconUrl; protected String javaType; protected String version; @@ -69,6 +70,11 @@ public class BasicCatalogItemMemento extends AbstractMemento implements CatalogI return self(); } + public Builder containingBundle(String containingBundle) { + this.containingBundle = containingBundle; + return self(); + } + public Builder iconUrl(String iconUrl) { this.iconUrl = iconUrl; return self(); @@ -128,6 +134,7 @@ public class BasicCatalogItemMemento extends AbstractMemento implements CatalogI super.from(other); description = other.getDescription(); symbolicName = other.getSymbolicName(); + containingBundle = other.getContainingBundle(); iconUrl = other.getIconUrl(); javaType = other.getJavaType(); version = other.getVersion(); @@ -149,6 +156,7 @@ public class BasicCatalogItemMemento extends AbstractMemento implements CatalogI private String description; private String symbolicName; + private String containingBundle; private String iconUrl; private String javaType; private String version; @@ -168,6 +176,7 @@ public class BasicCatalogItemMemento extends AbstractMemento implements CatalogI super(builder); this.description = builder.description; this.symbolicName = builder.symbolicName; + this.containingBundle = builder.containingBundle; this.iconUrl = builder.iconUrl; this.version = builder.version; this.planYaml = builder.planYaml; @@ -197,6 +206,11 @@ public class BasicCatalogItemMemento extends AbstractMemento implements CatalogI } @Override + public String getContainingBundle() { + return containingBundle; + } + + @Override public String getIconUrl() { return iconUrl; } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java index 20179bc..e3969cb 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/rebind/dto/MementosGenerators.java @@ -323,6 +323,7 @@ public class MementosGenerators { return builder.build(); } + @SuppressWarnings("deprecation") private static CatalogItemMemento newCatalogItemMemento(CatalogItem<?, ?> catalogItem) { if (catalogItem instanceof CatalogItemDo<?,?>) { catalogItem = ((CatalogItemDo<?,?>)catalogItem).getDto(); @@ -331,6 +332,7 @@ public class MementosGenerators { populateBrooklynObjectMementoBuilder(catalogItem, builder); builder.catalogItemJavaType(catalogItem.getCatalogItemJavaType()) .catalogItemType(catalogItem.getCatalogItemType()) + .containingBundle(catalogItem.getContainingBundle()) .description(catalogItem.getDescription()) .iconUrl(catalogItem.getIconUrl()) .javaType(catalogItem.getJavaType()) http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/core/src/main/java/org/apache/brooklyn/core/typereg/BasicManagedBundle.java ---------------------------------------------------------------------- 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 d480ed5..1cf4e84 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 @@ -31,7 +31,6 @@ import org.apache.brooklyn.core.objs.AbstractBrooklynObject; import org.apache.brooklyn.core.objs.BrooklynObjectInternal; import org.apache.brooklyn.util.osgi.VersionedName; import org.apache.brooklyn.util.text.BrooklynVersionSyntax; -import org.osgi.framework.Version; import com.google.common.annotations.Beta; import com.google.common.base.MoreObjects; @@ -42,6 +41,7 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage private String symbolicName; private String version; + private String checksum; private String url; private transient File localFileWhenJustUploaded; @@ -129,6 +129,7 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage @Override public int hashCode() { + // checksum deliberately omitted here to match with OsgiBundleWithUrl return Objects.hashCode(symbolicName, version, url); } @@ -141,6 +142,11 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage if (!Objects.equal(symbolicName, other.getSymbolicName())) return false; if (!Objects.equal(getOsgiVersionString(), other.getOsgiVersionString())) return false; if (!Objects.equal(url, other.getUrl())) return false; + if (other instanceof BasicManagedBundle) { + // make equality symetricm, OsgiBunde equals this iff this equals OsgiBundle; + // checksum compared if available, but not required + if (!Objects.equal(checksum, ((BasicManagedBundle)other).getChecksum())) return false; + } return true; } @@ -180,6 +186,14 @@ public class BasicManagedBundle extends AbstractBrooklynObject implements Manage public void setDisplayName(String newName) { throw new UnsupportedOperationException(); } + + @Override + public String getChecksum() { + return checksum; + } + public void setChecksum(String md5Checksum) { + this.checksum = md5Checksum; + } @Override protected BrooklynObjectInternal configure(Map<?, ?> flags) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/core/src/main/resources/brooklyn/empty.catalog.bom ---------------------------------------------------------------------- diff --git a/core/src/main/resources/brooklyn/empty.catalog.bom b/core/src/main/resources/brooklyn/empty.catalog.bom index 58cfb1b..a256754 100644 --- a/core/src/main/resources/brooklyn/empty.catalog.bom +++ b/core/src/main/resources/brooklyn/empty.catalog.bom @@ -15,4 +15,6 @@ # specific language governing permissions and limitations # under the License. # -brooklyn.catalog: {} \ No newline at end of file +brooklyn.catalog: + bundle: brooklyn-empty-catalog + version: 0.0.0-SNAPSHOT http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java b/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java index 0f34357..a703dba 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/stream/Streams.java @@ -30,6 +30,9 @@ import java.io.Reader; import java.io.StringReader; import java.io.Writer; import java.nio.charset.Charset; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import org.apache.brooklyn.util.exceptions.Exceptions; import org.slf4j.Logger; @@ -39,6 +42,7 @@ import com.google.common.annotations.Beta; import com.google.common.base.Charsets; import com.google.common.base.Function; import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import com.google.common.base.Supplier; import com.google.common.io.ByteStreams; import com.google.common.io.CharStreams; @@ -215,4 +219,21 @@ public class Streams { return false; } + public static String getMd5Checksum(InputStream in) { + MessageDigest md; + try { + md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw Exceptions.propagate(e); + } + DigestInputStream dis = new DigestInputStream(in, md); + readFullyAndClose(dis); + byte[] digest = md.digest(); + StringBuilder result = new StringBuilder(); + for (byte b: digest) { + result.append(Strings.padStart(Integer.toHexString((256+b)%256), 2, '0')); + } + return result.toString().toUpperCase(); + } + } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/utils/common/src/test/java/org/apache/brooklyn/util/stream/StreamsTest.java ---------------------------------------------------------------------- diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/stream/StreamsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/stream/StreamsTest.java new file mode 100644 index 0000000..37340f4 --- /dev/null +++ b/utils/common/src/test/java/org/apache/brooklyn/util/stream/StreamsTest.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.util.stream; + +import java.io.ByteArrayInputStream; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class StreamsTest { + + @Test + public void testChecksum() { + Assert.assertEquals(Streams.getMd5Checksum(new ByteArrayInputStream("hello world".getBytes())), + // generated from 3rd party tool + "5EB63BBBE01EEED093CB22BB8F5ACDC3" + ); + + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/e7dc875a/utils/test-support/src/main/java/org/apache/brooklyn/test/support/TestResourceUnavailableException.java ---------------------------------------------------------------------- diff --git a/utils/test-support/src/main/java/org/apache/brooklyn/test/support/TestResourceUnavailableException.java b/utils/test-support/src/main/java/org/apache/brooklyn/test/support/TestResourceUnavailableException.java index cb4205f..34c3de3 100644 --- a/utils/test-support/src/main/java/org/apache/brooklyn/test/support/TestResourceUnavailableException.java +++ b/utils/test-support/src/main/java/org/apache/brooklyn/test/support/TestResourceUnavailableException.java @@ -53,7 +53,7 @@ public class TestResourceUnavailableException extends SkipException { * * Note that this will use the same classloader that was used to load this class. * - * @param resourceName the classpath resource name, e.g. + * @param resourceName the classpath resource name, as a path, e.g. * <code>/brooklyn/osgi/brooklyn-test-osgi-entities.jar</code> */ public static void throwIfResourceUnavailable(Class<?> relativeToClass, String resourceName) { @@ -61,8 +61,10 @@ public class TestResourceUnavailableException extends SkipException { checkNotNull(resourceName, "resourceName"); checkArgument(!resourceName.isEmpty(), "resourceName must not be empty"); InputStream resource = relativeToClass.getResourceAsStream(resourceName); - if (resource == null) + if (resource == null) { + // would be nice to support URLs but ResourceUtils isn't available here throw new TestResourceUnavailableException(resourceName); + } // just make sure we clean up the resource try {
