| /** |
| * 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; |
| } |
| } |
| |
| |
| } |