diff --git a/core/pom.xml b/core/pom.xml
index 45c91918b9..be19d53667 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -39,7 +39,10 @@
- *
+
+ org.nnsoft.guice.rocoto*;version="[6.1,7)",
+ *
+
org.jclouds*;version=${project.version};-noimport:=true
org.jclouds.osgi.Activator
diff --git a/core/src/main/java/org/jclouds/osgi/MetadataBundleListener.java b/core/src/main/java/org/jclouds/osgi/MetadataBundleListener.java
index 3f627883a5..d614140d21 100644
--- a/core/src/main/java/org/jclouds/osgi/MetadataBundleListener.java
+++ b/core/src/main/java/org/jclouds/osgi/MetadataBundleListener.java
@@ -19,7 +19,10 @@
package org.jclouds.osgi;
import com.google.common.base.Charsets;
-
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Multimap;
+import com.google.common.io.Closeables;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.apis.ApiRegistry;
import org.jclouds.providers.ProviderMetadata;
@@ -33,8 +36,8 @@ import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Collection;
+import java.util.List;
/**
* A {@link BundleListener} that listens for {@link BundleEvent} and searches for {@link org.jclouds.providers.ProviderMetadata} and {@link org.jclouds.apis.ApiMetadata} in newly
@@ -43,168 +46,183 @@ import java.util.Map;
*/
public class MetadataBundleListener implements BundleListener {
- private Map providerMetadataMap = new HashMap();
- private Map apiMetadataMap = new HashMap();
+ private Multimap providerMetadataMap = ArrayListMultimap.create();
+ private Multimap apiMetadataMap = ArrayListMultimap.create();
- public void start(BundleContext bundleContext) {
- bundleContext.addBundleListener(this);
- for (Bundle bundle : bundleContext.getBundles()) {
- if (bundle.getState() == Bundle.ACTIVE) {
- ProviderMetadata providerMetadata = getProviderMetadata(bundle);
- ApiMetadata apiMetadata = getApiMetadata(bundle);
+ public void start(BundleContext bundleContext) {
+ bundleContext.addBundleListener(this);
+ for (Bundle bundle : bundleContext.getBundles()) {
+ if (bundle.getState() == Bundle.ACTIVE) {
+ List providerMetadataList = getProviderMetadata(bundle);
+ List apiMetadataList = getApiMetadata(bundle);
- if (providerMetadata != null) {
- ProviderRegistry.registerProvider(providerMetadata);
- providerMetadataMap.put(bundle.getBundleId(), providerMetadata);
- }
- if (apiMetadata != null) {
- ApiRegistry.registerApi(apiMetadata);
- apiMetadataMap.put(bundle.getBundleId(), apiMetadata);
- }
+ for (ProviderMetadata providerMetadata : providerMetadataList) {
+ if (providerMetadata != null) {
+ ProviderRegistry.registerProvider(providerMetadata);
+ providerMetadataMap.put(bundle.getBundleId(), providerMetadata);
+ }
+ }
+
+ for (ApiMetadata apiMetadata : apiMetadataList) {
+ if (apiMetadata != null) {
+ ApiRegistry.registerApi(apiMetadata);
+ apiMetadataMap.put(bundle.getBundleId(), apiMetadata);
+ }
+ }
+ }
}
- }
- }
+ }
- public void stop(BundleContext bundleContext) {
- providerMetadataMap.clear();
- apiMetadataMap.clear();
- }
+ public void stop(BundleContext bundleContext) {
+ providerMetadataMap.clear();
+ apiMetadataMap.clear();
+ }
- @Override
- public void bundleChanged(BundleEvent event) {
- ProviderMetadata providerMetadata;
- ApiMetadata apiMetadata;
- switch (event.getType()) {
- case BundleEvent.STARTED:
- providerMetadata = getProviderMetadata(event.getBundle());
- apiMetadata = getApiMetadata(event.getBundle());
- if (providerMetadata != null) {
- ProviderRegistry.registerProvider(providerMetadata);
- providerMetadataMap.put(event.getBundle().getBundleId(), providerMetadata);
- }
- if (apiMetadata != null) {
- ApiRegistry.registerApi(apiMetadata);
- apiMetadataMap.put(event.getBundle().getBundleId(), apiMetadata);
- }
- break;
- case BundleEvent.STOPPING:
- case BundleEvent.STOPPED:
- providerMetadata = providerMetadataMap.get(event.getBundle().getBundleId());
- apiMetadata = apiMetadataMap.get(event.getBundle().getBundleId());
- if (providerMetadata != null) {
- ProviderRegistry.unregisterProvider(providerMetadata);
- }
- if (apiMetadata != null) {
- ApiRegistry.unRegisterApi(apiMetadata);
- }
- break;
- }
- }
+ @Override
+ public void bundleChanged(BundleEvent event) {
+ Collection providerMetadataList = null;
+ Collection apiMetadataList = null;
+ switch (event.getType()) {
+ case BundleEvent.STARTED:
+ providerMetadataList = getProviderMetadata(event.getBundle());
+ apiMetadataList = getApiMetadata(event.getBundle());
+ for (ProviderMetadata providerMetadata : providerMetadataList) {
+ if (providerMetadata != null) {
+ ProviderRegistry.registerProvider(providerMetadata);
+ providerMetadataMap.put(event.getBundle().getBundleId(), providerMetadata);
+ }
+ }
+
+ for (ApiMetadata apiMetadata : apiMetadataList) {
+ if (apiMetadata != null) {
+ ApiRegistry.registerApi(apiMetadata);
+ apiMetadataMap.put(event.getBundle().getBundleId(), apiMetadata);
+ }
+ }
+ break;
+ case BundleEvent.STOPPING:
+ case BundleEvent.STOPPED:
+ providerMetadataList = providerMetadataMap.get(event.getBundle().getBundleId());
+ apiMetadataList = apiMetadataMap.get(event.getBundle().getBundleId());
+
+ if (providerMetadataList != null) {
+ for (ProviderMetadata providerMetadata : providerMetadataList) {
+ ProviderRegistry.unregisterProvider(providerMetadata);
+ }
+ }
+ if (apiMetadataList != null) {
+ for (ApiMetadata apiMetadata : apiMetadataList) {
+ ApiRegistry.unRegisterApi(apiMetadata);
+ }
+ }
+ break;
+ }
+ }
+
+ /**
+ * Creates an instance of {@link ProviderMetadata} from the {@link Bundle}.
+ *
+ * @param bundle
+ * @return
+ */
+ public List getProviderMetadata(Bundle bundle) {
+ List metadataList = Lists.newArrayList();
+ String classNames = getProviderMetadataClassNames(bundle);
+ if (classNames != null && !classNames.isEmpty()) {
+ for (String className : classNames.split("\n")) {
+ try {
+ Class extends ProviderMetadata> providerMetadataClass = bundle.loadClass(className);
+ //Classes loaded by other class loaders are not assignable.
+ if (ProviderMetadata.class.isAssignableFrom(providerMetadataClass)) {
+ ProviderMetadata metadata = providerMetadataClass.newInstance();
+ metadataList.add(metadata);
+ }
+ } catch (ClassNotFoundException e) {
+ // ignore
+ } catch (InstantiationException e) {
+ // ignore
+ } catch (IllegalAccessException e) {
+ // ignore
+ }
+ }
+ }
+ return metadataList;
+ }
+
+ /**
+ * Creates an instance of {@link ApiMetadata} from the {@link Bundle}.
+ *
+ * @param bundle
+ * @return
+ */
+ public List getApiMetadata(Bundle bundle) {
+ List metadataList = Lists.newArrayList();
+ String classNames = getApiMetadataClassNames(bundle);
+ if (classNames != null && !classNames.isEmpty()) {
+ for (String className : classNames.split("\n")) {
+ try {
+ Class extends ApiMetadata> apiMetadataClass = bundle.loadClass(className);
+ //Classes loaded by other class loaders are not assignable.
+ if (ApiMetadata.class.isAssignableFrom(apiMetadataClass)) {
+ ApiMetadata metadata = apiMetadataClass.newInstance();
+ metadataList.add(metadata);
+ }
+ } catch (ClassNotFoundException e) {
+ // ignore
+ } catch (InstantiationException e) {
+ // ignore
+ } catch (IllegalAccessException e) {
+ // ignore
+ }
+ }
+ }
+ return metadataList;
+ }
+
+
+ public String getMetadataClassNames(Bundle bundle, String pathToMetadata) {
+ URL resource = bundle.getEntry(pathToMetadata);
+ InputStream is = null;
+ InputStreamReader reader = null;
+ BufferedReader bufferedReader = null;
+ StringBuilder sb = new StringBuilder();
- /**
- * Creates an instance of {@link ProviderMetadata} from the {@link Bundle}.
- *
- * @param bundle
- * @return
- */
- public ProviderMetadata getProviderMetadata(Bundle bundle) {
- ProviderMetadata metadata = null;
- String className = getProviderMetadataClassName(bundle);
- if (className != null && !className.isEmpty()) {
try {
- Class extends ProviderMetadata> providerMetadataClass = bundle.loadClass(className);
- metadata = providerMetadataClass.newInstance();
- } catch (ClassNotFoundException e) {
- // ignore
- } catch (InstantiationException e) {
- // ignore
- } catch (IllegalAccessException e) {
- // ignore
- }
- }
- return metadata;
- }
-
- /**
- * Creates an instance of {@link ApiMetadata} from the {@link Bundle}.
- *
- * @param bundle
- * @return
- */
- public ApiMetadata getApiMetadata(Bundle bundle) {
- ApiMetadata metadata = null;
- String className = getApiMetadataClassName(bundle);
- if (className != null && !className.isEmpty()) {
- try {
- Class extends ApiMetadata> apiMetadataClass = bundle.loadClass(className);
- metadata = apiMetadataClass.newInstance();
- } catch (ClassNotFoundException e) {
- // ignore
- } catch (InstantiationException e) {
- // ignore
- } catch (IllegalAccessException e) {
- // ignore
- }
- }
- return metadata;
- }
-
-
- public String getMetadataClassName(Bundle bundle, String pathToMetadata) {
- URL resource = bundle.getEntry(pathToMetadata);
- InputStream is = null;
- InputStreamReader reader = null;
- BufferedReader bufferedReader = null;
- StringBuilder sb = new StringBuilder();
-
- try {
- is = resource.openStream();
- reader = new InputStreamReader(is, Charsets.UTF_8);
- bufferedReader = new BufferedReader(reader);
- String line;
- while ((line = bufferedReader.readLine()) != null) {
- sb.append(line).append("\n");
- }
- } catch (Throwable e) {
- } finally {
- try {
- if (reader != null)
- reader.close();
- } catch (Throwable e) {
- }
- try {
- if (bufferedReader != null)
- bufferedReader.close();
- } catch (Throwable e) {
- }
- try {
- is.close();
+ is = resource.openStream();
+ reader = new InputStreamReader(is, Charsets.UTF_8);
+ bufferedReader = new BufferedReader(reader);
+ String line;
+ while ((line = bufferedReader.readLine()) != null) {
+ sb.append(line).append("\n");
+ }
} catch (Throwable e) {
+ } finally {
+ Closeables.closeQuietly(reader);
+ Closeables.closeQuietly(bufferedReader);
+ Closeables.closeQuietly(is);
}
+ return sb.toString().trim();
+ }
- }
- return sb.toString().trim();
- }
+ /**
+ * Retrieves the {@link ProviderMetadata} class name for the bundle if it exists.
+ *
+ * @param bundle
+ * @return
+ */
+ public String getProviderMetadataClassNames(Bundle bundle) {
+ return getMetadataClassNames(bundle, "/META-INF/services/org.jclouds.providers.ProviderMetadata");
+ }
- /**
- * Retrieves the {@link ProviderMetadata} class name for the bundle if it exists.
- *
- * @param bundle
- * @return
- */
- public String getProviderMetadataClassName(Bundle bundle) {
- return getMetadataClassName(bundle, "/META-INF/services/org.jclouds.providers.ProviderMetadata");
- }
-
- /**
- * Retrieves the {@link ProviderMetadata} class name for the bundle if it exists.
- *
- * @param bundle
- * @return
- */
- public String getApiMetadataClassName(Bundle bundle) {
- return getMetadataClassName(bundle, "/META-INF/services/org.jclouds.apis.ApiMetadata");
- }
+ /**
+ * Retrieves the {@link ProviderMetadata} class name for the bundle if it exists.
+ *
+ * @param bundle
+ * @return
+ */
+ public String getApiMetadataClassNames(Bundle bundle) {
+ return getMetadataClassNames(bundle, "/META-INF/services/org.jclouds.apis.ApiMetadata");
+ }
}
diff --git a/core/src/test/java/org/jclouds/osgi/MetadataBundleListenerTest.java b/core/src/test/java/org/jclouds/osgi/MetadataBundleListenerTest.java
new file mode 100644
index 0000000000..697877491e
--- /dev/null
+++ b/core/src/test/java/org/jclouds/osgi/MetadataBundleListenerTest.java
@@ -0,0 +1,147 @@
+/**
+ * Licensed to jclouds, Inc. (jclouds) under one or more
+ * contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. jclouds licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.jclouds.osgi;
+
+import org.jclouds.apis.ApiMetadata;
+import org.jclouds.apis.JcloudsTestBlobStoreApiMetadata;
+import org.jclouds.apis.JcloudsTestComputeApiMetadata;
+import org.jclouds.apis.JcloudsTestYetAnotherComputeApiMetadata;
+import org.jclouds.providers.JcloudsTestBlobStoreProviderMetadata;
+import org.jclouds.providers.JcloudsTestComputeProviderMetadata;
+import org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata;
+import org.jclouds.providers.ProviderMetadata;
+import org.osgi.framework.Bundle;
+import org.testng.annotations.Test;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.List;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertNotNull;
+
+
+public class MetadataBundleListenerTest {
+
+ @Test
+ public void testSanity() throws MalformedURLException, ClassNotFoundException {
+ //We are checking here that the class loader we create and use in this test series is indeed different and isolated from our tests classloader.
+ ClassLoader loader = createIsolatedClassLoader();
+ assertFalse(ProviderMetadata.class.isAssignableFrom(loader.loadClass("org.jclouds.providers.JcloudsTestComputeProviderMetadata")));
+ }
+
+
+ @Test
+ public void testGetProviderMetadata() throws Exception {
+ MetadataBundleListener listener = new MetadataBundleListener();
+ Bundle bundle = createMock(Bundle.class);
+ expect(bundle.getEntry("/META-INF/services/org.jclouds.providers.ProviderMetadata")).andReturn(getClass().getResource("/META-INF/services/org.jclouds.providers.ProviderMetadata")).anyTimes();
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestBlobStoreProviderMetadata")).andReturn(JcloudsTestBlobStoreProviderMetadata.class).anyTimes();
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestComputeProviderMetadata")).andReturn(JcloudsTestComputeProviderMetadata.class).anyTimes();
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata")).andReturn(JcloudsTestYetAnotherComputeProviderMetadata.class).anyTimes();
+
+ replay(bundle);
+ List providerMetadataList = listener.getProviderMetadata(bundle);
+ assertNotNull(providerMetadataList);
+ assertEquals(3, providerMetadataList.size());
+ assertTrue(providerMetadataList.contains(new JcloudsTestBlobStoreProviderMetadata()));
+ assertTrue(providerMetadataList.contains(new JcloudsTestComputeProviderMetadata()));
+ assertTrue(providerMetadataList.contains(new JcloudsTestYetAnotherComputeProviderMetadata()));
+ verify(bundle);
+ }
+
+ @Test
+ public void testGetProviderMetadataFromMultipleClassLoaders() throws Exception {
+ ClassLoader isolatedClassLoader = createIsolatedClassLoader();
+ MetadataBundleListener listener = new MetadataBundleListener();
+ Bundle bundle = createMock(Bundle.class);
+ expect(bundle.getEntry("/META-INF/services/org.jclouds.providers.ProviderMetadata")).andReturn(getClass().getResource("/META-INF/services/org.jclouds.providers.ProviderMetadata")).anyTimes();
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestBlobStoreProviderMetadata")).andReturn(isolatedClassLoader.loadClass(JcloudsTestBlobStoreProviderMetadata.class.getName())).anyTimes();
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestComputeProviderMetadata")).andReturn(JcloudsTestComputeProviderMetadata.class).anyTimes();
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata")).andReturn(JcloudsTestYetAnotherComputeProviderMetadata.class).anyTimes();
+
+ replay(bundle);
+ List providerMetadataList = listener.getProviderMetadata(bundle);
+ assertNotNull(providerMetadataList);
+ assertEquals(2, providerMetadataList.size());
+ assertFalse(providerMetadataList.contains(new JcloudsTestBlobStoreProviderMetadata()));
+ assertTrue(providerMetadataList.contains(new JcloudsTestComputeProviderMetadata()));
+ assertTrue(providerMetadataList.contains(new JcloudsTestYetAnotherComputeProviderMetadata()));
+ verify(bundle);
+ }
+
+ @Test
+ public void testGetApiMetadata() throws Exception {
+ MetadataBundleListener listener = new MetadataBundleListener();
+ Bundle bundle = createMock(Bundle.class);
+ expect(bundle.getEntry("/META-INF/services/org.jclouds.apis.ApiMetadata")).andReturn(getClass().getResource("/META-INF/services/org.jclouds.apis.ApiMetadata")).anyTimes();
+ expect(bundle.loadClass("org.jclouds.apis.JcloudsTestBlobStoreApiMetadata")).andReturn(JcloudsTestBlobStoreApiMetadata.class).anyTimes();
+ expect(bundle.loadClass("org.jclouds.apis.JcloudsTestComputeApiMetadata")).andReturn(JcloudsTestComputeApiMetadata.class).anyTimes();
+ expect(bundle.loadClass("org.jclouds.apis.JcloudsTestYetAnotherComputeApiMetadata")).andReturn(JcloudsTestYetAnotherComputeApiMetadata.class).anyTimes();
+
+ replay(bundle);
+ List apiMetadataList = listener.getApiMetadata(bundle);
+ assertNotNull(apiMetadataList);
+ assertEquals(3, apiMetadataList.size());
+ assertTrue(apiMetadataList.contains(new JcloudsTestBlobStoreApiMetadata()));
+ assertTrue(apiMetadataList.contains(new JcloudsTestComputeApiMetadata()));
+ assertTrue(apiMetadataList.contains(new JcloudsTestYetAnotherComputeApiMetadata()));
+ verify(bundle);
+ }
+
+ @Test
+ public void testGetApiMetadataFromMultipleClassLoaders() throws Exception {
+ ClassLoader isolatedClassLoader = createIsolatedClassLoader();
+ MetadataBundleListener listener = new MetadataBundleListener();
+ Bundle bundle = createMock(Bundle.class);
+ expect(bundle.getEntry("/META-INF/services/org.jclouds.apis.ApiMetadata")).andReturn(getClass().getResource("/META-INF/services/org.jclouds.apis.ApiMetadata")).anyTimes();
+ expect(bundle.loadClass("org.jclouds.apis.JcloudsTestBlobStoreApiMetadata")).andReturn(isolatedClassLoader.loadClass(JcloudsTestBlobStoreApiMetadata.class.getName())).anyTimes();
+ expect(bundle.loadClass("org.jclouds.apis.JcloudsTestComputeApiMetadata")).andReturn(JcloudsTestComputeApiMetadata.class).anyTimes();
+ expect(bundle.loadClass("org.jclouds.apis.JcloudsTestYetAnotherComputeApiMetadata")).andReturn(JcloudsTestYetAnotherComputeApiMetadata.class).anyTimes();
+
+ replay(bundle);
+ List apiMetadataList = listener.getApiMetadata(bundle);
+ assertNotNull(apiMetadataList);
+ assertEquals(2, apiMetadataList.size());
+ assertFalse(apiMetadataList.contains(new JcloudsTestBlobStoreApiMetadata()));
+ assertTrue(apiMetadataList.contains(new JcloudsTestComputeApiMetadata()));
+ assertTrue(apiMetadataList.contains(new JcloudsTestYetAnotherComputeApiMetadata()));
+ verify(bundle);
+ }
+
+
+ /**
+ * Creates a different {@link ClassLoader}.
+ *
+ * @return
+ */
+ private ClassLoader createIsolatedClassLoader() throws MalformedURLException {
+ URLClassLoader testClassLoader = (URLClassLoader) getClass().getClassLoader();
+ URL[] urls = testClassLoader.getURLs();
+ URLClassLoader loader = new URLClassLoader(urls, null);
+ return loader;
+ }
+}
diff --git a/drivers/netty/pom.xml b/drivers/netty/pom.xml
index eae81f6158..b52819dccd 100644
--- a/drivers/netty/pom.xml
+++ b/drivers/netty/pom.xml
@@ -35,7 +35,11 @@
org.jclouds.netty*;version="${project.version}"
- org.jclouds*;version="${project.version}",*
+
+ org.jclouds*;version="${project.version}",
+ org.jboss.netty*;version="[3.3,4)",
+ *
+
diff --git a/drivers/slf4j/pom.xml b/drivers/slf4j/pom.xml
index 91db097d8d..9204a6d758 100644
--- a/drivers/slf4j/pom.xml
+++ b/drivers/slf4j/pom.xml
@@ -35,7 +35,11 @@
org.jclouds.logging.slf4j*;version="${project.version}"
- org.jclouds*;version="${project.version}",*
+
+ org.jclouds*;version="${project.version}",
+ org.slf4j*;version="[1.5,2)",
+ *
+