blob: 5b57e505b578896a4cf77429a3011bad20e8e2f5 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.yoko.osgi.locator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.yoko.osgi.ProviderLocator;
/**
* The implementation of the provider registry used to store
* the bundle registrations.
*/
public class ProviderRegistryImpl implements org.apache.yoko.osgi.ProviderRegistry, Register {
private static final Logger log = Logger.getLogger(ProviderRegistryImpl.class.getName());
// our mapping between a provider id and the implementation information. There
// might be a one-to-many relationship between the ids and implementing classes.
private SPIRegistry providers = new SPIRegistry();
// our mapping between an interface name and a META-INF/services SPI implementation. There
// might be a one-to-many relationship between the ids and implementing classes.
private SPIRegistry serviceProviders = new SPIRegistry();
public void start() {
ProviderLocator.setRegistry(this);
}
public void stop() {
ProviderLocator.setRegistry(null);
}
/**
* Register an individual provivider item by its provider identifier.
*
* @param provider The loader used to resolve the provider class.
*/
public void registerProvider(BundleProviderLoader provider) {
log(Level.FINE, "registering provider " + provider);
providers.register(provider);
}
/**
* Removed a provider registration for a named provider id.
*
* @param provider The provider registration instance
*/
public void unregisterProvider(BundleProviderLoader provider) {
log(Level.FINE, "unregistering provider " + provider);
providers.unregister(provider);
}
/**
* Register an individual provivider item by its provider identifier.
*
* @param provider The loader used to resolve the provider class.
*/
public void registerService(BundleProviderLoader provider) {
log(Level.FINE, "registering service " + provider);
serviceProviders.register(provider);
}
/**
* Removed a provider registration for a named provider id.
*
* @param provider The provider registration instance
*/
public void unregisterService(BundleProviderLoader provider) {
log(Level.FINE, "unregistering service " + provider);
serviceProviders.unregister(provider);
}
/**
* Locate a class by its provider id indicator. .
*
* @param providerId The provider id (generally, a fully qualified class name).
*
* @return The Class corresponding to this provider id. Returns null
* if this is not registered or the indicated class can't be
* loaded.
*/
public Class<?> locate(String providerId) {
// see if we have a registered match for this...getting just the first instance
BundleProviderLoader loader = providers.getLoader(providerId);
if (loader != null) {
try {
// try to load this. We always return null
return loader.loadClass();
} catch (Exception e) {
e.printStackTrace();
// just swallow this and return null. The exception has already
// been logged.
}
}
// no match to return
return null;
}
/**
* Locate all class files that match a given provider id.
*
* @param providerId The target provider identifier.
*
* @return A List containing the class objects corresponding to the
* provider identifier. Returns an empty list if no
* matching classes can be located.
*/
public List<Class<?>> locateAll(String providerId) {
List<Class<?>> classes = new ArrayList<Class<?>>();
List<BundleProviderLoader> l = providers.getLoaders(providerId);
// this returns null if nothing is found.
if (l != null) {
for (BundleProviderLoader c : l) {
try {
classes.add(c.loadClass());
} catch (Exception e) {
// just swallow this and proceed to the next. The exception has
// already been logged.
}
}
}
return classes;
}
/**
* Locate and instantiate an instance of a service provider
* defined in the META-INF/services directory of tracked bundles.
*
* @param providerId The name of the target interface class.
*
* @return The service instance. Returns null if no service defintions
* can be located.
* @exception Exception Any classloading or other exceptions thrown during
* the process of creating this service instance.
*/
public Object getService(String providerId) throws Exception {
// see if we have a registered match for this...getting just the first instance
BundleProviderLoader loader = serviceProviders.getLoader(providerId);
if (loader != null) {
// try to load this and create an instance. Any/all exceptions get
// thrown here
return loader.createInstance();
}
// no match to return
return null;
}
/**
* Locate all services that match a given provider id and create instances.
*
* @param providerId The target provider identifier.
*
* @return A List containing the instances corresponding to the
* provider identifier. Returns an empty list if no
* matching classes can be located or created
*/
public List<Object> getServices(String providerId) {
List<Object> instances = new ArrayList<Object>();
List<BundleProviderLoader> l = serviceProviders.getLoaders(providerId);
// this returns null for nothing found
if (l != null) {
for (BundleProviderLoader c : l) {
try {
instances.add(c.createInstance());
} catch (Exception e) {
// just swallow this and proceed to the next. The exception has
// already been logged.
}
}
}
return instances;
}
/**
* Locate all services that match a given provider id and return the implementation
* classes
*
* @param providerId The target provider identifier.
*
* @return A List containing the classes corresponding to the
* provider identifier. Returns an empty list if no
* matching classes can be located.
*/
public List<Class<?>> getServiceClasses(String providerId) {
List<Class<?>> classes = new ArrayList<Class<?>>();
List<BundleProviderLoader> l = serviceProviders.getLoaders(providerId);
// this returns null for nothing found
if (l != null) {
for (BundleProviderLoader c : l) {
try {
classes.add(c.loadClass());
} catch (Exception e) {
e.printStackTrace();
// just swallow this and proceed to the next. The exception has
// already been logged.
}
}
}
return classes;
}
/**
* Locate and return the class for a service provider
* defined in the META-INF/services directory of tracked bundles.
*
* @param providerId The name of the target interface class.
*
* @return The provider class. Returns null if no service defintions
* can be located.
* @exception ClassNotFoundException Any classloading or other exceptions thrown during
* the process of loading this service provider class.
*/
public Class<?> getServiceClass(String providerId) throws ClassNotFoundException {
// see if we have a registered match for this...getting just the first instance
BundleProviderLoader loader = serviceProviders.getLoader(providerId);
if (loader != null) {
// try to load this and create an instance. Any/all exceptions get
// thrown here
return loader.loadClass();
}
// no match to return
return null;
}
private void log(Level level, String message) {
log.log(level, message);
}
/**
* Holder class for information about a given collection of
* id to provider mappings. Used for both the providers and
* the services.
*/
private class SPIRegistry {
private Map<String, List<BundleProviderLoader>> registry;
/**
* Register an individual provivider item by its provider identifier.
*
* @param provider The loader used to resolve the provider class.
*/
public synchronized void register(BundleProviderLoader provider) {
// if this is the first registration, create the mapping table
if (registry == null) {
registry = new HashMap<String, List<BundleProviderLoader>>();
}
String providerId = provider.id();
// the providers are stored as a list...we use the first one registered
// when asked to locate.
List<BundleProviderLoader> l = registry.get(providerId);
if (l == null) {
l = new ArrayList<BundleProviderLoader>(2);
registry.put(providerId, l);
}
l.add(provider);
Collections.sort(l);
}
/**
* Remove a provider registration for a named provider id.
*
* @param provider The provider registration instance
*/
public synchronized void unregister(BundleProviderLoader provider) {
if (registry != null) {
// this is stored as a list. Just remove using the registration information
// This may move a different provider to the front of the list.
List<BundleProviderLoader> l = registry.get(provider.id());
if (l != null) {
l.remove(provider);
}
}
}
private synchronized BundleProviderLoader getLoader(String id) {
// synchronize on the registry instance
if (registry != null) {
log.fine("registry: " + registry);
// return the first match, if any
List<BundleProviderLoader> list = registry.get(id);
if (list != null && !list.isEmpty()) {
return list.get(0);
}
}
// no match here
return null;
}
private synchronized List<BundleProviderLoader> getLoaders(String id) {
if (registry != null) {
// if we have matches, return a copy of what we currently have
// to create a safe local copy.
List<BundleProviderLoader> list = registry.get(id);
if (list != null && !list.isEmpty()) {
return new ArrayList<BundleProviderLoader>(list);
}
}
// no match here
return null;
}
}
}