classNames = stringsForResorceInBundle("/META-INF/services/org.jclouds.apis.ApiMetadata", bundle);
+ return instantiateAvailableClasses(bundle, classNames, ApiMetadata.class);
}
/**
- * Retrieves the {@link ProviderMetadata} class name for the bundle if it exists.
+ * Adds a {@link ProviderListener} and notifies it of existing {@link ProviderMetadata}.
*
- * @param bundle
- * @return
+ * @param listener The listener.
*/
- public String getProviderMetadataClassNames(Bundle bundle) {
- return getMetadataClassNames(bundle, "/META-INF/services/org.jclouds.providers.ProviderMetadata");
+ public synchronized void addProviderListener(ProviderListener listener) {
+ providerListeners.add(listener);
+ for (ProviderMetadata metadata : providerMetadataMap.values()) {
+ listener.added(metadata);
+ }
}
/**
- * Retrieves the {@link ProviderMetadata} class name for the bundle if it exists.
+ * Removes the {@link ProviderListener}
*
- * @param bundle
- * @return
+ * @param listener The listener
*/
- public String getApiMetadataClassNames(Bundle bundle) {
- return getMetadataClassNames(bundle, "/META-INF/services/org.jclouds.apis.ApiMetadata");
+ public synchronized void removeProviderListener(ProviderListener listener) {
+ providerListeners.remove(listener);
+ }
+
+ /**
+ * Adds a {@link ApiListener} and notifies it of existing {@link ApiMetadata}.
+ *
+ * @param listener
+ */
+ public synchronized void addApiListenerListener(ApiListener listener) {
+ apiListeners.add(listener);
+ for (ApiMetadata metadata : apiMetadataMap.values()) {
+ listener.added(metadata);
+ }
+ }
+
+ /**
+ * Removes the {@link ApiListener}
+ *
+ * @param listener
+ */
+ public synchronized void removeApiListenerListener(ApiListener listener) {
+ apiListeners.remove(listener);
}
}
diff --git a/core/src/main/java/org/jclouds/osgi/ProviderListener.java b/core/src/main/java/org/jclouds/osgi/ProviderListener.java
new file mode 100644
index 0000000000..39e38755df
--- /dev/null
+++ b/core/src/main/java/org/jclouds/osgi/ProviderListener.java
@@ -0,0 +1,47 @@
+/**
+ * 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.providers.ProviderMetadata;
+
+/**
+ * A listener interface for {@link ProviderMetadata}.
+ * In OSGi a provider can be added or removed dynamically.
+ * OSGi services using this interface will receive a notification whenever this happens.
+ */
+public interface ProviderListener {
+
+ /**
+ * Method to be called when a Provider gets added.
+ *
+ * @param provider The provider that was added.
+ * @param The {@link ProviderMetadata}.
+ */
+
void added(P provider);
+
+ /**
+ * Method to be called when a Provider gets removed.
+ *
+ * @param provider The provider that was added.
+ * @param
The {@link ProviderMetadata}.
+ */
+
void removed(P provider);
+
+}
diff --git a/core/src/main/java/org/jclouds/providers/ProviderRegistry.java b/core/src/main/java/org/jclouds/providers/ProviderRegistry.java
index d9bd784be3..ece39834e9 100644
--- a/core/src/main/java/org/jclouds/providers/ProviderRegistry.java
+++ b/core/src/main/java/org/jclouds/providers/ProviderRegistry.java
@@ -27,21 +27,21 @@ import com.google.common.collect.Sets;
*/
public class ProviderRegistry {
- private static final Set providers = Sets.newHashSet();
+ private static final Set providers = Sets.newHashSet();
- public static void registerProvider(ProviderMetadata provider) {
- providers.add(provider);
- }
+ public static void registerProvider(ProviderMetadata provider) {
+ providers.add(provider);
+ }
- public static void unregisterProvider(ProviderMetadata provider) {
- providers.remove(provider);
- }
+ public static void unregisterProvider(ProviderMetadata provider) {
+ providers.remove(provider);
+ }
- public static Iterable fromRegistry() {
- return Iterable.class.cast(providers);
- }
+ public static Iterable fromRegistry() {
+ return Iterable.class.cast(providers);
+ }
- public static void clear() {
- providers.clear();
- }
+ public static void clear() {
+ providers.clear();
+ }
}
diff --git a/core/src/main/java/org/jclouds/providers/Providers.java b/core/src/main/java/org/jclouds/providers/Providers.java
index e57fb19daa..c4b79e54ea 100644
--- a/core/src/main/java/org/jclouds/providers/Providers.java
+++ b/core/src/main/java/org/jclouds/providers/Providers.java
@@ -24,7 +24,7 @@ import static com.google.common.collect.Iterables.find;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
-import com.google.common.collect.Iterables;
+import com.google.common.collect.ImmutableSet;
import org.jclouds.Context;
import org.jclouds.View;
import org.jclouds.apis.ApiMetadata;
@@ -83,7 +83,9 @@ public class Providers {
* @return all available providers
*/
public static Iterable all() {
- return Iterables.concat(fromServiceLoader(), ProviderRegistry.fromRegistry());
+ return ImmutableSet.builder()
+ .addAll(fromServiceLoader())
+ .addAll(ProviderRegistry.fromRegistry()).build();
}
/**
diff --git a/core/src/test/java/org/jclouds/osgi/BundlesTest.java b/core/src/test/java/org/jclouds/osgi/BundlesTest.java
new file mode 100644
index 0000000000..fc4c319295
--- /dev/null
+++ b/core/src/test/java/org/jclouds/osgi/BundlesTest.java
@@ -0,0 +1,115 @@
+/**
+ * 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 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 org.jclouds.apis.JcloudsTestComputeApiMetadata;
+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 com.google.common.collect.ImmutableSet;
+
+/**
+ *
+ * @author Adrian Cole
+ *
+ */
+public class BundlesTest {
+
+ @Test
+ public void testInstantiateAvailableClassesWhenAllAssignable() throws ClassNotFoundException {
+ Bundle bundle = createMock(Bundle.class);
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestBlobStoreProviderMetadata"))
+ .andReturn(JcloudsTestBlobStoreProviderMetadata.class);
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestComputeProviderMetadata"))
+ .andReturn(JcloudsTestComputeProviderMetadata.class);
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata"))
+ .andReturn(JcloudsTestYetAnotherComputeProviderMetadata.class);
+ replay(bundle);
+
+ Iterable providers = Bundles.instantiateAvailableClasses(bundle, ImmutableSet.of(
+ "org.jclouds.providers.JcloudsTestBlobStoreProviderMetadata",
+ "org.jclouds.providers.JcloudsTestComputeProviderMetadata",
+ "org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata"), ProviderMetadata.class);
+ assertEquals(providers, ImmutableSet.of(new JcloudsTestBlobStoreProviderMetadata(),
+ new JcloudsTestComputeProviderMetadata(), new JcloudsTestYetAnotherComputeProviderMetadata()));
+
+ verify(bundle);
+ }
+
+ @Test
+ public void testInstantiateAvailableClassesWhenNotAllAssignable() throws ClassNotFoundException {
+ Bundle bundle = createMock(Bundle.class);
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestBlobStoreProviderMetadata"))
+ .andReturn(JcloudsTestBlobStoreProviderMetadata.class);
+ expect(bundle.loadClass("org.jclouds.apis.JcloudsTestComputeApiMetadata"))
+ .andReturn(JcloudsTestComputeApiMetadata.class);
+ expect(bundle.loadClass("org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata"))
+ .andReturn(JcloudsTestYetAnotherComputeProviderMetadata.class);
+ replay(bundle);
+
+ Iterable providers = Bundles.instantiateAvailableClasses(bundle, ImmutableSet.of(
+ "org.jclouds.providers.JcloudsTestBlobStoreProviderMetadata",
+ "org.jclouds.apis.JcloudsTestComputeApiMetadata",
+ "org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata"), ProviderMetadata.class);
+ assertEquals(providers, ImmutableSet.of(new JcloudsTestBlobStoreProviderMetadata(),
+ new JcloudsTestYetAnotherComputeProviderMetadata()));
+
+ verify(bundle);
+ }
+
+ @Test
+ public void testStringsForResourcesInBundleWhenNoResources() throws Exception {
+
+ Bundle bundle = createMock(Bundle.class);
+ expect(bundle.getEntry("/META-INF/services/org.jclouds.apis.ApiMetadata")).andReturn(null);
+ replay(bundle);
+
+ assertEquals(Bundles.stringsForResorceInBundle("/META-INF/services/org.jclouds.apis.ApiMetadata", bundle),
+ ImmutableSet.of());
+
+ verify(bundle);
+ }
+
+ @Test
+ public void testStringsForResourcesInBundleWhenResourcePresent() throws Exception {
+
+ 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"));
+ replay(bundle);
+
+ assertEquals(Bundles.stringsForResorceInBundle(
+ "/META-INF/services/org.jclouds.providers.ProviderMetadata", bundle), ImmutableSet.of(
+ "org.jclouds.providers.JcloudsTestBlobStoreProviderMetadata",
+ "org.jclouds.providers.JcloudsTestComputeProviderMetadata",
+ "org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata"));
+
+ verify(bundle);
+ }
+}
diff --git a/core/src/test/java/org/jclouds/osgi/MetadataBundleListenerTest.java b/core/src/test/java/org/jclouds/osgi/MetadataBundleListenerTest.java
index 697877491e..7ea1b43621 100644
--- a/core/src/test/java/org/jclouds/osgi/MetadataBundleListenerTest.java
+++ b/core/src/test/java/org/jclouds/osgi/MetadataBundleListenerTest.java
@@ -18,6 +18,7 @@
*/
package org.jclouds.osgi;
+import com.google.common.collect.Lists;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.apis.JcloudsTestBlobStoreApiMetadata;
import org.jclouds.apis.JcloudsTestComputeApiMetadata;
@@ -27,6 +28,7 @@ import org.jclouds.providers.JcloudsTestComputeProviderMetadata;
import org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata;
import org.jclouds.providers.ProviderMetadata;
import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
import org.testng.annotations.Test;
import java.net.MalformedURLException;
@@ -34,16 +36,22 @@ import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
+import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
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;
+import static org.testng.Assert.assertTrue;
-
+/**
+ *
+ * @author iocanel
+ *
+ */
public class MetadataBundleListenerTest {
@Test
@@ -62,9 +70,8 @@ public class MetadataBundleListenerTest {
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);
+ List providerMetadataList = Lists.newArrayList(listener.listProviderMetadata(bundle));
assertNotNull(providerMetadataList);
assertEquals(3, providerMetadataList.size());
assertTrue(providerMetadataList.contains(new JcloudsTestBlobStoreProviderMetadata()));
@@ -73,6 +80,33 @@ public class MetadataBundleListenerTest {
verify(bundle);
}
+ @Test
+ public void testProviderListener() throws Exception {
+ MetadataBundleListener listener = new MetadataBundleListener();
+ ProviderListener providerListener = createMock(ProviderListener.class);
+ listener.addProviderListener(providerListener);
+
+ Bundle bundle = createMock(Bundle.class);
+ expect(bundle.getBundleId()).andReturn(10L).anyTimes();
+ expect(bundle.getEntry("/META-INF/services/org.jclouds.providers.ProviderMetadata")).andReturn(getClass().getResource("/META-INF/services/org.jclouds.providers.ProviderMetadata")).anyTimes();
+ expect(bundle.getEntry("/META-INF/services/org.jclouds.apis.ApiMetadata")).andReturn(null).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();
+
+ providerListener.added(anyObject(JcloudsTestBlobStoreProviderMetadata.class));
+ expectLastCall().times(1);
+ providerListener.added(anyObject(JcloudsTestComputeProviderMetadata.class));
+ expectLastCall().times(1);
+ providerListener.added(anyObject(JcloudsTestYetAnotherComputeProviderMetadata.class));
+ expectLastCall().times(1);
+ replay(bundle, providerListener);
+
+ BundleEvent event = new BundleEvent(BundleEvent.STARTED, bundle);
+ listener.bundleChanged(event);
+ verify(bundle, providerListener);
+ }
+
@Test
public void testGetProviderMetadataFromMultipleClassLoaders() throws Exception {
ClassLoader isolatedClassLoader = createIsolatedClassLoader();
@@ -84,7 +118,7 @@ public class MetadataBundleListenerTest {
expect(bundle.loadClass("org.jclouds.providers.JcloudsTestYetAnotherComputeProviderMetadata")).andReturn(JcloudsTestYetAnotherComputeProviderMetadata.class).anyTimes();
replay(bundle);
- List providerMetadataList = listener.getProviderMetadata(bundle);
+ List providerMetadataList = Lists.newArrayList(listener.listProviderMetadata(bundle));
assertNotNull(providerMetadataList);
assertEquals(2, providerMetadataList.size());
assertFalse(providerMetadataList.contains(new JcloudsTestBlobStoreProviderMetadata()));
@@ -103,7 +137,7 @@ public class MetadataBundleListenerTest {
expect(bundle.loadClass("org.jclouds.apis.JcloudsTestYetAnotherComputeApiMetadata")).andReturn(JcloudsTestYetAnotherComputeApiMetadata.class).anyTimes();
replay(bundle);
- List apiMetadataList = listener.getApiMetadata(bundle);
+ List apiMetadataList = Lists.newArrayList(listener.listApiMetadata(bundle));
assertNotNull(apiMetadataList);
assertEquals(3, apiMetadataList.size());
assertTrue(apiMetadataList.contains(new JcloudsTestBlobStoreApiMetadata()));
@@ -112,6 +146,34 @@ public class MetadataBundleListenerTest {
verify(bundle);
}
+ @Test
+ public void testApiListener() throws Exception {
+ MetadataBundleListener listener = new MetadataBundleListener();
+ ApiListener apiListener = createMock(ApiListener.class);
+ listener.addApiListenerListener(apiListener);
+
+ Bundle bundle = createMock(Bundle.class);
+ expect(bundle.getBundleId()).andReturn(10L).anyTimes();
+ expect(bundle.getEntry("/META-INF/services/org.jclouds.providers.ProviderMetadata")).andReturn(null).anyTimes();
+ 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();
+
+
+ apiListener.added(anyObject(JcloudsTestBlobStoreApiMetadata.class));
+ expectLastCall().times(1);
+ apiListener.added(anyObject(JcloudsTestBlobStoreApiMetadata.class));
+ expectLastCall().times(1);
+ apiListener.added(anyObject(JcloudsTestComputeApiMetadata.class));
+ expectLastCall().times(1);
+ replay(bundle, apiListener);
+
+ BundleEvent event = new BundleEvent(BundleEvent.STARTED, bundle);
+ listener.bundleChanged(event);
+ verify(bundle, apiListener);
+ }
+
@Test
public void testGetApiMetadataFromMultipleClassLoaders() throws Exception {
ClassLoader isolatedClassLoader = createIsolatedClassLoader();
@@ -123,7 +185,8 @@ public class MetadataBundleListenerTest {
expect(bundle.loadClass("org.jclouds.apis.JcloudsTestYetAnotherComputeApiMetadata")).andReturn(JcloudsTestYetAnotherComputeApiMetadata.class).anyTimes();
replay(bundle);
- List apiMetadataList = listener.getApiMetadata(bundle);
+
+ List apiMetadataList = Lists.newArrayList(listener.listApiMetadata(bundle));
assertNotNull(apiMetadataList);
assertEquals(2, apiMetadataList.size());
assertFalse(apiMetadataList.contains(new JcloudsTestBlobStoreApiMetadata()));
diff --git a/project/pom.xml b/project/pom.xml
index 33daf9e514..6e86a3c471 100644
--- a/project/pom.xml
+++ b/project/pom.xml
@@ -384,6 +384,7 @@
test.jks
CreateInternetService-options-test.xml
.gitattributes
+ OSGI-OPT/bnd.bnd
true