| /* |
| * 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.felix.dm.runtime; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.felix.dm.Component; |
| import org.apache.felix.dm.DependencyManager; |
| import org.osgi.framework.Bundle; |
| import org.osgi.service.packageadmin.PackageAdmin; |
| |
| /** |
| * This class parses service descriptors generated by the annotation bnd processor. |
| * The descriptors are located under META-INF/dependencymanager directory. Such files are actually |
| * referenced by a specific "DependendencyManager-Component" manifest header. |
| * |
| * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> |
| */ |
| public class DependencyManagerRuntime |
| { |
| /** |
| * Map between bundles and their corresponding DependencyManager objects used to create bundle's components. |
| * Notice that we can safely use this map without synchronization because we are relying on the new DM4 thread |
| * model which serialize all component events safely. |
| */ |
| private final Map<Bundle, DependencyManager> m_managers = new HashMap<Bundle, DependencyManager>(); |
| |
| /** |
| * Parser used to scan component descriptors defined in bundles meta data. |
| */ |
| private final DescriptorParser m_parser; |
| |
| /** |
| * We use the PackageAdmin service to allow support for annotations in fragment bundles. |
| */ |
| private volatile PackageAdmin m_packageAdmin; |
| |
| /** |
| * Our constructor. We'll initialize here our DM component builders. |
| */ |
| public DependencyManagerRuntime() |
| { |
| // Instantiates our descriptor parser, and register our service builders into it. |
| m_parser = new DescriptorParser(); |
| m_parser.addBuilder(new ComponentBuilder()); |
| m_parser.addBuilder(new AspectServiceBuilder()); |
| m_parser.addBuilder(new AdapterServiceBuilder()); |
| m_parser.addBuilder(new BundleAdapterServiceBuilder()); |
| m_parser.addBuilder(new FactoryConfigurationAdapterServiceBuilder()); |
| m_parser.addBuilder(new ResourceAdapterServiceBuilder()); |
| } |
| |
| /** |
| * Return our Object Composition (the Activator will inject dependencies into it) |
| */ |
| protected Object[] getComposition() |
| { |
| return new Object[] { this, Log.instance() }; |
| } |
| |
| /** |
| * Starts our Service (at this point, we have been injected with our bundle context, as well |
| * as with our log service. We'll listen to bundle start/stop events (we implement the |
| * SynchronousBundleListener interface). |
| */ |
| protected void start() |
| { |
| Log.instance().info("Starting Dependency Manager annotation runtime."); |
| } |
| |
| /** |
| * Stops our service. We'll stop all activated DependencyManager services. |
| */ |
| protected void stop() |
| { |
| Log.instance().info("Runtime: stopping services"); |
| for (DependencyManager dm : m_managers.values()) |
| { |
| List<Component> services = new ArrayList<Component>(dm.getComponents()); |
| for (Component service : services) |
| { |
| dm.remove(service); |
| } |
| } |
| |
| m_managers.clear(); |
| } |
| |
| /** |
| * Load the DM descriptors from the started bundle. We also check possible fragments |
| * attached to the bundle, which might also contain some DM descriptors. |
| * @param bundle the started bundle which contains a DependencyManager-Component header |
| */ |
| protected void bundleStarted(Bundle bundle) |
| { |
| Log.instance().info("Scanning started bundle %s", bundle.getSymbolicName()); |
| List<URL> descriptorURLs = new ArrayList<URL>(); |
| collectDescriptors(bundle, descriptorURLs); |
| Bundle[] fragments = m_packageAdmin.getFragments(bundle); |
| if (fragments != null) |
| { |
| for (Bundle fragment : fragments) |
| { |
| collectDescriptors(fragment, descriptorURLs); |
| } |
| } |
| for (URL descriptorURL : descriptorURLs) |
| { |
| loadDescriptor(bundle, descriptorURL); |
| } |
| } |
| |
| /** |
| * Unregisters all services for a stopping bundle. |
| * @param b |
| */ |
| protected void bundleStopped(Bundle b) |
| { |
| Log.instance().info("Runtime: Removing services from stopping bundle: %s", b.getSymbolicName()); |
| DependencyManager dm = m_managers.remove(b); |
| if (dm != null) |
| { |
| List<Component> services = new ArrayList<Component>(dm.getComponents()); |
| for (Component service : services) |
| { |
| Log.instance().info("Runtime: Removing service: %s", service); |
| dm.remove(service); |
| } |
| } |
| } |
| |
| /** |
| * Collect all descriptors found from a given bundle, including its possible attached fragments. |
| * @param bundle a started bundle containing some DM descriptors |
| * @param out the list of descriptors' URLS found from the started bundle, as well as from possibly |
| * attached fragments. |
| */ |
| private void collectDescriptors(Bundle bundle, List<URL> out) { |
| String descriptorPaths = (String) bundle.getHeaders().get("DependencyManager-Component"); |
| if (descriptorPaths == null) |
| { |
| return; |
| } |
| |
| for (String descriptorPath : descriptorPaths.split(",")) |
| { |
| URL descriptorURL = bundle.getEntry(descriptorPath); |
| if (descriptorURL == null) |
| { |
| Log.instance() |
| .error("Runtime: " + "DependencyManager component descriptor not found: %s", |
| descriptorPath); |
| continue; |
| } |
| out.add(descriptorURL); |
| } |
| } |
| |
| /** |
| * Load a DependencyManager component descriptor from a given bundle. |
| * @param b |
| * @param descriptorURL |
| */ |
| private void loadDescriptor(Bundle b, URL descriptorURL) |
| { |
| Log.instance().debug("Parsing descriptor %s from bundle %s", descriptorURL, b.getSymbolicName()); |
| |
| BufferedReader in = null; |
| try |
| { |
| in = new BufferedReader(new InputStreamReader(descriptorURL.openStream())); |
| DependencyManager dm = m_managers.get(b); |
| if (dm == null) |
| { |
| dm = new DependencyManager(b.getBundleContext()); |
| m_managers.put(b, dm); |
| } |
| |
| m_parser.parse(in, b, dm); |
| } |
| |
| catch (Throwable t) |
| { |
| Log.instance().error("Runtime: Error while parsing descriptor %s from bundle %s", |
| t, |
| descriptorURL, |
| b.getSymbolicName()); |
| } |
| |
| finally |
| { |
| if (in != null) |
| { |
| try |
| { |
| in.close(); |
| } |
| catch (IOException ignored) |
| { |
| } |
| } |
| } |
| } |
| } |