From cf94e70a95718ca31fe9b37baf465a7145a24578 Mon Sep 17 00:00:00 2001 From: Ioannis Canellos Date: Wed, 13 Jun 2012 13:05:23 +0300 Subject: [PATCH] Improved discovery of api metadata inside OSGi. --- .../java/org/jclouds/apis/ApiRegistry.java | 46 ++++++++++ core/src/main/java/org/jclouds/apis/Apis.java | 2 +- .../main/java/org/jclouds/osgi/Activator.java | 4 +- ...tener.java => MetadataBundleListener.java} | 85 +++++++++++++++---- 4 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 core/src/main/java/org/jclouds/apis/ApiRegistry.java rename core/src/main/java/org/jclouds/osgi/{ProviderBundleListener.java => MetadataBundleListener.java} (55%) diff --git a/core/src/main/java/org/jclouds/apis/ApiRegistry.java b/core/src/main/java/org/jclouds/apis/ApiRegistry.java new file mode 100644 index 0000000000..78071db153 --- /dev/null +++ b/core/src/main/java/org/jclouds/apis/ApiRegistry.java @@ -0,0 +1,46 @@ +/** + * 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.apis; + +import java.util.HashSet; +import java.util.Set; + +/** + * A registry for holding {@link org.jclouds.apis.ApiMetadata}. + */ +public class ApiRegistry { + + private static final Set apis = new HashSet(); + + public static void registerApi(ApiMetadata api) { + apis.add(api); + } + + public static void unRegisterApi(ApiMetadata api) { + apis.remove(api); + } + + public static Iterable fromRegistry() { + return Iterable.class.cast(apis); + } + + public static void clear() { + apis.clear(); + } +} diff --git a/core/src/main/java/org/jclouds/apis/Apis.java b/core/src/main/java/org/jclouds/apis/Apis.java index fbb4c14282..484a6c5eaa 100644 --- a/core/src/main/java/org/jclouds/apis/Apis.java +++ b/core/src/main/java/org/jclouds/apis/Apis.java @@ -69,7 +69,7 @@ public class Apis { * @return all available apis */ public static Iterable all() { - return fromServiceLoader(); + return Iterables.concat(fromServiceLoader(), ApiRegistry.fromRegistry()); } /** diff --git a/core/src/main/java/org/jclouds/osgi/Activator.java b/core/src/main/java/org/jclouds/osgi/Activator.java index 64de199e1d..087585dd85 100644 --- a/core/src/main/java/org/jclouds/osgi/Activator.java +++ b/core/src/main/java/org/jclouds/osgi/Activator.java @@ -18,13 +18,14 @@ */ package org.jclouds.osgi; +import org.jclouds.apis.ApiRegistry; import org.jclouds.providers.ProviderRegistry; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { - ProviderBundleListener bundleListener = new ProviderBundleListener(); + MetadataBundleListener bundleListener = new MetadataBundleListener(); /** * Called when this bundle is started so the Framework can perform the @@ -67,5 +68,6 @@ public class Activator implements BundleActivator { public void stop(BundleContext context) throws Exception { context.removeBundleListener(bundleListener); ProviderRegistry.clear(); + ApiRegistry.clear(); } } diff --git a/core/src/main/java/org/jclouds/osgi/ProviderBundleListener.java b/core/src/main/java/org/jclouds/osgi/MetadataBundleListener.java similarity index 55% rename from core/src/main/java/org/jclouds/osgi/ProviderBundleListener.java rename to core/src/main/java/org/jclouds/osgi/MetadataBundleListener.java index 01d3a267b6..9a996c43d6 100644 --- a/core/src/main/java/org/jclouds/osgi/ProviderBundleListener.java +++ b/core/src/main/java/org/jclouds/osgi/MetadataBundleListener.java @@ -18,6 +18,8 @@ */ package org.jclouds.osgi; +import org.jclouds.apis.ApiMetadata; +import org.jclouds.apis.ApiRegistry; import org.jclouds.providers.ProviderMetadata; import org.jclouds.providers.ProviderRegistry; import org.osgi.framework.Bundle; @@ -32,30 +34,41 @@ import java.util.HashMap; import java.util.Map; /** - * A {@link BundleListener} that listens for {@link BundleEvent} and searches for {@link org.jclouds.providers.ProviderMetadata} in newly + * A {@link BundleListener} that listens for {@link BundleEvent} and searches for {@link org.jclouds.providers.ProviderMetadata} and {@ling org.jclouds.apis.ApiMetadata} in newly * installed Bundles. This is used as a workaround for OSGi environments where the ServiceLoader cannot cross bundle * boundaries. */ -public class ProviderBundleListener implements BundleListener { +public class MetadataBundleListener implements BundleListener { - private Map bundleMetadataMap = new HashMap(); + private Map providerMetadataMap = new HashMap(); + private Map apiMetadataMap = new HashMap(); @Override public void bundleChanged(BundleEvent event) { - ProviderMetadata metadata; + ProviderMetadata providerMetadata; + ApiMetadata apiMetadata; switch (event.getType()) { case BundleEvent.STARTED: - metadata = getProviderMetadata(event.getBundle()); - if (metadata != null) { - ProviderRegistry.registerProvider(metadata); - bundleMetadataMap.put(event.getBundle().getBundleId(), metadata); + 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: - metadata = bundleMetadataMap.get(event.getBundle().getBundleId()); - if (metadata != null) { - ProviderRegistry.uRegisterProvider(metadata); + providerMetadata = providerMetadataMap.get(event.getBundle().getBundleId()); + apiMetadata = apiMetadataMap.get(event.getBundle().getBundleId()); + if (providerMetadata != null) { + ProviderRegistry.uRegisterProvider(providerMetadata); + } + if (apiMetadata != null) { + ApiRegistry.unRegisterApi(apiMetadata); } break; } @@ -72,8 +85,8 @@ public class ProviderBundleListener implements BundleListener { String className = getProviderMetadataClassName(bundle); if (className != null && !className.isEmpty()) { try { - Class provideClass = bundle.loadClass(className); - metadata = provideClass.newInstance(); + Class providerMetadataClass = bundle.loadClass(className); + metadata = providerMetadataClass.newInstance(); } catch (ClassNotFoundException e) { // ignore } catch (InstantiationException e) { @@ -86,13 +99,32 @@ public class ProviderBundleListener implements BundleListener { } /** - * Retrieves the {@link ProviderMetadata} class name for the bundle if it exists. + * Creates an instance of {@link ApiMetadata} from the {@link Bundle}. * * @param bundle * @return */ - public String getProviderMetadataClassName(Bundle bundle) { - URL resource = bundle.getEntry("/META-INF/services/org.jclouds.providers.ProviderMetadata"); + public ApiMetadata getApiMetadata(Bundle bundle) { + ApiMetadata metadata = null; + String className = getApiMetadataClassName(bundle); + if (className != null && !className.isEmpty()) { + try { + Class 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; @@ -126,4 +158,25 @@ public class ProviderBundleListener implements BundleListener { } return sb.toString().trim(); } + + /** + * 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"); + } + } \ No newline at end of file