mirror of https://github.com/apache/jclouds.git
Improved the discovery of providers inside OSGi
This commit is contained in:
parent
5e69df71d1
commit
6ffe7085bc
|
@ -41,6 +41,7 @@
|
|||
<properties>
|
||||
<jclouds.osgi.import>*</jclouds.osgi.import>
|
||||
<jclouds.osgi.export>org.jclouds*;version=${project.version};-noimport:=true</jclouds.osgi.export>
|
||||
<jclouds.osgi.activator>org.jclouds.osgi.Activator</jclouds.osgi.activator>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -106,6 +107,12 @@
|
|||
<artifactId>guava</artifactId>
|
||||
<version>12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.osgi</groupId>
|
||||
<artifactId>org.osgi.core</artifactId>
|
||||
<version>4.2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* 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.ProviderRegistry;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
public class Activator implements BundleActivator {
|
||||
|
||||
ProviderBundleListener bundleListener = new ProviderBundleListener();
|
||||
|
||||
/**
|
||||
* Called when this bundle is started so the Framework can perform the
|
||||
* bundle-specific activities necessary to start this bundle. This method
|
||||
* can be used to register services or to allocate any resources that this
|
||||
* bundle needs.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* This method must complete and return to its caller in a timely manner.
|
||||
*
|
||||
* @param context The execution context of the bundle being started.
|
||||
* @throws Exception If this method throws an exception, this
|
||||
* bundle is marked as stopped and the Framework will remove this
|
||||
* bundle's listeners, unregister all services registered by this
|
||||
* bundle, and release all services used by this bundle.
|
||||
*/
|
||||
@Override
|
||||
public void start(BundleContext context) throws Exception {
|
||||
context.addBundleListener(bundleListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this bundle is stopped so the Framework can perform the
|
||||
* bundle-specific activities necessary to stop the bundle. In general, this
|
||||
* method should undo the work that the <code>BundleActivator.start</code>
|
||||
* method started. There should be no active threads that were started by
|
||||
* this bundle when this bundle returns. A stopped bundle must not call any
|
||||
* Framework objects.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* This method must complete and return to its caller in a timely manner.
|
||||
*
|
||||
* @param context The execution context of the bundle being stopped.
|
||||
* @throws Exception If this method throws an exception, the
|
||||
* bundle is still marked as stopped, and the Framework will remove
|
||||
* the bundle's listeners, unregister all services registered by the
|
||||
* bundle, and release all services used by the bundle.
|
||||
*/
|
||||
@Override
|
||||
public void stop(BundleContext context) throws Exception {
|
||||
context.removeBundleListener(bundleListener);
|
||||
ProviderRegistry.clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* 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;
|
||||
import org.jclouds.providers.ProviderRegistry;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleEvent;
|
||||
import org.osgi.framework.BundleListener;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
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
|
||||
* installed Bundles. This is used as a workaround for OSGi environments where the ServiceLoader cannot cross bundle
|
||||
* boundaries.
|
||||
*/
|
||||
public class ProviderBundleListener implements BundleListener {
|
||||
|
||||
private Map<Long, ProviderMetadata> bundleMetadataMap = new HashMap<Long, ProviderMetadata>();
|
||||
|
||||
@Override
|
||||
public void bundleChanged(BundleEvent event) {
|
||||
ProviderMetadata metadata;
|
||||
switch (event.getType()) {
|
||||
case BundleEvent.STARTED:
|
||||
metadata = getProviderMetadata(event.getBundle());
|
||||
if (metadata != null) {
|
||||
ProviderRegistry.registerProvider(metadata);
|
||||
bundleMetadataMap.put(event.getBundle().getBundleId(), metadata);
|
||||
}
|
||||
break;
|
||||
case BundleEvent.STOPPING:
|
||||
case BundleEvent.STOPPED:
|
||||
metadata = bundleMetadataMap.get(event.getBundle().getBundleId());
|
||||
if (metadata != null) {
|
||||
ProviderRegistry.uRegisterProvider(metadata);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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> provideClass = bundle.loadClass(className);
|
||||
metadata = provideClass.newInstance();
|
||||
} catch (ClassNotFoundException e) {
|
||||
// ignore
|
||||
} catch (InstantiationException e) {
|
||||
// ignore
|
||||
} catch (IllegalAccessException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the {@link ProviderMetadata} class name for the bundle if it exists.
|
||||
*
|
||||
* @param bundle
|
||||
* @return
|
||||
*/
|
||||
public String getProviderMetadataClassName(Bundle bundle) {
|
||||
URL resource = bundle.getEntry("/META-INF/services/org.jclouds.providers.ProviderMetadata");
|
||||
InputStream is = null;
|
||||
InputStreamReader reader = null;
|
||||
BufferedReader bufferedReader = null;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
try {
|
||||
is = resource.openStream();
|
||||
reader = new InputStreamReader(is, "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();
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
|
||||
}
|
||||
return sb.toString().trim();
|
||||
}
|
||||
}
|
|
@ -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.providers;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A registry for holding {@link org.jclouds.providers.ProviderMetadata}.
|
||||
*/
|
||||
public class ProviderRegistry {
|
||||
|
||||
private static final Set<ProviderMetadata> providers = new HashSet<ProviderMetadata>();
|
||||
|
||||
public static void registerProvider(ProviderMetadata provider) {
|
||||
providers.add(provider);
|
||||
}
|
||||
|
||||
public static void uRegisterProvider(ProviderMetadata provider) {
|
||||
providers.remove(provider);
|
||||
}
|
||||
|
||||
public static Iterable<ProviderMetadata> fromRegistry() {
|
||||
return Iterable.class.cast(providers);
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
providers.clear();
|
||||
}
|
||||
}
|
|
@ -24,6 +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 org.jclouds.Context;
|
||||
import org.jclouds.View;
|
||||
import org.jclouds.apis.ApiMetadata;
|
||||
|
@ -82,7 +83,7 @@ public class Providers {
|
|||
* @return all available providers
|
||||
*/
|
||||
public static Iterable<ProviderMetadata> all() {
|
||||
return fromServiceLoader();
|
||||
return Iterables.concat(fromServiceLoader(), ProviderRegistry.fromRegistry());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -560,6 +560,7 @@ pageTracker._trackPageview();
|
|||
<configuration>
|
||||
<obrRepository>NONE</obrRepository>
|
||||
<instructions>
|
||||
<Bundle-Activator>${jclouds.osgi.activator}</Bundle-Activator>
|
||||
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
|
||||
<Export-Package>${jclouds.osgi.export}</Export-Package>
|
||||
<Import-Package>${jclouds.osgi.import}</Import-Package>
|
||||
|
|
Loading…
Reference in New Issue