Improved discovery of api metadata inside OSGi.

This commit is contained in:
Ioannis Canellos 2012-06-13 13:05:23 +03:00
parent 4704e29941
commit cf94e70a95
4 changed files with 119 additions and 18 deletions

View File

@ -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<ApiMetadata> apis = new HashSet<ApiMetadata>();
public static void registerApi(ApiMetadata api) {
apis.add(api);
}
public static void unRegisterApi(ApiMetadata api) {
apis.remove(api);
}
public static Iterable<ApiMetadata> fromRegistry() {
return Iterable.class.cast(apis);
}
public static void clear() {
apis.clear();
}
}

View File

@ -69,7 +69,7 @@ public class Apis {
* @return all available apis * @return all available apis
*/ */
public static Iterable<ApiMetadata> all() { public static Iterable<ApiMetadata> all() {
return fromServiceLoader(); return Iterables.concat(fromServiceLoader(), ApiRegistry.fromRegistry());
} }
/** /**

View File

@ -18,13 +18,14 @@
*/ */
package org.jclouds.osgi; package org.jclouds.osgi;
import org.jclouds.apis.ApiRegistry;
import org.jclouds.providers.ProviderRegistry; import org.jclouds.providers.ProviderRegistry;
import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator { 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 * 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 { public void stop(BundleContext context) throws Exception {
context.removeBundleListener(bundleListener); context.removeBundleListener(bundleListener);
ProviderRegistry.clear(); ProviderRegistry.clear();
ApiRegistry.clear();
} }
} }

View File

@ -18,6 +18,8 @@
*/ */
package org.jclouds.osgi; package org.jclouds.osgi;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.apis.ApiRegistry;
import org.jclouds.providers.ProviderMetadata; import org.jclouds.providers.ProviderMetadata;
import org.jclouds.providers.ProviderRegistry; import org.jclouds.providers.ProviderRegistry;
import org.osgi.framework.Bundle; import org.osgi.framework.Bundle;
@ -32,30 +34,41 @@ import java.util.HashMap;
import java.util.Map; 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 * installed Bundles. This is used as a workaround for OSGi environments where the ServiceLoader cannot cross bundle
* boundaries. * boundaries.
*/ */
public class ProviderBundleListener implements BundleListener { public class MetadataBundleListener implements BundleListener {
private Map<Long, ProviderMetadata> bundleMetadataMap = new HashMap<Long, ProviderMetadata>(); private Map<Long, ProviderMetadata> providerMetadataMap = new HashMap<Long, ProviderMetadata>();
private Map<Long, ApiMetadata> apiMetadataMap = new HashMap<Long, ApiMetadata>();
@Override @Override
public void bundleChanged(BundleEvent event) { public void bundleChanged(BundleEvent event) {
ProviderMetadata metadata; ProviderMetadata providerMetadata;
ApiMetadata apiMetadata;
switch (event.getType()) { switch (event.getType()) {
case BundleEvent.STARTED: case BundleEvent.STARTED:
metadata = getProviderMetadata(event.getBundle()); providerMetadata = getProviderMetadata(event.getBundle());
if (metadata != null) { apiMetadata = getApiMetadata(event.getBundle());
ProviderRegistry.registerProvider(metadata); if (providerMetadata != null) {
bundleMetadataMap.put(event.getBundle().getBundleId(), metadata); ProviderRegistry.registerProvider(providerMetadata);
providerMetadataMap.put(event.getBundle().getBundleId(), providerMetadata);
}
if (apiMetadata != null) {
ApiRegistry.registerApi(apiMetadata);
apiMetadataMap.put(event.getBundle().getBundleId(), apiMetadata);
} }
break; break;
case BundleEvent.STOPPING: case BundleEvent.STOPPING:
case BundleEvent.STOPPED: case BundleEvent.STOPPED:
metadata = bundleMetadataMap.get(event.getBundle().getBundleId()); providerMetadata = providerMetadataMap.get(event.getBundle().getBundleId());
if (metadata != null) { apiMetadata = apiMetadataMap.get(event.getBundle().getBundleId());
ProviderRegistry.uRegisterProvider(metadata); if (providerMetadata != null) {
ProviderRegistry.uRegisterProvider(providerMetadata);
}
if (apiMetadata != null) {
ApiRegistry.unRegisterApi(apiMetadata);
} }
break; break;
} }
@ -72,8 +85,8 @@ public class ProviderBundleListener implements BundleListener {
String className = getProviderMetadataClassName(bundle); String className = getProviderMetadataClassName(bundle);
if (className != null && !className.isEmpty()) { if (className != null && !className.isEmpty()) {
try { try {
Class<? extends ProviderMetadata> provideClass = bundle.loadClass(className); Class<? extends ProviderMetadata> providerMetadataClass = bundle.loadClass(className);
metadata = provideClass.newInstance(); metadata = providerMetadataClass.newInstance();
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
// ignore // ignore
} catch (InstantiationException e) { } 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 * @param bundle
* @return * @return
*/ */
public String getProviderMetadataClassName(Bundle bundle) { public ApiMetadata getApiMetadata(Bundle bundle) {
URL resource = bundle.getEntry("/META-INF/services/org.jclouds.providers.ProviderMetadata"); 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; InputStream is = null;
InputStreamReader reader = null; InputStreamReader reader = null;
BufferedReader bufferedReader = null; BufferedReader bufferedReader = null;
@ -126,4 +158,25 @@ public class ProviderBundleListener implements BundleListener {
} }
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 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");
}
} }