You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/11/11 02:52:53 UTC
[1/2] incubator-brooklyn git commit: support multiple instances of
the same osgi symbolic-name:version
Repository: incubator-brooklyn
Updated Branches:
refs/heads/master 3cfda7e8f -> dc53cec5d
support multiple instances of the same osgi symbolic-name:version
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/72b29b95
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/72b29b95
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/72b29b95
Branch: refs/heads/master
Commit: 72b29b950b0ad2839dc0e3beafb814089a466472
Parents: 3cfda7e
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Nov 6 17:41:33 2014 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Nov 11 01:52:05 2014 +0000
----------------------------------------------------------------------
.../brooklyn/management/ha/OsgiManager.java | 78 +++--
.../main/java/brooklyn/util/ResourceUtils.java | 2 +-
.../src/main/java/brooklyn/util/osgi/Osgis.java | 300 +++++++++++++++----
.../osgi/more-entities-v2-evil-twin/pom.xml | 88 ++++++
.../brooklyn/osgi/tests/more/MoreEntity.java | 38 +++
.../osgi/tests/more/MoreEntityImpl.java | 47 +++
.../brooklyn/catalog/internal/CatalogItems.java | 8 +
.../management/osgi/OsgiTestResources.java | 16 +-
.../osgi/OsgiVersionMoreEntityTest.java | 116 +++++--
...-test-osgi-more-entities_evil-twin_0.2.0.jar | Bin 0 -> 12757 bytes
...-test-osgi-more-entities_evil-twin_0.2.0.txt | 21 ++
.../util/exceptions/ReferenceWithError.java | 6 +-
12 files changed, 601 insertions(+), 119 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/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 3dea979..44b30af 100644
--- a/core/src/main/java/brooklyn/management/ha/OsgiManager.java
+++ b/core/src/main/java/brooklyn/management/ha/OsgiManager.java
@@ -21,6 +21,7 @@ package brooklyn.management.ha;
import java.io.File;
import java.net.URL;
import java.util.Arrays;
+import java.util.List;
import java.util.Map;
import org.osgi.framework.Bundle;
@@ -51,7 +52,9 @@ public class OsgiManager {
protected Framework framework;
protected File osgiTempDir;
- protected Map<String,String> bundleUrlToNameVersionString = MutableMap.of();
+
+ // 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();
public void start() {
try {
@@ -87,19 +90,32 @@ public class OsgiManager {
public void registerBundle(String bundleUrl) {
try {
- String nv = bundleUrlToNameVersionString.get(bundleUrl);
+ String nv = urlToBundleIdentifier.get(bundleUrl);
if (nv!=null) {
- if (Osgis.getBundle(framework, nv).isPresent()) {
+ if (Osgis.bundleFinder(framework).id(nv).requiringFromUrl(bundleUrl).find().isPresent()) {
log.trace("Bundle from "+bundleUrl+" already installed as "+nv+"; not re-registering");
return;
+ } else {
+ log.debug("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();
- // TODO if there is another entry for name:version we should log a warning at the very least,
- // or better provide a way to get back *this* bundle
- bundleUrlToNameVersionString.put(bundleUrl, nv);
- log.debug("Bundle from "+bundleUrl+" successfully installed as " + nv + " ("+b+")");
+
+ 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 {
+ 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.");
+ }
+ urlToBundleIdentifier.put(bundleUrl, nv);
+
} catch (BundleException e) {
log.debug("Bundle from "+bundleUrl+" failed to install (rethrowing): "+e);
throw Throwables.propagate(e);
@@ -112,15 +128,9 @@ public class OsgiManager {
public <T> Maybe<Class<T>> tryResolveClass(String type, Iterable<String> bundleUrlsOrNameVersionString) {
Map<String,Throwable> bundleProblems = MutableMap.of();
for (String bundleUrlOrNameVersionString: bundleUrlsOrNameVersionString) {
- boolean noVersionInstalled = false;
try {
- String bundleNameVersion = bundleUrlToNameVersionString.get(bundleUrlOrNameVersionString);
- if (bundleNameVersion==null) {
- noVersionInstalled = true;
- bundleNameVersion = bundleUrlOrNameVersionString;
- }
-
- Maybe<Bundle> bundle = Osgis.getBundle(framework, bundleNameVersion);
+ Maybe<Bundle> bundle = findBundle(bundleUrlOrNameVersionString);
+
if (bundle.isPresent()) {
Bundle b = bundle.get();
Class<T> clazz;
@@ -137,20 +147,13 @@ public class OsgiManager {
}
return Maybe.of(clazz);
} else {
- bundleProblems.put(bundleUrlOrNameVersionString, new IllegalStateException("Unable to find bundle "+bundleUrlOrNameVersionString));
+ bundleProblems.put(bundleUrlOrNameVersionString, ((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);
- if (noVersionInstalled) {
- if (bundleUrlOrNameVersionString.contains("/")) {
- // suppress misleading nested trace if the input string looked like a URL
- bundleProblems.put(bundleUrlOrNameVersionString, new IllegalStateException("Bundle does not appear to be installed"));
- } else {
- bundleProblems.put(bundleUrlOrNameVersionString, new IllegalStateException("Bundle does not appear to be installed", e));
- }
- } else {
- bundleProblems.put(bundleUrlOrNameVersionString, e);
- }
+ bundleProblems.put(bundleUrlOrNameVersionString, e);
Throwable cause = e.getCause();
if (cause != null && cause.getMessage().contains("Unresolved constraint in bundle")) {
@@ -170,15 +173,22 @@ 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;
+ }
+ Maybe<Bundle> bundle = Osgis.bundleFinder(framework).id(bundleNameVersion).preferringFromUrl(bundleUrlOrNameVersionString).find();
+ return bundle;
+ }
+
public URL getResource(String name, Iterable<String> bundleUrlsOrNameVersionString) {
for (String bundleUrlOrNameVersionString: bundleUrlsOrNameVersionString) {
try {
- String bundleNameVersion = bundleUrlToNameVersionString.get(bundleUrlOrNameVersionString);
- if (bundleNameVersion==null) {
- bundleNameVersion = bundleUrlOrNameVersionString;
- }
-
- Maybe<Bundle> bundle = Osgis.getBundle(framework, bundleNameVersion);
+ Maybe<Bundle> bundle = findBundle(bundleUrlOrNameVersionString);
if (bundle.isPresent()) {
URL result = bundle.get().getResource(name);
if (result!=null) return result;
@@ -190,4 +200,8 @@ public class OsgiManager {
return null;
}
+ public Framework getFramework() {
+ return framework;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/core/src/main/java/brooklyn/util/ResourceUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/ResourceUtils.java b/core/src/main/java/brooklyn/util/ResourceUtils.java
index 072789e..b40df0d 100644
--- a/core/src/main/java/brooklyn/util/ResourceUtils.java
+++ b/core/src/main/java/brooklyn/util/ResourceUtils.java
@@ -323,7 +323,7 @@ public class ResourceUtils {
} catch (MalformedURLException e) {
throw Exceptions.propagate(e);
}
- if (!urlOut.equals(in) && log.isDebugEnabled()) {
+ if (!urlOut.equals(url) && log.isDebugEnabled()) {
log.debug("quietly changing " + url + " to " + urlOut);
}
return urlOut;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/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 d8f20ae..f7508f6 100644
--- a/core/src/main/java/brooklyn/util/osgi/Osgis.java
+++ b/core/src/main/java/brooklyn/util/osgi/Osgis.java
@@ -28,10 +28,14 @@ import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
@@ -56,13 +60,16 @@ import org.slf4j.LoggerFactory;
import brooklyn.util.ResourceUtils;
import brooklyn.util.collections.MutableList;
import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
import brooklyn.util.exceptions.Exceptions;
import brooklyn.util.exceptions.ReferenceWithError;
import brooklyn.util.guava.Maybe;
import brooklyn.util.net.Urls;
import brooklyn.util.os.Os;
import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Strings;
import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
import com.google.common.annotations.Beta;
import com.google.common.base.Joiner;
@@ -82,54 +89,195 @@ public class Osgis {
private static final String EXTENSION_PROTOCOL = "system";
private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
+ private static final Set<String> SYSTEM_BUNDLES = MutableSet.of();
+
+ public static class BundleFinder {
+ protected final Framework framework;
+ protected String symbolicName;
+ protected String version;
+ protected String url;
+ protected boolean urlMandatory = false;
+ protected final List<Predicate<? super Bundle>> predicates = MutableList.of();
+
+ protected BundleFinder(Framework framework) {
+ this.framework = framework;
+ }
- public static List<Bundle> getBundlesByName(Framework framework, String symbolicName, Predicate<Version> versionMatcher) {
- List<Bundle> result = MutableList.of();
- for (Bundle b: framework.getBundleContext().getBundles()) {
- if (symbolicName.equals(b.getSymbolicName()) && versionMatcher.apply(b.getVersion())) {
+ public BundleFinder symbolicName(String symbolicName) {
+ this.symbolicName = symbolicName;
+ return this;
+ }
+
+ public BundleFinder version(String version) {
+ this.version = version;
+ return this;
+ }
+
+ public BundleFinder id(String symbolicNameOptionallyWithVersion) {
+ if (Strings.isBlank(symbolicNameOptionallyWithVersion))
+ return this;
+
+ Maybe<String[]> partsM = parseOsgiIdentifier(symbolicNameOptionallyWithVersion);
+ if (partsM.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 this;
+ }
+
+ /** Looks for a bundle matching the given URL;
+ * unlike {@link #requiringFromUrl(String)} however, if the URL does not match any bundles
+ * it will return other matching bundles <i>if</if> a {@link #symbolicName(String)} is specified.
+ */
+ public BundleFinder preferringFromUrl(String url) {
+ this.url = url;
+ urlMandatory = false;
+ return this;
+ }
+
+ /** Requires the bundle to have the given URL set as its location. */
+ public BundleFinder requiringFromUrl(String url) {
+ this.url = url;
+ urlMandatory = true;
+ return this;
+ }
+
+ /** Finds the best matching bundle. */
+ public Maybe<Bundle> find() {
+ return findOne(false);
+ }
+
+ /** Finds the matching bundle, requiring it to be unique. */
+ public Maybe<Bundle> findUnique() {
+ return findOne(true);
+ }
+
+ protected Maybe<Bundle> findOne(boolean requireExactlyOne) {
+ if (symbolicName==null && url==null)
+ throw new IllegalStateException(this+" must be given either a symbolic name or a URL");
+
+ List<Bundle> result = findAll();
+ if (result.isEmpty())
+ return Maybe.absent("No bundle matching "+getConstraintsDescription());
+ if (requireExactlyOne && result.size()>1)
+ return Maybe.absent("Multiple bundles ("+result.size()+") matching "+getConstraintsDescription());
+
+ return Maybe.of(result.get(0));
+ }
+
+ /** Finds all matching bundles, in decreasing version order. */
+ public List<Bundle> findAll() {
+ boolean urlMatched = false;
+ List<Bundle> result = MutableList.of();
+ for (Bundle b: framework.getBundleContext().getBundles()) {
+ if (symbolicName!=null && !symbolicName.equals(b.getSymbolicName())) continue;
+ if (version!=null && !Version.parseVersion(version).equals(b.getVersion())) continue;
+ for (Predicate<? super Bundle> predicate: predicates) {
+ if (!predicate.apply(b)) continue;
+ }
+
+ // check url last, because if it isn't mandatory we should only clear if we find a url
+ // for which the other items also match
+ if (url!=null) {
+ boolean matches = url.equals(b.getLocation());
+ if (urlMandatory) {
+ if (!matches) continue;
+ } else {
+ if (matches) {
+ if (!urlMatched) {
+ result.clear();
+ urlMatched = true;
+ }
+ } else {
+ if (urlMatched) {
+ // can't use this bundle as we have previously found a preferred bundle, with a matching url
+ continue;
+ }
+ }
+ }
+ }
+
result.add(b);
}
+
+ if (symbolicName==null && url!=null && !urlMatched) {
+ // if we only "preferred" the url, and we did not match it, and we did not have a symbolic name,
+ // then clear the results list!
+ result.clear();
+ }
+
+ Collections.sort(result, new Comparator<Bundle>() {
+ @Override
+ public int compare(Bundle o1, Bundle o2) {
+ return o2.getVersion().compareTo(o1.getVersion());
+ }
+ });
+
+ return result;
+ }
+
+ public String getConstraintsDescription() {
+ List<String> parts = MutableList.of();
+ if (symbolicName!=null) parts.add("symbolicName="+symbolicName);
+ if (version!=null) parts.add("version="+version);
+ if (url!=null)
+ parts.add("url["+(urlMandatory ? "required" : "preferred")+"]="+url);
+ if (!predicates.isEmpty())
+ parts.add("predicates="+predicates);
+ return Joiner.on(";").join(parts);
+ }
+
+ public String toString() {
+ return getClass().getCanonicalName()+"["+getConstraintsDescription()+"]";
+ }
+
+ public BundleFinder version(final Predicate<Version> versionPredicate) {
+ return satisfying(new Predicate<Bundle>() {
+ @Override
+ public boolean apply(Bundle input) {
+ return versionPredicate.apply(input.getVersion());
+ }
+ });
+ }
+
+ public BundleFinder satisfying(Predicate<? super Bundle> predicate) {
+ predicates.add(predicate);
+ return this;
}
- return result;
+ }
+
+ public static BundleFinder bundleFinder(Framework framework) {
+ return new BundleFinder(framework);
+ }
+
+ /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
+ public static List<Bundle> getBundlesByName(Framework framework, String symbolicName, Predicate<Version> versionMatcher) {
+ return bundleFinder(framework).symbolicName(symbolicName).version(versionMatcher).findAll();
}
+ /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
public static List<Bundle> getBundlesByName(Framework framework, String symbolicName) {
- return getBundlesByName(framework, symbolicName, Predicates.<Version>alwaysTrue());
+ return bundleFinder(framework).symbolicName(symbolicName).findAll();
}
/**
* Tries to find a bundle in the given framework with name matching either `name' or `name:version'.
- */
+ * @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
public static Maybe<Bundle> getBundle(Framework framework, String symbolicNameOptionallyWithVersion) {
- String[] parts = symbolicNameOptionallyWithVersion.split(":");
- Maybe<Bundle> result = Maybe.absent("No bundles matching "+symbolicNameOptionallyWithVersion);
- if (parts.length == 2) {
- result = getBundle(framework, parts[0], parts[1]);
- } else if (parts.length == 1) {
- // TODO: Select latest version rather than first result
- List<Bundle> matches = getBundlesByName(framework, symbolicNameOptionallyWithVersion);
- if (!matches.isEmpty()) {
- result = Maybe.of(matches.iterator().next());
- }
- } else {
- throw new IllegalArgumentException("Cannot parse symbolic-name:version string '"+symbolicNameOptionallyWithVersion+"'");
- }
- return result;
+ return bundleFinder(framework).id(symbolicNameOptionallyWithVersion).find();
}
+ /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
public static Maybe<Bundle> getBundle(Framework framework, String symbolicName, String version) {
- return getBundle(framework, symbolicName, Version.parseVersion(version));
+ return bundleFinder(framework).symbolicName(symbolicName).version(version).find();
}
+ /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
public static Maybe<Bundle> getBundle(Framework framework, String symbolicName, Version version) {
- List<Bundle> matches = getBundlesByName(framework, symbolicName, Predicates.equalTo(version));
- if (matches.isEmpty()) {
- return Maybe.absent("No bundles matching name=" + symbolicName + " version=" + version);
- } else if (matches.size() > 1) {
- LOG.warn("More than one bundle in framework={} matched name={}, version={}! Returning first of matches={}",
- new Object[]{framework, symbolicName, version, Joiner.on(", ").join(matches)});
- }
- return Maybe.of(matches.iterator().next());
+ return bundleFinder(framework).symbolicName(symbolicName).version(Predicates.equalTo(version)).findUnique();
}
// -------- creating
@@ -168,6 +316,7 @@ public class Osgis {
Map<Object,Object> cfg = MutableMap.copyOf(extraStartupConfig);
if (clean) cfg.put(Constants.FRAMEWORK_STORAGE_CLEAN, "onFirstInit");
if (felixCacheDir!=null) cfg.put(Constants.FRAMEWORK_STORAGE, felixCacheDir);
+ cfg.put(Constants.FRAMEWORK_BSNVERSION, Constants.FRAMEWORK_BSNVERSION_MULTIPLE);
FrameworkFactory factory = newFrameworkFactory();
Stopwatch timer = Stopwatch.createStarted();
@@ -180,12 +329,14 @@ public class Osgis {
// framework bundle start exceptions are not interesting to caller...
throw Exceptions.propagate(e);
}
+ LOG.debug("System bundles are: "+SYSTEM_BUNDLES);
LOG.debug("OSGi framework started in " + Duration.of(timer));
-
return framework;
}
private static void installBootBundles(Framework framework) {
+ Stopwatch timer = Stopwatch.createStarted();
+ LOG.debug("Installing OSGi boot bundles from "+Osgis.class.getClassLoader()+"...");
Enumeration<URL> resources;
try {
resources = Osgis.class.getClassLoader().getResources(MANIFEST_PATH);
@@ -193,29 +344,32 @@ public class Osgis {
throw Exceptions.propagate(e);
}
BundleContext bundleContext = framework.getBundleContext();
- Map<String, Bundle> installedBundles = getInstalledBundles(bundleContext);
+ Map<String, Bundle> installedBundles = getInstalledBundlesById(bundleContext);
while(resources.hasMoreElements()) {
URL url = resources.nextElement();
- ReferenceWithError<Boolean> installResult = installExtensionBundle(bundleContext, url, installedBundles, getVersionedId(framework));
- if (installResult.hasError()) {
- if (installResult.getWithoutError()) {
- // true return code means it was installed or trivially not installed
- if (LOG.isTraceEnabled())
- LOG.trace(installResult.getError().getMessage());
- } else {
- if (installResult.masksErrorIfPresent()) {
- // if error is masked, then it's not so important (many of the bundles we are looking at won't have manifests)
- LOG.debug(installResult.getError().getMessage());
+ ReferenceWithError<?> installResult = installExtensionBundle(bundleContext, url, installedBundles, getVersionedId(framework));
+ if (installResult.hasError() && !installResult.masksErrorIfPresent()) {
+ // it's reported as a critical error, so warn here
+ LOG.warn("Unable to install manifest from "+url+": "+installResult.getError(), installResult.getError());
+ } else {
+ Object result = installResult.getWithoutError();
+ if (result instanceof Bundle) {
+ String v = getVersionedId( (Bundle)result );
+ SYSTEM_BUNDLES.add(v);
+ if (installResult.hasError()) {
+ LOG.debug(installResult.getError().getMessage()+(result!=null ? " ("+result+"/"+v+")" : ""));
} else {
- // it's reported as a critical error, so warn here
- LOG.warn("Unable to install manifest from "+url+": "+installResult.getError(), installResult.getError());
+ LOG.debug("Installed "+v+" from "+url);
}
+ } else if (installResult.hasError()) {
+ LOG.debug(installResult.getError().getMessage());
}
}
}
+ LOG.debug("Installed OSGi boot bundles in "+Time.makeTimeStringRounded(timer)+": "+Arrays.asList(framework.getBundleContext().getBundles()));
}
- private static Map<String, Bundle> getInstalledBundles(BundleContext bundleContext) {
+ private static Map<String, Bundle> getInstalledBundlesById(BundleContext bundleContext) {
Map<String, Bundle> installedBundles = new HashMap<String, Bundle>();
Bundle[] bundles = bundleContext.getBundles();
for (Bundle b : bundles) {
@@ -224,15 +378,21 @@ public class Osgis {
return installedBundles;
}
- private static ReferenceWithError<Boolean> installExtensionBundle(BundleContext bundleContext, URL manifestUrl, Map<String, Bundle> installedBundles, String frameworkVersionedId) {
+ /** Wraps the bundle if successful or already installed, wraps TRUE if it's the system entry,
+ * wraps null if the bundle is already installed from somewhere else;
+ * in all these cases <i>masking</i> an explanatory error if already installed or it's the system entry.
+ * <p>
+ * Returns an instance wrapping null and <i>throwing</i> an error if the bundle could not be installed.
+ */
+ private static ReferenceWithError<?> installExtensionBundle(BundleContext bundleContext, URL manifestUrl, Map<String, Bundle> installedBundles, String frameworkVersionedId) {
//ignore http://felix.extensions:9/ system entry
if("felix.extensions".equals(manifestUrl.getHost()))
- return ReferenceWithError.newInstanceMaskingError(true, new IllegalArgumentException("Skiping install of internal extension bundle from "+manifestUrl));
+ return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Skipping install of internal extension bundle from "+manifestUrl));
try {
Manifest manifest = readManifest(manifestUrl);
if (!isValidBundle(manifest))
- return ReferenceWithError.newInstanceMaskingError(false, new IllegalArgumentException("Resource at "+manifestUrl+" is not an OSGi bundle: no valid manifest"));
+ return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Resource at "+manifestUrl+" is not an OSGi bundle: no valid manifest"));
String versionedId = getVersionedId(manifest);
URL bundleUrl = ResourceUtils.getContainerUrl(manifestUrl, MANIFEST_PATH);
@@ -242,9 +402,9 @@ public class Osgis {
if (!bundleUrl.equals(existingBundle.getLocation()) &&
//the framework bundle is always pre-installed, don't display duplicate info
!versionedId.equals(frameworkVersionedId)) {
- return ReferenceWithError.newInstanceMaskingError(false, new IllegalArgumentException("Bundle "+versionedId+" (from manifest " + manifestUrl + ") is already installed, from " + existingBundle.getLocation()));
+ return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Bundle "+versionedId+" (from manifest " + manifestUrl + ") is already installed, from " + existingBundle.getLocation()));
}
- return ReferenceWithError.newInstanceMaskingError(true, new IllegalArgumentException("Bundle "+versionedId+" from manifest " + manifestUrl + " is already installed"));
+ return ReferenceWithError.newInstanceMaskingError(existingBundle, new IllegalArgumentException("Bundle "+versionedId+" from manifest " + manifestUrl + " is already installed"));
}
byte[] jar = buildExtensionBundle(manifest);
@@ -253,10 +413,10 @@ public class Osgis {
//(since we cannot access BundleImpl.isExtension)
Bundle newBundle = bundleContext.installBundle(EXTENSION_PROTOCOL + ":" + bundleUrl.toString(), new ByteArrayInputStream(jar));
installedBundles.put(versionedId, newBundle);
- return ReferenceWithError.newInstanceWithoutError(true);
+ return ReferenceWithError.newInstanceWithoutError(newBundle);
} catch (Exception e) {
Exceptions.propagateIfFatal(e);
- return ReferenceWithError.newInstanceThrowingError(false,
+ return ReferenceWithError.newInstanceThrowingError(null,
new IllegalStateException("Problem installing extension bundle " + manifestUrl + ": "+e, e));
}
}
@@ -364,10 +524,11 @@ public class Osgis {
return bundle;
}
- //Note that in OSGi 4.3+ it could be possible to have the same version installed
- //multiple times in more advanced scenarios. In our case we don't support it.
+ // We now support same version installed multiple times (avail since OSGi 4.3+).
+ // However we do not support overriding *system* bundles, ie anything already on the classpath.
+ // If we wanted to disable multiple versions, see comments below, and reference to FRAMEWORK_BSNVERSION_MULTIPLE above.
- //Felix already assumes the stream is pointing to a Jar
+ // Felix already assumes the stream is pointing to a JAR
JarInputStream stream;
try {
stream = new JarInputStream(getUrlStream(url));
@@ -379,7 +540,15 @@ public class Osgis {
String versionedId = getVersionedId(manifest);
for (Bundle installedBundle : framework.getBundleContext().getBundles()) {
if (versionedId.equals(getVersionedId(installedBundle))) {
- return installedBundle;
+ if (SYSTEM_BUNDLES.contains(versionedId)) {
+ LOG.debug("Already have system bundle "+versionedId+" from "+installedBundle+"/"+installedBundle.getLocation()+" when requested "+url+"; not installing");
+ // "System bundles" (ie things on the classpath) cannot be overridden
+ return installedBundle;
+ } else {
+ LOG.debug("Already have bundle "+versionedId+" from "+installedBundle+"/"+installedBundle.getLocation()+" when requested "+url+"; but it is not a system bundle so proceeding");
+ // Other bundles can be installed multiple times. To ignore multiples and continue to use the old one,
+ // just return the installedBundle as done just above for system bundles.
+ }
}
}
return null;
@@ -395,6 +564,25 @@ public class Osgis {
EXTENSION_PROTOCOL.equals(Urls.getProtocol(location));
}
+ /** 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) {
+ if (Strings.isBlank(symbolicNameOptionalWithVersion))
+ return Maybe.absent("OSGi identifier is blank");
+
+ String[] parts = symbolicNameOptionalWithVersion.split(":");
+ if (parts.length>2)
+ return Maybe.absent("OSGi identifier has too many parts; max one ':' symbol");
+
+ try {
+ Version.parseVersion(parts[1]);
+ } catch (IllegalArgumentException e) {
+ return Maybe.absent("OSGi identifier has invalid version string");
+ }
+
+ return Maybe.of(parts);
+ }
/**
* The class is not used, staying for future reference.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/pom.xml
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/pom.xml b/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/pom.xml
new file mode 100644
index 0000000..28655c2
--- /dev/null
+++ b/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/pom.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <packaging>jar</packaging>
+
+ <groupId>org.apache.brooklyn.test.resources.osgi.evil_twin</groupId>
+ <artifactId>brooklyn-test-osgi-more-entities</artifactId>
+ <version>0.2.0</version>
+
+ <name>OSGi bundled test entities</name>
+
+ <description>
+ Simple entities for testing the OSGi functionality
+ </description>
+
+ <parent>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-parent</artifactId>
+ <version>0.7.0-SNAPSHOT</version><!-- BROOKLYN_VERSION -->
+ <relativePath>../../../../../../pom.xml</relativePath>
+ </parent>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-core</artifactId>
+ <version>${brooklyn.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-api</artifactId>
+ <version>${brooklyn.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn</groupId>
+ <artifactId>brooklyn-utils-common</artifactId>
+ <version>${brooklyn.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.brooklyn.test.resources.osgi</groupId>
+ <artifactId>brooklyn-test-osgi-entities</artifactId>
+ <version>0.1.0</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <outputDirectory>../../../resources/brooklyn/osgi</outputDirectory>
+ <finalName>brooklyn-test-osgi-more-entities_evil-twin_${version}</finalName>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.5.3</version>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>org.apache.brooklyn.test.resources.osgi.brooklyn-test-osgi-more-entities</Bundle-SymbolicName>
+ <Bundle-Version>${project.version}</Bundle-Version>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java b/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java
new file mode 100644
index 0000000..553cbc5
--- /dev/null
+++ b/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntity.java
@@ -0,0 +1,38 @@
+/*
+ * 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.osgi.tests.more;
+
+
+import brooklyn.entity.Effector;
+import brooklyn.entity.Entity;
+import brooklyn.entity.effector.Effectors;
+import brooklyn.entity.proxying.ImplementedBy;
+
+@ImplementedBy(MoreEntityImpl.class)
+public interface MoreEntity extends Entity {
+
+ public static final Effector<String> SAY_HI = Effectors.effector(String.class, "sayHI")
+ .description("says HO to an uppercased name")
+ .parameter(String.class, "name")
+ .buildAbstract();
+
+ /** Makes a string saying HO to the given name, in contrast to v1 and v2. */
+ String sayHI(String name);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java b/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
new file mode 100644
index 0000000..2788b8b
--- /dev/null
+++ b/core/src/test/dependencies/osgi/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.osgi.tests.more;
+
+import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.effector.EffectorBody;
+import brooklyn.policy.PolicySpec;
+import brooklyn.util.config.ConfigBag;
+
+
+public class MoreEntityImpl extends AbstractEntity implements MoreEntity {
+
+ /** Unlike v1, this declares an explicit dependency on SimplePolicy */
+ @Override
+ public void init() {
+ super.init();
+ getMutableEntityType().addEffector(SAY_HI, new EffectorBody<String>() {
+ @Override
+ public String call(ConfigBag parameters) {
+ return sayHI((String)parameters.getStringKey("name"));
+ }
+ });
+ addPolicy(PolicySpec.create(brooklyn.osgi.tests.SimplePolicy.class));
+ }
+
+ /** Returns HO instead of HI (like v2 non-evil twin) or Hi (like v1) */
+ public String sayHI(String name) {
+ return "HO "+name.toUpperCase();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java b/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java
index dcefbcc..80b41d5 100644
--- a/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java
+++ b/core/src/test/java/brooklyn/catalog/internal/CatalogItems.java
@@ -18,6 +18,8 @@
*/
package brooklyn.catalog.internal;
+import com.google.common.annotations.Beta;
+
import io.brooklyn.camp.spi.pdp.DeploymentPlan;
/** Only for internal use / use in tests. */
@@ -41,6 +43,12 @@ public class CatalogItems {
return target;
}
+ // TODO just added this method to expose registeredTypeName for tests; but it should all go away;
+ // so long as tests pass no need to keep deprecation imho
+ @Beta
+ public static CatalogEntityItemDto newEntityFromJavaWithRegisteredTypeName(String registeredTypeName, String javaType) {
+ return set(new CatalogEntityItemDto(), registeredTypeName, javaType, registeredTypeName, null, null);
+ }
public static CatalogEntityItemDto newEntityFromJava(String javaType, String name) {
return newEntityFromJava(javaType, name, null, null);
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java b/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java
index de889be..48d01dc 100644
--- a/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java
+++ b/core/src/test/java/brooklyn/management/osgi/OsgiTestResources.java
@@ -28,6 +28,7 @@ package brooklyn.management.osgi;
*/
public class OsgiTestResources {
+
/**
* brooklyn-osgi-test-a_0.1.0 -
* defines TestA which has a "times" method and a static multiplier field;
@@ -48,7 +49,10 @@ public class OsgiTestResources {
* another bundle with a minimal sayHi effector, used to test versioning and dependencies
* (this one has no dependencies, but see also {@value #BROOKLYN_TEST_MORE_ENTITIES_V2_PATH})
*/
- public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_PATH = "/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.1.0.jar";
+ public static final String BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART = "brooklyn-test-osgi-more-entities";
+ public static final String BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL =
+ "org.apache.brooklyn.test.resources.osgi."+BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART;
+ public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_PATH = "/brooklyn/osgi/" + BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_0.1.0.jar";
public static final String BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY = "brooklyn.osgi.tests.more.MoreEntity";
/**
@@ -56,6 +60,14 @@ public class OsgiTestResources {
* similar to {@link #BROOKLYN_TEST_MORE_ENTITIES_V1_PATH} but saying "HI NAME" rather than "Hi NAME",
* and declaring an explicit dependency on SimplePolicy from {@link #BROOKLYN_TEST_OSGI_ENTITIES_PATH}
*/
- public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_PATH = "/brooklyn/osgi/brooklyn-test-osgi-more-entities_0.2.0.jar";
+ public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_PATH = "/brooklyn/osgi/" + BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_0.2.0.jar";
+
+ /**
+ * bundle with identical metadata (same symbolic name and version -- hence being an evil twin)
+ * as {@link #BROOKLYN_TEST_MORE_ENTITIES_V2_PATH},
+ * but slightly different behaviour -- saying "HO NAME" -- in order to make sure we can differentiate two two
+ * at runtime.
+ */
+ public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH = "/brooklyn/osgi/" + BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FINAL_PART + "_evil-twin_0.2.0.jar";
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java b/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
index c5df30d..4b653ab 100644
--- a/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
+++ b/core/src/test/java/brooklyn/management/osgi/OsgiVersionMoreEntityTest.java
@@ -21,6 +21,7 @@ package brooklyn.management.osgi;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.util.List;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
@@ -46,6 +47,7 @@ import brooklyn.management.internal.ManagementContextInternal;
import brooklyn.policy.PolicySpec;
import brooklyn.test.entity.LocalManagementContextForTests;
import brooklyn.test.entity.TestApplication;
+import brooklyn.util.guava.Maybe;
import brooklyn.util.os.Os;
import brooklyn.util.osgi.Osgis;
@@ -66,6 +68,8 @@ public class OsgiVersionMoreEntityTest {
public static final String BROOKLYN_TEST_MORE_ENTITIES_V1_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V1_PATH;
public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_PATH = OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V2_PATH;
public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V2_PATH;
+ public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH = OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH;
+ public static final String BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_URL = "classpath:"+BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_PATH;
protected LocalManagementContext mgmt;
protected TestApplication app;
@@ -115,17 +119,23 @@ public class OsgiVersionMoreEntityTest {
}
}
+ protected CatalogItem<?, ?> addCatalogItemWithTypeAsName(String type, String ...libraries) {
+ return addCatalogItemWithNameAndType(type, type, libraries);
+ }
@SuppressWarnings("deprecation")
- protected CatalogItem<?, ?> addCatalogItem(String type, String ...libraries) {
- CatalogEntityItemDto c1 = newCatalogItem(type, libraries);
+ protected CatalogItem<?, ?> addCatalogItemWithNameAndType(String symName, String type, String ...libraries) {
+ CatalogEntityItemDto c1 = newCatalogItemWithNameAndType(symName, type, libraries);
mgmt.getCatalog().addItem(c1);
CatalogItem<?, ?> c2 = mgmt.getCatalog().getCatalogItem(type);
return c2;
}
- static CatalogEntityItemDto newCatalogItem(String type, String ...libraries) {
- CatalogEntityItemDto c1 = CatalogItems.newEntityFromJava(type, type);
- c1.setCatalogItemId(type);
+ static CatalogEntityItemDto newCatalogItemWithTypeAsName(String type, String ...libraries) {
+ return newCatalogItemWithNameAndType(type, type, libraries);
+ }
+ static CatalogEntityItemDto newCatalogItemWithNameAndType(String symName, String type, String ...libraries) {
+ CatalogEntityItemDto c1 = CatalogItems.newEntityFromJavaWithRegisteredTypeName(symName, type);
+ c1.setCatalogItemId(symName);
for (String library: libraries)
c1.getLibrariesDto().addBundle(library);
return c1;
@@ -149,6 +159,9 @@ public class OsgiVersionMoreEntityTest {
public static void assertV2MethodCall(Entity me) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Assert.assertEquals(doMethodCallBrooklyn(me), "HI BROOKLYN");
}
+ public static void assertV2EvilTwinMethodCall(Entity me) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+ Assert.assertEquals(doMethodCallBrooklyn(me), "HO BROOKLYN");
+ }
public static Object doMethodCallBrooklyn(Entity me) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
return me.getClass().getMethod("sayHI", String.class).invoke(me, "Brooklyn");
@@ -160,6 +173,9 @@ public class OsgiVersionMoreEntityTest {
public static void assertV2EffectorCall(Entity me) {
Assert.assertEquals(doEffectorCallBrooklyn(me), "HI BROOKLYN");
}
+ public static void assertV2EvilTwinEffectorCall(Entity me) {
+ Assert.assertEquals(doEffectorCallBrooklyn(me), "HO BROOKLYN");
+ }
public static String doEffectorCallBrooklyn(Entity me) {
return me.invoke(Effectors.effector(String.class, "sayHI").buildAbstract(), ImmutableMap.of("name", "brooklyn")).getUnchecked();
@@ -167,7 +183,7 @@ public class OsgiVersionMoreEntityTest {
@Test
public void testMoreEntitiesV1() throws Exception {
- CatalogItem<?, ?> c2 = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
+ CatalogItem<?, ?> c2 = addCatalogItemWithTypeAsName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
// test load and instantiate
Entity me = addItemFromCatalog(c2);
@@ -193,12 +209,12 @@ public class OsgiVersionMoreEntityTest {
@Test
public void testMoreEntitiesV1Policy() throws Exception {
- CatalogItem<?, ?> c2 = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
+ CatalogItem<?, ?> c2 = addCatalogItemWithTypeAsName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY, BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
// test load and instantiate
Entity me = addItemFromCatalog(c2);
- CatalogItem<?, ?> cp = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_POLICY,
+ CatalogItem<?, ?> cp = addCatalogItemWithTypeAsName(OsgiTestResources.BROOKLYN_TEST_OSGI_ENTITIES_SIMPLE_POLICY,
BROOKLYN_TEST_OSGI_ENTITIES_URL);
me.addPolicy(getPolicySpec(cp));
@@ -213,7 +229,7 @@ public class OsgiVersionMoreEntityTest {
@Test
public void testMoreEntitiesV2FailsWithoutBasicTestOsgiEntitiesBundle() throws Exception {
- CatalogItem<?, ?> c2 = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+ CatalogItem<?, ?> c2 = addCatalogItemWithTypeAsName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
BROOKLYN_TEST_MORE_ENTITIES_V2_URL);
// test load and instantiate
@@ -231,7 +247,7 @@ public class OsgiVersionMoreEntityTest {
// and has policy, with policy item catalog ID is reasonable
@Test
public void testMoreEntitiesV2() throws Exception {
- CatalogItem<?, ?> c2 = addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+ CatalogItem<?, ?> c2 = addCatalogItemWithTypeAsName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
BROOKLYN_TEST_MORE_ENTITIES_V2_URL, BROOKLYN_TEST_OSGI_ENTITIES_URL);
// test load and instantiate
@@ -250,9 +266,9 @@ public class OsgiVersionMoreEntityTest {
@Test
public void testMoreEntitiesV1ThenV2GivesV2() throws Exception {
- addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+ addCatalogItemWithTypeAsName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
- addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+ addCatalogItemWithTypeAsName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
BROOKLYN_TEST_MORE_ENTITIES_V2_URL, BROOKLYN_TEST_OSGI_ENTITIES_URL);
// test load and instantiate
@@ -265,9 +281,9 @@ public class OsgiVersionMoreEntityTest {
@Test
public void testMoreEntitiesV2ThenV1GivesV1() throws Exception {
- addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+ addCatalogItemWithTypeAsName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
BROOKLYN_TEST_MORE_ENTITIES_V2_URL, BROOKLYN_TEST_OSGI_ENTITIES_URL);
- addCatalogItem(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+ addCatalogItemWithTypeAsName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
// test load and instantiate
@@ -301,18 +317,64 @@ public class OsgiVersionMoreEntityTest {
Assert.assertEquals(me.getPolicies().size(), 0, "Wrong number of policies: "+me.getPolicies());
}
- // TODO test YAML for many of the above (in the camp project CAMP, using other code below)
-
+ @Test
+ public void testUnfazedByMoreEntitiesV1AndV2AndV2EvilTwin() throws Exception {
+ addCatalogItemWithNameAndType("v1", OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+ BROOKLYN_TEST_MORE_ENTITIES_V1_URL);
+ addCatalogItemWithNameAndType("v2", OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+ BROOKLYN_TEST_MORE_ENTITIES_V2_URL, BROOKLYN_TEST_OSGI_ENTITIES_URL);
+ addCatalogItemWithNameAndType("v2-evil", OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY,
+ BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_URL, BROOKLYN_TEST_OSGI_ENTITIES_URL);
+
+ // test osgi finding
+
+ List<Bundle> bundles = Osgis.bundleFinder(mgmt.getOsgiManager().get().getFramework())
+ .symbolicName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL).findAll();
+ Assert.assertEquals(bundles.size(), 3, "Wrong list of bundles: "+bundles);
+
+ Maybe<Bundle> preferredVersion = Osgis.bundleFinder(mgmt.getOsgiManager().get().getFramework())
+ .symbolicName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL).find();
+ Assert.assertTrue(preferredVersion.isPresent());
+ Assert.assertEquals(preferredVersion.get().getVersion().toString(), "0.2.0");
+
+ Maybe<Bundle> evilVersion = Osgis.bundleFinder(mgmt.getOsgiManager().get().getFramework()).
+ preferringFromUrl(BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_URL).find();
+ Assert.assertTrue(evilVersion.isPresent());
+ Assert.assertEquals(evilVersion.get().getVersion().toString(), "0.2.0");
+
+ // test preferredUrl vs requiredUrl
+
+ Maybe<Bundle> versionIgnoresInvalidPreferredUrl = Osgis.bundleFinder(mgmt.getOsgiManager().get().getFramework())
+ .symbolicName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL)
+ .version("0.1.0")
+ .preferringFromUrl(BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_URL).find();
+ Assert.assertTrue(versionIgnoresInvalidPreferredUrl.isPresent());
+ Assert.assertEquals(versionIgnoresInvalidPreferredUrl.get().getVersion().toString(), "0.1.0");
+
+ Maybe<Bundle> versionRespectsInvalidRequiredUrl = Osgis.bundleFinder(mgmt.getOsgiManager().get().getFramework())
+ .symbolicName(OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_SYMBOLIC_NAME_FULL)
+ .version("0.1.0")
+ .requiringFromUrl(BROOKLYN_TEST_MORE_ENTITIES_V2_EVIL_TWIN_URL).find();
+ Assert.assertFalse(versionRespectsInvalidRequiredUrl.isPresent());
+
+ // test entity resolution
+
+ Entity v2 = addItemFromCatalog( mgmt.getCatalog().getCatalogItem("v2") );
+ assertV2MethodCall(v2);
+ assertV2EffectorCall(v2);
+ Assert.assertEquals(v2.getPolicies().size(), 1, "Wrong number of policies: "+v2.getPolicies());
+
+ Entity v2_evil = addItemFromCatalog( mgmt.getCatalog().getCatalogItem("v2-evil") );
+ assertV2EvilTwinMethodCall(v2_evil);
+ assertV2EvilTwinEffectorCall(v2_evil);
+ Assert.assertEquals(v2_evil.getPolicies().size(), 1, "Wrong number of policies: "+v2_evil.getPolicies());
+
+ Entity v1 = addItemFromCatalog( mgmt.getCatalog().getCatalogItem("v1") );
+ assertV1MethodCall(v1);
+ assertV1EffectorCall(v1);
+ Assert.assertEquals(v1.getPolicies().size(), 0, "Wrong number of policies: "+v1.getPolicies());
+ }
+
// TODO versioning (WIP until #92), install both V1 and V2 with version number, and test that both work
-
- // TODO other code which might be useful - but requires CAMP:
-// mgmt.getCatalog().addItem(Strings.lines(
-// "brooklyn.catalog:",
-// " id: my-entity",
-// "brooklyn.library:",
-// "- url: "+BROOKLYN_TEST_MORE_ENTITIES_V1_URL,
-// "services:",
-// "- type: "+OsgiTestResources.BROOKLYN_TEST_MORE_ENTITIES_MORE_ENTITY
-// ));
-
+
}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar
new file mode 100644
index 0000000..2d52340
Binary files /dev/null and b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.jar differ
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.txt
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.txt b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.txt
new file mode 100644
index 0000000..9597d3b
--- /dev/null
+++ b/core/src/test/resources/brooklyn/osgi/brooklyn-test-osgi-more-entities_evil-twin_0.2.0.txt
@@ -0,0 +1,21 @@
+# 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.
+
+The file brooklyn-test-osgi-entities.jar is for testing a deployment of
+an OSGi bundle containing entities.
+
+The source is in core/src/test/dependencies/osgi/more-entities-v2-evil-twin
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/72b29b95/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java b/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
index 2ffe119..bd52b3f 100644
--- a/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
+++ b/utils/common/src/main/java/brooklyn/util/exceptions/ReferenceWithError.java
@@ -93,5 +93,9 @@ public class ReferenceWithError<T> implements Supplier<T> {
public boolean hasError() {
return error!=null;
}
-
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName()+"["+object+(error!=null?"/"+(maskError?"masking:":"throwing:")+error:"")+"]";
+ }
}
[2/2] incubator-brooklyn git commit: This closes #307
Posted by he...@apache.org.
This closes #307
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/dc53cec5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/dc53cec5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/dc53cec5
Branch: refs/heads/master
Commit: dc53cec5db859c30a05e397b69f4c71230d5840b
Parents: 3cfda7e 72b29b9
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Nov 11 01:52:33 2014 +0000
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Nov 11 01:52:33 2014 +0000
----------------------------------------------------------------------
.../brooklyn/management/ha/OsgiManager.java | 78 +++--
.../main/java/brooklyn/util/ResourceUtils.java | 2 +-
.../src/main/java/brooklyn/util/osgi/Osgis.java | 300 +++++++++++++++----
.../osgi/more-entities-v2-evil-twin/pom.xml | 88 ++++++
.../brooklyn/osgi/tests/more/MoreEntity.java | 38 +++
.../osgi/tests/more/MoreEntityImpl.java | 47 +++
.../brooklyn/catalog/internal/CatalogItems.java | 8 +
.../management/osgi/OsgiTestResources.java | 16 +-
.../osgi/OsgiVersionMoreEntityTest.java | 116 +++++--
...-test-osgi-more-entities_evil-twin_0.2.0.jar | Bin 0 -> 12757 bytes
...-test-osgi-more-entities_evil-twin_0.2.0.txt | 21 ++
.../util/exceptions/ReferenceWithError.java | 6 +-
12 files changed, 601 insertions(+), 119 deletions(-)
----------------------------------------------------------------------