Catalog versioning - Reference installed OSGi bundles by name+version Also fix failing tests from previous commits.
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/268aaf6b Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/268aaf6b Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/268aaf6b Branch: refs/heads/master Commit: 268aaf6bc85bcdf04496ca17d3aaa3a8b199dc37 Parents: 1e88783 Author: Svetoslav Neykov <svetoslav.ney...@cloudsoftcorp.com> Authored: Mon Jul 21 19:08:02 2014 +0300 Committer: Svetoslav Neykov <svetoslav.ney...@cloudsoftcorp.com> Committed: Thu Nov 13 11:49:49 2014 +0200 ---------------------------------------------------------------------- .../main/java/brooklyn/catalog/CatalogItem.java | 13 +- .../catalog/internal/CatalogBundleDto.java | 66 ++++++++ .../catalog/internal/CatalogLibrariesDo.java | 5 +- .../catalog/internal/CatalogLibrariesDto.java | 62 ++++++-- .../brooklyn/catalog/internal/CatalogUtils.java | 17 +- .../catalog/internal/CatalogXmlSerializer.java | 6 +- .../OsgiBrooklynClassLoadingContext.java | 8 +- .../brooklyn/management/ha/OsgiManager.java | 131 ++++++++++------ .../src/main/java/brooklyn/util/osgi/Osgis.java | 65 ++++++-- .../brooklyn/camp/lite/CampYamlLiteTest.java | 19 ++- .../catalog/internal/CatalogDtoTest.java | 15 +- .../catalog/internal/CatalogLoadTest.java | 21 ++- .../management/osgi/OsgiStandaloneTest.java | 2 + .../camp/lite/test-app-service-blueprint.yaml | 2 +- .../brooklyn/catalog/internal/osgi-catalog.xml | 4 +- .../camp/brooklyn/AbstractYamlTest.java | 6 +- .../camp/brooklyn/ReferencedYamlTest.java | 7 +- .../CatalogOsgiVersionMoreEntityTest.java | 14 +- .../brooklyn/catalog/CatalogYamlEntityTest.java | 157 +++++++++++++++++-- .../brooklyn/catalog/CatalogYamlPolicyTest.java | 8 +- ...more-entity-v1-with-policy-osgi-catalog.yaml | 2 +- .../catalog/more-entity-v2-osgi-catalog.yaml | 2 +- usage/camp/src/test/resources/yaml-ref-app.yaml | 2 +- .../src/test/resources/yaml-ref-catalog.yaml | 2 +- .../src/test/resources/yaml-ref-entity.yaml | 2 +- .../rest/resources/CatalogResourceTest.java | 18 ++- 26 files changed, 510 insertions(+), 146 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/api/src/main/java/brooklyn/catalog/CatalogItem.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/brooklyn/catalog/CatalogItem.java b/api/src/main/java/brooklyn/catalog/CatalogItem.java index 409bd7e..1f67ccd 100644 --- a/api/src/main/java/brooklyn/catalog/CatalogItem.java +++ b/api/src/main/java/brooklyn/catalog/CatalogItem.java @@ -18,7 +18,7 @@ */ package brooklyn.catalog; -import java.util.List; +import java.util.Collection; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -36,10 +36,19 @@ public interface CatalogItem<T,SpecT> extends BrooklynObject, Rebindable { public static enum CatalogItemType { TEMPLATE, ENTITY, POLICY, CONFIGURATION } + + public static interface CatalogBundle { + public String getName(); + public String getVersion(); + public String getUrl(); + + /** @return true if the bundle reference contains both name and version*/ + public boolean isNamed(); + } @Beta public static interface CatalogItemLibraries { - List<String> getBundles(); + Collection<CatalogBundle> getBundles(); } public CatalogItemType getCatalogItemType(); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/main/java/brooklyn/catalog/internal/CatalogBundleDto.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogBundleDto.java b/core/src/main/java/brooklyn/catalog/internal/CatalogBundleDto.java new file mode 100644 index 0000000..6ef148e --- /dev/null +++ b/core/src/main/java/brooklyn/catalog/internal/CatalogBundleDto.java @@ -0,0 +1,66 @@ +/* + * 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 brooklyn.catalog.internal; + +import com.google.common.base.Objects; + +import brooklyn.catalog.CatalogItem.CatalogBundle; + +public class CatalogBundleDto implements CatalogBundle { + private String name; + private String version; + private String url; + + public CatalogBundleDto() {} + + public CatalogBundleDto(String name, String version, String url) { + this.name = name; + this.version = version; + this.url = url; + } + + @Override + public boolean isNamed() { + return name != null && version != null; + } + + @Override + public String getName() { + return name; + } + + @Override + public String getVersion() { + return version; + } + + @Override + public String getUrl() { + return url; + } + + @Override + public String toString() { + return Objects.toStringHelper(this) + .add("name", name) + .add("version", version) + .add("url", url) + .toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDo.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDo.java b/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDo.java index fb461f3..fa5f478 100644 --- a/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDo.java +++ b/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDo.java @@ -18,9 +18,10 @@ */ package brooklyn.catalog.internal; -import java.util.List; +import java.util.Collection; import brooklyn.catalog.CatalogItem; +import brooklyn.catalog.CatalogItem.CatalogBundle; import com.google.common.base.Preconditions; @@ -34,7 +35,7 @@ public class CatalogLibrariesDo implements CatalogItem.CatalogItemLibraries { } @Override - public List<String> getBundles() { + public Collection<CatalogBundle> getBundles() { return librariesDto.getBundles(); } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java b/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java index bcbd25b..646d69c 100644 --- a/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java +++ b/core/src/main/java/brooklyn/catalog/internal/CatalogLibrariesDto.java @@ -20,34 +20,41 @@ package brooklyn.catalog.internal; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import brooklyn.catalog.CatalogItem; +import brooklyn.catalog.CatalogItem.CatalogBundle; + import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import brooklyn.catalog.CatalogItem; - public class CatalogLibrariesDto implements CatalogItem.CatalogItemLibraries { private static Logger LOG = LoggerFactory.getLogger(CatalogLibrariesDto.class); - // TODO: Incorporate name and version into entries - private List<String> bundles = new CopyOnWriteArrayList<String>(); + private Collection<CatalogBundle> bundles = new CopyOnWriteArrayList<CatalogBundle>(); - public void addBundle(String url) { + public void addBundle(String name, String version, String url) { Preconditions.checkNotNull(bundles, "Cannot add a bundle to a deserialized DTO"); - bundles.add(Preconditions.checkNotNull(url, "url")); + if (name == null && version == null) { + Preconditions.checkNotNull(url, "url"); + } else { + Preconditions.checkNotNull(name, "name"); + Preconditions.checkNotNull(version, "version"); + } + + bundles.add(new CatalogBundleDto(name, version, url)); } /** * @return An immutable copy of the bundle URLs referenced by this object */ - public List<String> getBundles() { + @Override + public Collection<CatalogBundle> getBundles() { if (bundles == null) { // can be null on deserialization return Collections.emptyList(); @@ -63,15 +70,37 @@ public class CatalogLibrariesDto implements CatalogItem.CatalogItemLibraries { CatalogLibrariesDto dto = new CatalogLibrariesDto(); for (Object object : possibleLibraries) { if (object instanceof Map) { - @SuppressWarnings("rawtypes") - Map entry = (Map) object; - // these might be useful in the future -// String name = stringValOrNull(entry, "name"); -// String version = stringValOrNull(entry, "version"); + Map<?, ?> entry = (Map<?, ?>) object; + String name = stringValOrNull(entry, "name"); + String version = stringValOrNull(entry, "version"); String url = stringValOrNull(entry, "url"); - dto.addBundle(url); + dto.addBundle(name, version, url); } else if (object instanceof String) { - dto.addBundle((String) object); + String inlineRef = (String) object; + + final String name; + final String version; + final String url; + + //Infer reference type (heuristically) + if (inlineRef.contains("/") || inlineRef.contains("\\")) { + //looks like an url/file path + name = null; + version = null; + url = inlineRef; + } else if (inlineRef.indexOf(CatalogUtils.VERSION_DELIMITER) != -1) { + //looks like a name+version ref + name = CatalogUtils.getIdFromVersionedId(inlineRef); + version = CatalogUtils.getVersionFromVersionedId(inlineRef); + url = null; + } else { + //assume it to be relative url + name = null; + version = null; + url = inlineRef; + } + + dto.addBundle(name, version, url); } else { LOG.debug("Unexpected entry in libraries list neither string nor map: " + object); } @@ -79,8 +108,7 @@ public class CatalogLibrariesDto implements CatalogItem.CatalogItemLibraries { return dto; } - @SuppressWarnings("rawtypes") - private static String stringValOrNull(Map map, String key) { + private static String stringValOrNull(Map<?, ?> map, String key) { Object val = map.get(key); return val != null ? String.valueOf(val) : null; } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java b/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java index 6f33574..312351f 100644 --- a/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java +++ b/core/src/main/java/brooklyn/catalog/internal/CatalogUtils.java @@ -18,20 +18,17 @@ */ package brooklyn.catalog.internal; -import java.util.List; +import java.util.Collection; import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.annotations.Beta; -import com.google.common.base.Joiner; -import com.google.common.base.Stopwatch; - import brooklyn.basic.BrooklynObject; import brooklyn.basic.BrooklynObjectInternal; import brooklyn.catalog.CatalogItem; +import brooklyn.catalog.CatalogItem.CatalogBundle; import brooklyn.catalog.CatalogItem.CatalogItemLibraries; import brooklyn.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker; import brooklyn.config.BrooklynLogging; @@ -47,6 +44,10 @@ import brooklyn.management.internal.ManagementContextInternal; import brooklyn.util.guava.Maybe; import brooklyn.util.time.Time; +import com.google.common.annotations.Beta; +import com.google.common.base.Joiner; +import com.google.common.base.Stopwatch; + public class CatalogUtils { private static final Logger log = LoggerFactory.getLogger(CatalogUtils.class); @@ -66,7 +67,7 @@ public class CatalogUtils { BrooklynClassLoadingContextSequential result = new BrooklynClassLoadingContextSequential(mgmt); if (libraries!=null) { - List<String> bundles = libraries.getBundles(); + Collection<CatalogBundle> bundles = libraries.getBundles(); if (bundles!=null && !bundles.isEmpty()) { result.add(new OsgiBrooklynClassLoadingContext(mgmt, catalogItemId, bundles)); } @@ -88,7 +89,7 @@ public class CatalogUtils { if (libraries == null) return; ManagementContextInternal mgmt = (ManagementContextInternal) managementContext; - List<String> bundles = libraries.getBundles(); + Collection<CatalogBundle> bundles = libraries.getBundles(); if (!bundles.isEmpty()) { Maybe<OsgiManager> osgi = mgmt.getOsgiManager(); if (osgi.isAbsent()) { @@ -99,7 +100,7 @@ public class CatalogUtils { "Loading bundles in {}: {}", new Object[] {managementContext, Joiner.on(", ").join(bundles)}); Stopwatch timer = Stopwatch.createStarted(); - for (String bundleUrl : bundles) { + for (CatalogBundle bundleUrl : bundles) { osgi.get().registerBundle(bundleUrl); } if (log.isDebugEnabled()) http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/main/java/brooklyn/catalog/internal/CatalogXmlSerializer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/catalog/internal/CatalogXmlSerializer.java b/core/src/main/java/brooklyn/catalog/internal/CatalogXmlSerializer.java index ccac60b..0948149 100644 --- a/core/src/main/java/brooklyn/catalog/internal/CatalogXmlSerializer.java +++ b/core/src/main/java/brooklyn/catalog/internal/CatalogXmlSerializer.java @@ -18,6 +18,8 @@ */ package brooklyn.catalog.internal; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -29,6 +31,8 @@ import brooklyn.util.xstream.XmlSerializer; public class CatalogXmlSerializer extends XmlSerializer<Object> { public CatalogXmlSerializer() { + xstream.addDefaultImplementation(ArrayList.class, Collection.class); + xstream.aliasType("list", List.class); xstream.aliasType("map", Map.class); @@ -54,7 +58,7 @@ public class CatalogXmlSerializer extends XmlSerializer<Object> { xstream.registerConverter(new EnumCaseForgivingSingleValueConverter(CatalogScanningModes.class)); xstream.aliasType("libraries", CatalogLibrariesDto.class); - xstream.addImplicitCollection(CatalogLibrariesDto.class, "bundles", "bundle", String.class); + xstream.addImplicitCollection(CatalogLibrariesDto.class, "bundles", "bundle", CatalogBundleDto.class); // Note: the management context is being omitted because it is unnecessary for // representations of catalogues generated with this serializer. http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java b/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java index 74cc6cf..bb763d5 100644 --- a/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java +++ b/core/src/main/java/brooklyn/management/classloading/OsgiBrooklynClassLoadingContext.java @@ -19,22 +19,22 @@ package brooklyn.management.classloading; import java.net.URL; -import java.util.List; +import java.util.Collection; +import brooklyn.catalog.CatalogItem.CatalogBundle; import brooklyn.management.ManagementContext; import brooklyn.management.ha.OsgiManager; import brooklyn.management.internal.ManagementContextInternal; -import brooklyn.util.exceptions.Exceptions; import brooklyn.util.guava.Maybe; import com.google.common.base.Objects; public class OsgiBrooklynClassLoadingContext extends AbstractBrooklynClassLoadingContext { - private final List<String> bundles; + private final Collection<CatalogBundle> bundles; private final String catalogItemId; - public OsgiBrooklynClassLoadingContext(ManagementContext mgmt, String catalogItemId, List<String> bundles) { + public OsgiBrooklynClassLoadingContext(ManagementContext mgmt, String catalogItemId, Collection<CatalogBundle> bundles) { super(mgmt); this.bundles = bundles; this.catalogItemId = catalogItemId; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/main/java/brooklyn/management/ha/OsgiManager.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/management/ha/OsgiManager.java b/core/src/main/java/brooklyn/management/ha/OsgiManager.java index 44b30af..47b0225 100644 --- a/core/src/main/java/brooklyn/management/ha/OsgiManager.java +++ b/core/src/main/java/brooklyn/management/ha/OsgiManager.java @@ -30,6 +30,7 @@ import org.osgi.framework.launch.Framework; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import brooklyn.catalog.CatalogItem.CatalogBundle; import brooklyn.config.BrooklynServerConfig; import brooklyn.config.ConfigKey; import brooklyn.util.collections.MutableMap; @@ -38,6 +39,8 @@ import brooklyn.util.guava.Maybe; import brooklyn.util.os.Os; import brooklyn.util.os.Os.DeletionResult; import brooklyn.util.osgi.Osgis; +import brooklyn.util.osgi.Osgis.BundleFinder; +import brooklyn.util.osgi.Osgis.VersionedName; import com.google.common.base.Throwables; import com.google.common.collect.Iterables; @@ -52,10 +55,10 @@ public class OsgiManager { protected Framework framework; protected File osgiTempDir; - + // we could manage without this map but it is useful to validate what is a user-supplied url - protected Map<String,String> urlToBundleIdentifier = MutableMap.of(); - + protected Map<String,VersionedName> urlToBundleIdentifier = MutableMap.of(); + public void start() { try { // TODO any extra startup args? @@ -88,49 +91,83 @@ public class OsgiManager { framework = null; } - public void registerBundle(String bundleUrl) { + public synchronized void registerBundle(CatalogBundle bundle) { try { - String nv = urlToBundleIdentifier.get(bundleUrl); + if (checkBundleInstalledThrowIfInconsistent(bundle)) { + return; + } + + Bundle b = Osgis.install(framework, bundle.getUrl()); + + checkCorrectlyInstalled(bundle, b); + + urlToBundleIdentifier.put(bundle.getUrl(), new VersionedName(b)); + } catch (BundleException e) { + log.debug("Bundle from "+bundle+" failed to install (rethrowing): "+e); + throw Throwables.propagate(e); + } + } + + private void checkCorrectlyInstalled(CatalogBundle bundle, Bundle b) { + List<Bundle> matches = Osgis.bundleFinder(framework) + .symbolicName(b.getSymbolicName()) + .version(b.getVersion().toString()) + .findAll(); + String nv = b.getSymbolicName()+":"+b.getVersion().toString(); + if (matches.isEmpty()) { + log.error("OSGi could not find bundle "+nv+" in search after installing it from "+bundle.getUrl()); + } else if (matches.size()==1) { + log.debug("Bundle from "+bundle.getUrl()+" successfully installed as " + nv + " ("+b+")"); + } else { + log.warn("OSGi has multiple bundles matching "+nv+", when just installed from "+bundle.getUrl()+": "+matches+"; " + + "brooklyn will prefer the URL-based bundle for top-level references but any dependencies or " + + "import-packages will be at the mercy of OSGi. " + + "It is recommended to use distinct versions for different bundles, and the same URL for the same bundles."); + } + } + + private boolean checkBundleInstalledThrowIfInconsistent(CatalogBundle bundle) { + String bundleUrl = bundle.getUrl(); + if (bundleUrl != null) { + VersionedName nv = urlToBundleIdentifier.get(bundleUrl); if (nv!=null) { - if (Osgis.bundleFinder(framework).id(nv).requiringFromUrl(bundleUrl).find().isPresent()) { + if (bundle.isNamed() && !nv.equals(bundle.getName(), bundle.getVersion())) { + throw new IllegalStateException("Bundle from "+bundleUrl+" already installed as "+nv+" but user explicitly requested "+bundle); + } + Maybe<Bundle> installedBundle = Osgis.bundleFinder(framework).requiringFromUrl(bundleUrl).find(); + if (installedBundle.isPresent()) { + if (bundle.isNamed()) { + Bundle b = installedBundle.get(); + if (!nv.equals(b.getSymbolicName(), b.getVersion().toString())) { + log.error("Bundle from "+bundleUrl+" already installed as "+nv+" but reports "+b.getSymbolicName()+":"+b.getVersion()); + } + } log.trace("Bundle from "+bundleUrl+" already installed as "+nv+"; not re-registering"); - return; + return true; } else { - log.debug("Bundle "+nv+" from "+bundleUrl+" is known in map but not installed; perhaps in the process of installing?"); + log.error("Bundle "+nv+" from "+bundleUrl+" is known in map but not installed; perhaps in the process of installing?"); } } - - Bundle b = Osgis.install(framework, bundleUrl); - nv = b.getSymbolicName()+":"+b.getVersion().toString(); - - List<Bundle> matches = Osgis.bundleFinder(framework).id(nv).findAll(); - if (matches.isEmpty()) { - log.error("OSGi could not find bundle "+nv+" in search after installing it from "+bundleUrl); - } else if (matches.size()==1) { - log.debug("Bundle from "+bundleUrl+" successfully installed as " + nv + " ("+b+")"); + } else { + Maybe<Bundle> installedBundle = Osgis.bundleFinder(framework).symbolicName(bundle.getName()).version(bundle.getVersion()).find(); + if (installedBundle.isPresent()) { + log.trace("Bundle "+bundle+" installed from "+installedBundle.get().getLocation()); } else { - log.warn("OSGi has multiple bundles matching "+nv+", when just installed from "+bundleUrl+": "+matches+"; " - + "brooklyn will prefer the URL-based bundle for top-level references but any dependencies or " - + "import-packages will be at the mercy of OSGi. " - + "It is recommended to use distinct versions for different bundles, and the same URL for the same bundles."); + throw new IllegalStateException("Bundle "+bundle+" not previously registered, but URL is empty."); } - urlToBundleIdentifier.put(bundleUrl, nv); - - } catch (BundleException e) { - log.debug("Bundle from "+bundleUrl+" failed to install (rethrowing): "+e); - throw Throwables.propagate(e); + return true; } + return false; } - public <T> Maybe<Class<T>> tryResolveClass(String type, String... bundleUrlsOrNameVersionString) { - return tryResolveClass(type, Arrays.asList(bundleUrlsOrNameVersionString)); + public <T> Maybe<Class<T>> tryResolveClass(String type, CatalogBundle... catalogBundles) { + return tryResolveClass(type, Arrays.asList(catalogBundles)); } - public <T> Maybe<Class<T>> tryResolveClass(String type, Iterable<String> bundleUrlsOrNameVersionString) { - Map<String,Throwable> bundleProblems = MutableMap.of(); - for (String bundleUrlOrNameVersionString: bundleUrlsOrNameVersionString) { + public <T> Maybe<Class<T>> tryResolveClass(String type, Iterable<CatalogBundle> catalogBundles) { + Map<CatalogBundle,Throwable> bundleProblems = MutableMap.of(); + for (CatalogBundle catalogBundle: catalogBundles) { try { - Maybe<Bundle> bundle = findBundle(bundleUrlOrNameVersionString); - + Maybe<Bundle> bundle = findBundle(catalogBundle); if (bundle.isPresent()) { Bundle b = bundle.get(); Class<T> clazz; @@ -147,17 +184,17 @@ public class OsgiManager { } return Maybe.of(clazz); } else { - bundleProblems.put(bundleUrlOrNameVersionString, ((Maybe.Absent<?>)bundle).getException()); + bundleProblems.put(catalogBundle, ((Maybe.Absent<?>)bundle).getException()); } } catch (Exception e) { // should come from classloading now; name formatting or missing bundle errors will be caught above Exceptions.propagateIfFatal(e); - bundleProblems.put(bundleUrlOrNameVersionString, e); + bundleProblems.put(catalogBundle, e); Throwable cause = e.getCause(); if (cause != null && cause.getMessage().contains("Unresolved constraint in bundle")) { - log.warn("Unresolved constraint resolving OSGi bundle "+bundleUrlOrNameVersionString+" to load "+type+": "+cause.getMessage()); + log.warn("Unresolved constraint resolving OSGi bundle "+catalogBundle+" to load "+type+": "+cause.getMessage()); if (log.isDebugEnabled()) log.debug("Trace for OSGi resolution failure", e); } } @@ -173,22 +210,20 @@ public class OsgiManager { } } - /** finds an installed bundle with the given URL or OSGi identifier ("symbolicName:version" string) */ - public Maybe<Bundle> findBundle(String bundleUrlOrNameVersionString) { - String bundleNameVersion = urlToBundleIdentifier.get(bundleUrlOrNameVersionString); - if (bundleNameVersion==null) { - Maybe<String[]> nv = Osgis.parseOsgiIdentifier(bundleUrlOrNameVersionString); - if (nv.isPresent()) - bundleNameVersion = bundleUrlOrNameVersionString; + public Maybe<Bundle> findBundle(CatalogBundle catalogBundle) { + BundleFinder bundleFinder = Osgis.bundleFinder(framework); + if (catalogBundle.isNamed()) { + bundleFinder.symbolicName(catalogBundle.getName()).version(catalogBundle.getVersion()); + } else { + bundleFinder.requiringFromUrl(catalogBundle.getUrl()); } - Maybe<Bundle> bundle = Osgis.bundleFinder(framework).id(bundleNameVersion).preferringFromUrl(bundleUrlOrNameVersionString).find(); - return bundle; + return bundleFinder.find(); } - public URL getResource(String name, Iterable<String> bundleUrlsOrNameVersionString) { - for (String bundleUrlOrNameVersionString: bundleUrlsOrNameVersionString) { + public URL getResource(String name, Iterable<CatalogBundle> catalogBundles) { + for (CatalogBundle catalogBundle: catalogBundles) { try { - Maybe<Bundle> bundle = findBundle(bundleUrlOrNameVersionString); + Maybe<Bundle> bundle = findBundle(catalogBundle); if (bundle.isPresent()) { URL result = bundle.get().getResource(name); if (result!=null) return result; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/main/java/brooklyn/util/osgi/Osgis.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/util/osgi/Osgis.java b/core/src/main/java/brooklyn/util/osgi/Osgis.java index f7508f6..98720a6 100644 --- a/core/src/main/java/brooklyn/util/osgi/Osgis.java +++ b/core/src/main/java/brooklyn/util/osgi/Osgis.java @@ -57,6 +57,7 @@ import org.osgi.framework.wiring.BundleCapability; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import brooklyn.catalog.CatalogItem.CatalogBundle; import brooklyn.util.ResourceUtils; import brooklyn.util.collections.MutableList; import brooklyn.util.collections.MutableMap; @@ -91,6 +92,34 @@ public class Osgis { private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF"; private static final Set<String> SYSTEM_BUNDLES = MutableSet.of(); + public static class VersionedName { + private String symbolicName; + private Version version; + public VersionedName(Bundle b) { + this.symbolicName = b.getSymbolicName(); + this.version = b.getVersion(); + } + public VersionedName(String symbolicName, Version version) { + this.symbolicName = symbolicName; + this.version = version; + } + @Override public String toString() { + return symbolicName + ":" + Strings.toString(version); + } + public boolean equals(String sn, String v) { + return symbolicName.equals(sn) && (version == null && v == null || version != null && version.toString().equals(v)); + } + public boolean equals(String sn, Version v) { + return symbolicName.equals(sn) && (version == null && v == null || version != null && version.equals(v)); + } + protected String getSymbolicName() { + return symbolicName; + } + protected Version getVersion() { + return version; + } + } + public static class BundleFinder { protected final Framework framework; protected String symbolicName; @@ -117,14 +146,29 @@ public class Osgis { if (Strings.isBlank(symbolicNameOptionallyWithVersion)) return this; - Maybe<String[]> partsM = parseOsgiIdentifier(symbolicNameOptionallyWithVersion); - if (partsM.isAbsent()) + Maybe<VersionedName> nv = parseOsgiIdentifier(symbolicNameOptionallyWithVersion); + if (nv.isAbsent()) throw new IllegalArgumentException("Cannot parse symbolic-name:version string '"+symbolicNameOptionallyWithVersion+"'"); - String[] parts = partsM.get(); - - symbolicName(parts[0]); - if (parts.length >= 2) version(parts[1]); - + + return id(nv.get()); + } + + private BundleFinder id(VersionedName nv) { + symbolicName(nv.getSymbolicName()); + if (nv.getVersion() != null) { + version(nv.getVersion().toString()); + } + return this; + } + + public BundleFinder bundle(CatalogBundle bundle) { + if (bundle.isNamed()) { + symbolicName(bundle.getName()); + version(bundle.getVersion()); + } + if (bundle.getUrl() != null) { + requiringFromUrl(bundle.getUrl()); + } return this; } @@ -567,7 +611,7 @@ public class Osgis { /** Takes a string which might be of the form "symbolic-name" or "symbolic-name:version" (or something else entirely) * and returns an array of 1 or 2 string items being the symbolic name or symbolic name and version if possible * (or returning {@link Maybe#absent()} if not, with a suitable error message). */ - public static Maybe<String[]> parseOsgiIdentifier(String symbolicNameOptionalWithVersion) { + public static Maybe<VersionedName> parseOsgiIdentifier(String symbolicNameOptionalWithVersion) { if (Strings.isBlank(symbolicNameOptionalWithVersion)) return Maybe.absent("OSGi identifier is blank"); @@ -575,13 +619,14 @@ public class Osgis { if (parts.length>2) return Maybe.absent("OSGi identifier has too many parts; max one ':' symbol"); + Version v = null; try { - Version.parseVersion(parts[1]); + v = Version.parseVersion(parts[1]); } catch (IllegalArgumentException e) { return Maybe.absent("OSGi identifier has invalid version string"); } - return Maybe.of(parts); + return Maybe.of(new VersionedName(parts[0], v)); } /** http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java b/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java index 9eb56fd..84e3fc5 100644 --- a/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java +++ b/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java @@ -28,9 +28,9 @@ import io.brooklyn.camp.test.mock.web.MockWebPlatform; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; +import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,6 +40,7 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import brooklyn.catalog.CatalogItem; +import brooklyn.catalog.CatalogItem.CatalogBundle; import brooklyn.catalog.CatalogPredicates; import brooklyn.catalog.internal.BasicBrooklynCatalog; import brooklyn.catalog.internal.CatalogDto; @@ -58,7 +59,6 @@ import brooklyn.test.entity.LocalManagementContextForTests; import brooklyn.test.entity.TestApplication; import brooklyn.test.entity.TestEntity; import brooklyn.util.ResourceUtils; -import brooklyn.util.collections.MutableList; import brooklyn.util.collections.MutableMap; import brooklyn.util.config.ConfigBag; import brooklyn.util.stream.Streams; @@ -66,7 +66,6 @@ import brooklyn.util.stream.Streams; import com.google.common.base.Joiner; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; /** Tests of lightweight CAMP integration. Since the "real" integration is in brooklyn-camp project, * but some aspects of CAMP we want to be able to test here. */ @@ -161,9 +160,11 @@ public class CampYamlLiteTest { CatalogItem<Object, Object> retrievedItem = Iterables.getOnlyElement(retrievedItems); Assert.assertEquals(retrievedItem, realItem); - Set<String> expectedBundles = Sets.newHashSet(OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL); - Assert.assertEquals(retrievedItem.getLibraries().getBundles(), expectedBundles); - // Assert.assertEquals(retrievedItem.getVersion(), "0.9"); + Collection<CatalogBundle> bundles = retrievedItem.getLibraries().getBundles(); + Assert.assertEquals(bundles.size(), 1); + CatalogBundle bundle = Iterables.getOnlyElement(bundles); + Assert.assertEquals(bundle.getUrl(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL); + Assert.assertEquals(bundle.getVersion(), "0.1.0"); EntitySpec<?> spec1 = (EntitySpec<?>) mgmt.getCatalog().createSpec(retrievedItem); assertNotNull(spec1); @@ -231,8 +232,10 @@ public class CampYamlLiteTest { assertEquals(item.getId(), registeredTypeName); // and let's check we have libraries - List<String> libs = item.getLibraries().getBundles(); - assertEquals(libs, MutableList.of(bundleUrl)); + Collection<CatalogBundle> libs = item.getLibraries().getBundles(); + assertEquals(libs.size(), 1); + CatalogBundle bundle = Iterables.getOnlyElement(libs); + assertEquals(bundle.getUrl(), bundleUrl); // now let's check other things on the item assertEquals(item.getDisplayName(), "My Catalog App"); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java b/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java index 8e6d704..e232116 100644 --- a/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java +++ b/core/src/test/java/brooklyn/catalog/internal/CatalogDtoTest.java @@ -91,19 +91,24 @@ public class CatalogDtoTest { "example for what can be expressed, and how", "contents-built-in-test")); root.setClasspathScanForEntities(CatalogScanningModes.NONE); + String bundleUrl = MavenRetriever.localUrl(BrooklynMavenArtifacts.artifact("", "brooklyn-core", "jar", "tests")); CatalogDo testEntitiesJavaCatalog = new CatalogDo( managementContext, CatalogDto.newNamedInstance("Test Entities from Java", null, "test-java")); testEntitiesJavaCatalog.setClasspathScanForEntities(CatalogScanningModes.NONE); - testEntitiesJavaCatalog.addToClasspath(MavenRetriever.localUrl(BrooklynMavenArtifacts.artifact("", "brooklyn-core", "jar", "tests"))); - testEntitiesJavaCatalog.addEntry(CatalogItemBuilder.newTemplate(TestApplication.class.getCanonicalName(), "Test App from JAR").build()); - testEntitiesJavaCatalog.addEntry(CatalogItemBuilder.newEntity(TestEntity.class.getCanonicalName(), "Test Entity from JAR").build()); + testEntitiesJavaCatalog.addToClasspath(bundleUrl); + testEntitiesJavaCatalog.addEntry(CatalogItemBuilder.newTemplate(TestApplication.class.getCanonicalName(), "Test App from JAR") + .javaType(TestApplication.class.getCanonicalName()) + .build()); + testEntitiesJavaCatalog.addEntry(CatalogItemBuilder.newEntity(TestEntity.class.getCanonicalName(), "Test Entity from JAR") + .javaType(TestEntity.class.getCanonicalName()) + .build()); root.addCatalog(testEntitiesJavaCatalog.dto); CatalogDo testEntitiesJavaCatalogScanning = new CatalogDo( managementContext, CatalogDto.newNamedInstance("Test Entities from Java Scanning", null, "test-java-scan")); - testEntitiesJavaCatalogScanning.addToClasspath(MavenRetriever.localUrl(BrooklynMavenArtifacts.artifact("", "brooklyn-core", "jar", "tests"))); + testEntitiesJavaCatalogScanning.addToClasspath(bundleUrl); testEntitiesJavaCatalogScanning.setClasspathScanForEntities(CatalogScanningModes.ANNOTATIONS); root.addCatalog(testEntitiesJavaCatalogScanning.dto); @@ -114,7 +119,7 @@ public class CatalogDtoTest { osgiCatalog.setClasspathScanForEntities(CatalogScanningModes.NONE); CatalogEntityItemDto osgiEntity = CatalogItemBuilder.newEntity(TestEntity.class.getCanonicalName(), "Test Entity from OSGi").build(); // NB: this is not actually an OSGi bundle, but it's okay as we don't instantiate the bundles ahead of time (currently) - osgiEntity.libraries.addBundle(MavenRetriever.localUrl(BrooklynMavenArtifacts.artifact("", "brooklyn-core", "jar", "tests"))); + osgiEntity.libraries.addBundle(null, null, bundleUrl); testEntitiesJavaCatalog.addEntry(osgiEntity); root.addCatalog(osgiCatalog.dto); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java b/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java index e9102c2..976223e 100644 --- a/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java +++ b/core/src/test/java/brooklyn/catalog/internal/CatalogLoadTest.java @@ -20,15 +20,16 @@ package brooklyn.catalog.internal; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import brooklyn.catalog.CatalogItem.CatalogBundle; +import brooklyn.util.ResourceUtils; + import com.google.common.base.Joiner; import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; - -import brooklyn.util.ResourceUtils; public class CatalogLoadTest { @@ -57,8 +58,18 @@ public class CatalogLoadTest { assertEquals(template.getJavaType(), "com.example.ExampleApp"); assertEquals(template.getLibraries().getBundles().size(), 2, "Template bundles=" + Joiner.on(", ").join(template.getLibraries().getBundles())); - assertEquals(Sets.newHashSet(template.getLibraries().getBundles()), - Sets.newHashSet("file://path/to/bundle.jar", "http://www.url.com/for/bundle.jar")); + + boolean foundBundle1 = false, foundBundle2 = false; + for (CatalogBundle bundle : template.getLibraries().getBundles()) { + if (bundle.getUrl().equals("file://path/to/bundle.jar")) { + foundBundle1 = true; + } + if (bundle.getUrl().equals("http://www.url.com/for/bundle.jar")) { + foundBundle2 = true; + } + } + assertTrue(foundBundle1); + assertTrue(foundBundle2); } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java b/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java index 94b9e9e..6d2cbc8 100644 --- a/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java +++ b/core/src/test/java/brooklyn/management/osgi/OsgiStandaloneTest.java @@ -62,6 +62,8 @@ public class OsgiStandaloneTest { public static final String BROOKLYN_TEST_OSGI_ENTITIES_PATH = OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_PATH; public static final String BROOKLYN_TEST_OSGI_ENTITIES_URL = "classpath:"+BROOKLYN_TEST_OSGI_ENTITIES_PATH; + public static final String BROOKLYN_TEST_OSGI_ENTITIES_NAME = "org.apache.brooklyn.test.resources.osgi.brooklyn-test-osgi-entities"; + public static final String BROOKLYN_TEST_OSGI_ENTITIES_VERSION = "0.1.0"; protected Framework framework = null; private File storageTempDir; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/test/resources/brooklyn/camp/lite/test-app-service-blueprint.yaml ---------------------------------------------------------------------- diff --git a/core/src/test/resources/brooklyn/camp/lite/test-app-service-blueprint.yaml b/core/src/test/resources/brooklyn/camp/lite/test-app-service-blueprint.yaml index 8740ca5..846f299 100644 --- a/core/src/test/resources/brooklyn/camp/lite/test-app-service-blueprint.yaml +++ b/core/src/test/resources/brooklyn/camp/lite/test-app-service-blueprint.yaml @@ -34,5 +34,5 @@ brooklyn.catalog: version: 0.9 libraries: - name: lib1 - version: v1 + version: 0.1.0 url: classpath:/brooklyn/osgi/brooklyn-test-osgi-entities.jar \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/core/src/test/resources/brooklyn/catalog/internal/osgi-catalog.xml ---------------------------------------------------------------------- diff --git a/core/src/test/resources/brooklyn/catalog/internal/osgi-catalog.xml b/core/src/test/resources/brooklyn/catalog/internal/osgi-catalog.xml index 52a9764..651dfc5 100644 --- a/core/src/test/resources/brooklyn/catalog/internal/osgi-catalog.xml +++ b/core/src/test/resources/brooklyn/catalog/internal/osgi-catalog.xml @@ -24,8 +24,8 @@ <template name="Entity name" version="9.1.3" type="com.example.ExampleApp"> <description>An example application</description> <libraries> - <bundle>file://path/to/bundle.jar</bundle> - <bundle>http://www.url.com/for/bundle.jar</bundle> + <bundle><url>file://path/to/bundle.jar</url></bundle> + <bundle><url>http://www.url.com/for/bundle.jar</url></bundle> </libraries> </template> </catalog> http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java index 61e3e4f..e5c233a 100644 --- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java +++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java @@ -30,6 +30,7 @@ import org.slf4j.LoggerFactory; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; +import brooklyn.catalog.internal.CatalogUtils; import brooklyn.entity.Entity; import brooklyn.entity.basic.BrooklynTaskTags; import brooklyn.entity.basic.Entities; @@ -148,5 +149,8 @@ public abstract class AbstractYamlTest { private String join(String[] catalogYaml) { return Joiner.on("\n").join(catalogYaml); } - + + protected String ver(String id) { + return id + CatalogUtils.VERSION_DELIMITER + TEST_VERSION; + } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencedYamlTest.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencedYamlTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencedYamlTest.java index 05bb8c0..048fa8f 100644 --- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencedYamlTest.java +++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/ReferencedYamlTest.java @@ -95,6 +95,7 @@ public class ReferencedYamlTest extends AbstractYamlTest { addCatalogItem( "brooklyn.catalog:", " id: yaml.reference", + " version: " + TEST_VERSION, "services:", "- type: classpath://yaml-ref-entity.yaml"); @@ -102,7 +103,7 @@ public class ReferencedYamlTest extends AbstractYamlTest { Entity app = createAndStartApplication( "services:", "- name: " + entityName, - " type: yaml.reference"); + " type: " + ver("yaml.reference")); checkChildEntitySpec(app, entityName); } @@ -112,6 +113,7 @@ public class ReferencedYamlTest extends AbstractYamlTest { addCatalogItem( "brooklyn.catalog:", " id: yaml.basic", + " version: " + TEST_VERSION, "services:", "- type: brooklyn.entity.basic.BasicEntity"); @@ -134,6 +136,7 @@ public class ReferencedYamlTest extends AbstractYamlTest { addCatalogItem( "brooklyn.catalog:", " id: " + parentCatalogId, + " version: " + TEST_VERSION, " libraries:", " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, "", @@ -142,7 +145,7 @@ public class ReferencedYamlTest extends AbstractYamlTest { Entity app = createAndStartApplication( "services:", - "- type: " + parentCatalogId); + "- type: " + ver(parentCatalogId)); Collection<Entity> children = app.getChildren(); Assert.assertEquals(children.size(), 1); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java index 9281e61..d4b6474 100644 --- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java +++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java @@ -42,7 +42,7 @@ public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest { @Test public void testMoreEntityV1() throws Exception { addCatalogItem(getLocalResource("more-entity-v1-osgi-catalog.yaml")); - Entity app = createAndStartApplication("services: [ { type: more-entity } ]"); + Entity app = createAndStartApplication("services: [ { type: 'more-entity:1.0' } ]"); Entity moreEntity = Iterables.getOnlyElement(app.getChildren()); Assert.assertEquals(moreEntity.getCatalogItemId(), "more-entity"); @@ -56,7 +56,7 @@ public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest { public void testMoreEntityV1WithPolicy() throws Exception { addCatalogItem(getLocalResource("simple-policy-osgi-catalog.yaml")); addCatalogItem(getLocalResource("more-entity-v1-with-policy-osgi-catalog.yaml")); - Entity app = createAndStartApplication("services: [ { type: more-entity } ]"); + Entity app = createAndStartApplication("services: [ { type: 'more-entity:1.0' } ]"); Entity moreEntity = Iterables.getOnlyElement(app.getChildren()); Assert.assertEquals(moreEntity.getCatalogItemId(), "more-entity"); @@ -70,7 +70,7 @@ public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest { @Test public void testMoreEntityV2() throws Exception { addCatalogItem(getLocalResource("more-entity-v2-osgi-catalog.yaml")); - Entity app = createAndStartApplication("services: [ { type: more-entity } ]"); + Entity app = createAndStartApplication("services: [ { type: 'more-entity:1.0' } ]"); Entity moreEntity = Iterables.getOnlyElement(app.getChildren()); Assert.assertEquals(moreEntity.getCatalogItemId(), "more-entity"); @@ -88,7 +88,7 @@ public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest { public void testMoreEntityV2ThenV1GivesV1() throws Exception { addCatalogItem(getLocalResource("more-entity-v2-osgi-catalog.yaml")); addCatalogItem(getLocalResource("more-entity-v1-osgi-catalog.yaml")); - Entity app = createAndStartApplication("services: [ { type: more-entity } ]"); + Entity app = createAndStartApplication("services: [ { type: 'more-entity:1.0' } ]"); Entity moreEntity = Iterables.getOnlyElement(app.getChildren()); OsgiVersionMoreEntityTest.assertV1EffectorCall(moreEntity); @@ -102,7 +102,7 @@ public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest { public void testMoreEntityV1ThenV2GivesV2() throws Exception { addCatalogItem(getLocalResource("more-entity-v1-osgi-catalog.yaml")); addCatalogItem(getLocalResource("more-entity-v2-osgi-catalog.yaml")); - Entity app = createAndStartApplication("services: [ { type: more-entity } ]"); + Entity app = createAndStartApplication("services: [ { type: 'more-entity:1.0' } ]"); Entity moreEntity = Iterables.getOnlyElement(app.getChildren()); OsgiVersionMoreEntityTest.assertV2EffectorCall(moreEntity); @@ -113,8 +113,8 @@ public class CatalogOsgiVersionMoreEntityTest extends AbstractYamlTest { public void testMoreEntityBothV1AndV2() throws Exception { addCatalogItem(getLocalResource("more-entity-v1-called-v1-osgi-catalog.yaml")); addCatalogItem(getLocalResource("more-entity-v2-osgi-catalog.yaml")); - Entity v1 = createAndStartApplication("services: [ { type: more-entity-v1 } ]"); - Entity v2 = createAndStartApplication("services: [ { type: more-entity } ]"); + Entity v1 = createAndStartApplication("services: [ { type: 'more-entity-v1:1.0' } ]"); + Entity v2 = createAndStartApplication("services: [ { type: 'more-entity:1.0' } ]"); Entity moreEntityV1 = Iterables.getOnlyElement(v1.getChildren()); Entity moreEntityV2 = Iterables.getOnlyElement(v2.getChildren()); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java index dfbc96b..f5ad95c 100644 --- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java +++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java @@ -25,10 +25,10 @@ import io.brooklyn.camp.brooklyn.AbstractYamlTest; import java.util.Collection; +import org.junit.Assert; import org.testng.annotations.Test; import brooklyn.catalog.CatalogItem; -import brooklyn.catalog.internal.CatalogUtils; import brooklyn.entity.Entity; import brooklyn.entity.basic.BasicEntity; import brooklyn.management.osgi.OsgiStandaloneTest; @@ -79,7 +79,7 @@ public class CatalogYamlEntityTest extends AbstractYamlTest { String yaml = "name: simple-app-yaml\n" + "location: localhost\n" + "services: \n" + - " - serviceType: " + registeredTypeName; + " - serviceType: " + ver(registeredTypeName); try { createAndStartApplication(yaml); } catch (UnsupportedOperationException e) { @@ -115,7 +115,7 @@ public class CatalogYamlEntityTest extends AbstractYamlTest { String referencedRegisteredTypeName = "my.catalog.app.id.child.referenced"; String referrerRegisteredTypeName = "my.catalog.app.id.child.referring"; addCatalogOSGiEntity(referencedRegisteredTypeName, SIMPLE_ENTITY_TYPE); - addCatalogChildOSGiEntity(referrerRegisteredTypeName, referencedRegisteredTypeName); + addCatalogChildOSGiEntity(referrerRegisteredTypeName, ver(referencedRegisteredTypeName)); Entity app = createAndStartApplication( "name: simple-app-yaml", @@ -123,7 +123,7 @@ public class CatalogYamlEntityTest extends AbstractYamlTest { "services:", "- serviceType: "+BasicEntity.class.getName(), " brooklyn.children:", - " - type: " + referrerRegisteredTypeName); + " - type: " + ver(referrerRegisteredTypeName)); Collection<Entity> children = app.getChildren(); assertEquals(children.size(), 1); @@ -160,19 +160,159 @@ public class CatalogYamlEntityTest extends AbstractYamlTest { public void testLaunchApplicationChildLoopCatalogIdFails() throws Exception { String referrerRegisteredTypeName = "my.catalog.app.id.child.referring"; try { - addCatalogChildOSGiEntity(referrerRegisteredTypeName, referrerRegisteredTypeName); + addCatalogChildOSGiEntity(referrerRegisteredTypeName, ver(referrerRegisteredTypeName)); fail("Expected to throw IllegalStateException"); } catch (IllegalStateException e) { assertTrue(e.getMessage().contains("Could not find "+referrerRegisteredTypeName)); } } + @Test + public void testReferenceInstalledBundleByName() { + String firstItemId = "my.catalog.app.id.register_bundle"; + String secondItemId = "my.catalog.app.id.reference_bundle"; + addCatalogItem( + "brooklyn.catalog:", + " id: " + firstItemId, + " version: " + TEST_VERSION, + " libraries:", + " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + "", + "services:", + "- type: " + SIMPLE_ENTITY_TYPE); + deleteCatalogEntity(firstItemId); + + addCatalogItem( + "brooklyn.catalog:", + " id: " + secondItemId, + " version: " + TEST_VERSION, + " libraries:", + " - name: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_NAME, + " version: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_VERSION, + "", + "services:", + "- type: " + SIMPLE_ENTITY_TYPE); + + deleteCatalogEntity(secondItemId); + } + + @Test + public void testReferenceNonInstalledBundledByNameFails() { + String nonExistentId = "none-existent-id"; + String nonExistentVersion = "9.9.9"; + try { + addCatalogItem( + "brooklyn.catalog:", + " id: my.catalog.app.id.non_existing.ref", + " version: " + TEST_VERSION, + " libraries:", + " - name: " + nonExistentId, + " version: " + nonExistentVersion, + "", + "services:", + "- type: " + SIMPLE_ENTITY_TYPE); + fail(); + } catch (IllegalStateException e) { + Assert.assertEquals(e.getMessage(), "Bundle CatalogBundleDto{name=" + nonExistentId + ", version=" + nonExistentVersion + ", url=null} not already registered by name:version, but URL is empty."); + } + } + + @Test + public void testPartialBundleReferenceFails() { + try { + addCatalogItem( + "brooklyn.catalog:", + " id: my.catalog.app.id.non_existing.ref", + " version: " + TEST_VERSION, + " libraries:", + " - name: io.brooklyn.brooklyn-test-osgi-entities", + "", + "services:", + "- type: " + SIMPLE_ENTITY_TYPE); + fail(); + } catch (NullPointerException e) { + Assert.assertEquals(e.getMessage(), "version"); + } + try { + addCatalogItem( + "brooklyn.catalog:", + " id: my.catalog.app.id.non_existing.ref", + " version: " + TEST_VERSION, + " libraries:", + " - version: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_VERSION, + "", + "services:", + "- type: " + SIMPLE_ENTITY_TYPE); + fail(); + } catch (NullPointerException e) { + Assert.assertEquals(e.getMessage(), "name"); + } + } + + @Test + public void testFullBundleReference() { + String itemId = "my.catalog.app.id.full_ref"; + addCatalogItem( + "brooklyn.catalog:", + " id: " + itemId, + " version: " + TEST_VERSION, + " libraries:", + " - name: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_NAME, + " version: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_VERSION, + " url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + "", + "services:", + "- type: " + SIMPLE_ENTITY_TYPE); + deleteCatalogEntity(itemId); + } + + /** + * Test that the name:version contained in the OSGi bundle will + * override the values supplied in the YAML. + */ + @Test + public void testFullBundleReferenceUrlMetaOverridesLocalNameVersion() { + String firstItemId = "my.catalog.app.id.register_bundle"; + String secondItemId = "my.catalog.app.id.reference_bundle"; + String nonExistentId = "non_existent_id"; + String nonExistentVersion = "9.9.9"; + addCatalogItem( + "brooklyn.catalog:", + " id: " + firstItemId, + " version: " + TEST_VERSION, + " libraries:", + " - name: " + nonExistentId, + " version: " + nonExistentVersion, + " url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, + "", + "services:", + "- type: " + SIMPLE_ENTITY_TYPE); + deleteCatalogEntity(firstItemId); + + try { + addCatalogItem( + "brooklyn.catalog:", + " id: " + secondItemId, + " version: " + TEST_VERSION, + " libraries:", + " - name: " + nonExistentId, + " version: " + nonExistentVersion, + "", + "services:", + "- type: " + SIMPLE_ENTITY_TYPE); + fail(); + } catch (IllegalStateException e) { + assertEquals(e.getMessage(), "Bundle CatalogBundleDto{name=" + nonExistentId + ", version=" + nonExistentVersion + ", url=null} " + + "not already registered by name:version, but URL is empty."); + } + } + private void registerAndLaunchAndAssertSimpleEntity(String registeredTypeName, String serviceType) throws Exception { addCatalogOSGiEntity(registeredTypeName, serviceType); String yaml = "name: simple-app-yaml\n" + "location: localhost\n" + "services: \n" + - " - serviceType: "+registeredTypeName; + " - serviceType: "+ver(registeredTypeName); Entity app = createAndStartApplication(yaml); Entity simpleEntity = Iterables.getOnlyElement(app.getChildren()); @@ -207,7 +347,7 @@ public class CatalogYamlEntityTest extends AbstractYamlTest { " name: My Catalog App", " description: My description", " icon_url: classpath://path/to/myicon.jpg", - " version: 0.1.2", + " version: " + TEST_VERSION, " libraries:", " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, "", @@ -217,7 +357,4 @@ public class CatalogYamlEntityTest extends AbstractYamlTest { " - type: " + serviceType); } - private String ver(String id) { - return id + CatalogUtils.VERSION_DELIMITER + TEST_VERSION; - } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java index e704ea1..9ba5bee 100644 --- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java +++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/catalog/CatalogYamlPolicyTest.java @@ -60,7 +60,7 @@ public class CatalogYamlPolicyTest extends AbstractYamlTest { "services: ", " - type: brooklyn.entity.basic.BasicEntity\n" + " brooklyn.policies:\n" + - " - type: " + registeredTypeName, + " - type: " + ver(registeredTypeName), " brooklyn.config:", " config2: config2 override", " config3: config3"); @@ -87,19 +87,19 @@ public class CatalogYamlPolicyTest extends AbstractYamlTest { " name: My Catalog App", " description: My description", " icon_url: classpath://path/to/myicon.jpg", - " version: 0.1.2", + " version: " + TEST_VERSION, " libraries:", " - url: " + OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_URL, "", "services:", "- type: " + SIMPLE_ENTITY_TYPE, " brooklyn.policies:", - " - type: " + referencedRegisteredTypeName); + " - type: " + ver(referencedRegisteredTypeName)); String yaml = "name: simple-app-yaml\n" + "location: localhost\n" + "services: \n" + - " - serviceType: "+referrerRegisteredTypeName; + " - serviceType: "+ ver(referrerRegisteredTypeName); Entity app = createAndStartApplication(yaml); http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v1-with-policy-osgi-catalog.yaml ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v1-with-policy-osgi-catalog.yaml b/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v1-with-policy-osgi-catalog.yaml index 79657d8..3c03bd0 100644 --- a/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v1-with-policy-osgi-catalog.yaml +++ b/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v1-with-policy-osgi-catalog.yaml @@ -19,7 +19,7 @@ services: - type: brooklyn.osgi.tests.more.MoreEntity brooklyn.policies: - - type: simple-policy + - type: simple-policy:1.0 brooklyn.catalog: id: more-entity http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v2-osgi-catalog.yaml ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v2-osgi-catalog.yaml b/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v2-osgi-catalog.yaml index 7b29439..74323fa 100644 --- a/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v2-osgi-catalog.yaml +++ b/usage/camp/src/test/resources/io/brooklyn/camp/brooklyn/catalog/more-entity-v2-osgi-catalog.yaml @@ -21,7 +21,7 @@ services: brooklyn.catalog: id: more-entity - version: 2.0 + version: 1.0 # see OsgiTestResources libraries: - classpath:/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/resources/yaml-ref-app.yaml ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/resources/yaml-ref-app.yaml b/usage/camp/src/test/resources/yaml-ref-app.yaml index a26a4ab..8e1f740 100644 --- a/usage/camp/src/test/resources/yaml-ref-app.yaml +++ b/usage/camp/src/test/resources/yaml-ref-app.yaml @@ -18,4 +18,4 @@ name: Basic app services: - name: service - type: brooklyn.entity.basic.BasicApplication \ No newline at end of file + type: brooklyn.entity.basic.BasicApplication http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/resources/yaml-ref-catalog.yaml ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/resources/yaml-ref-catalog.yaml b/usage/camp/src/test/resources/yaml-ref-catalog.yaml index 220deb9..545fd1a 100644 --- a/usage/camp/src/test/resources/yaml-ref-catalog.yaml +++ b/usage/camp/src/test/resources/yaml-ref-catalog.yaml @@ -18,4 +18,4 @@ name: Basic app services: - name: service - type: yaml.basic \ No newline at end of file + type: yaml.basic:0.1.2 http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/camp/src/test/resources/yaml-ref-entity.yaml ---------------------------------------------------------------------- diff --git a/usage/camp/src/test/resources/yaml-ref-entity.yaml b/usage/camp/src/test/resources/yaml-ref-entity.yaml index 8d27427..69d311f 100644 --- a/usage/camp/src/test/resources/yaml-ref-entity.yaml +++ b/usage/camp/src/test/resources/yaml-ref-entity.yaml @@ -18,4 +18,4 @@ name: Basic entity services: - name: service - type: brooklyn.entity.basic.BasicEntity \ No newline at end of file + type: brooklyn.entity.basic.BasicEntity http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/268aaf6b/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java ---------------------------------------------------------------------- diff --git a/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java b/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java index 771f8ff..8e33ebb 100644 --- a/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java +++ b/usage/rest-server/src/test/java/brooklyn/rest/resources/CatalogResourceTest.java @@ -25,6 +25,7 @@ import java.awt.Image; import java.awt.Toolkit; import java.io.IOException; import java.net.URI; +import java.util.Collection; import java.util.List; import java.util.Set; @@ -39,14 +40,16 @@ import org.testng.annotations.Test; import org.testng.reporters.Files; import brooklyn.catalog.CatalogItem; +import brooklyn.catalog.CatalogItem.CatalogBundle; +import brooklyn.catalog.internal.CatalogUtils; import brooklyn.management.osgi.OsgiStandaloneTest; import brooklyn.policy.autoscaling.AutoScalerPolicy; import brooklyn.rest.domain.CatalogEntitySummary; import brooklyn.rest.domain.CatalogItemSummary; import brooklyn.rest.domain.CatalogPolicySummary; import brooklyn.rest.testing.BrooklynRestResourceTest; -import brooklyn.util.collections.MutableList; +import com.google.common.collect.Iterables; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.GenericType; @@ -99,14 +102,16 @@ public class CatalogResourceTest extends BrooklynRestResourceTest { Assert.assertNotNull(entityItem.getPlanYaml()); Assert.assertTrue(entityItem.getPlanYaml().contains("brooklyn.test.entity.TestEntity")); + assertEquals(entityItem.getId(), ver(registeredTypeName)); assertEquals(entityItem.getSymbolicName(), registeredTypeName); assertEquals(entityItem.getVersion(), TEST_VERSION); // and internally let's check we have libraries CatalogItem<?, ?> item = getManagementContext().getCatalog().getCatalogItem(registeredTypeName, TEST_VERSION); Assert.assertNotNull(item); - List<String> libs = item.getLibraries().getBundles(); - assertEquals(libs, MutableList.of(bundleUrl)); + Collection<CatalogBundle> libs = item.getLibraries().getBundles(); + assertEquals(libs.size(), 1); + assertEquals(Iterables.getOnlyElement(libs).getUrl(), bundleUrl); // now let's check other things on the item assertEquals(entityItem.getName(), "My Catalog App"); @@ -129,7 +134,7 @@ public class CatalogResourceTest extends BrooklynRestResourceTest { " id: " + registeredTypeName + "\n"+ " name: My Catalog App\n"+ " description: My description\n"+ - " version: 0.1.2\n"+ + " version: " + TEST_VERSION + "\n" + " libraries:\n"+ " - url: " + bundleUrl + "\n"+ "\n"+ @@ -142,6 +147,7 @@ public class CatalogResourceTest extends BrooklynRestResourceTest { assertEquals(entityItem.getRegisteredType(), registeredTypeName); Assert.assertNotNull(entityItem.getPlanYaml()); Assert.assertTrue(entityItem.getPlanYaml().contains(policyType)); + assertEquals(entityItem.getId(), ver(registeredTypeName)); assertEquals(entityItem.getSymbolicName(), registeredTypeName); assertEquals(entityItem.getVersion(), TEST_VERSION); } @@ -260,4 +266,8 @@ public class CatalogResourceTest extends BrooklynRestResourceTest { .get(ClientResponse.class); assertEquals(getPostDeleteResponse.getStatus(), Response.Status.NOT_FOUND.getStatusCode()); } + + private static String ver(String id) { + return id + CatalogUtils.VERSION_DELIMITER + TEST_VERSION; + } }