| /* |
| * 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.ipojo.extender.internal.processor; |
| |
| import org.apache.felix.ipojo.IPojoFactory; |
| import org.apache.felix.ipojo.extender.internal.BundleProcessor; |
| import org.apache.felix.ipojo.extender.internal.builder.ReflectiveFactoryBuilder; |
| import org.apache.felix.ipojo.extender.internal.declaration.DefaultExtensionDeclaration; |
| import org.apache.felix.ipojo.metadata.Element; |
| import org.apache.felix.ipojo.parser.ParseUtils; |
| import org.apache.felix.ipojo.util.Log; |
| import org.apache.felix.ipojo.util.Logger; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| |
| import java.util.*; |
| |
| /** |
| * Bundle processor handling the {@link #IPOJO_EXTENSION} header. |
| */ |
| public class ExtensionBundleProcessor implements BundleProcessor { |
| |
| /** |
| * iPOJO Extension declaration header. |
| */ |
| public static final String IPOJO_EXTENSION = "IPOJO-Extension"; |
| |
| /** |
| * Logger. |
| */ |
| private final Log m_logger; |
| |
| /** |
| * The map storing the association between bundles and the list of extension declaration. |
| */ |
| private Map<Bundle, List<DefaultExtensionDeclaration>> m_extensions = new HashMap<Bundle, List<DefaultExtensionDeclaration>>(); |
| |
| /** |
| * Creates the processor. |
| * |
| * @param logger the logger |
| */ |
| public ExtensionBundleProcessor(Log logger) { |
| m_logger = logger; |
| } |
| |
| /** |
| * A bundle is starting. |
| * |
| * @param bundle the bundle |
| */ |
| public void activate(Bundle bundle) { |
| Dictionary dict = bundle.getHeaders(); |
| // Check for abstract factory type |
| String extension = (String) dict.get(IPOJO_EXTENSION); |
| if (extension != null) { |
| activateExtensions(bundle, extension); |
| } |
| } |
| |
| /** |
| * A bundle is stopping. |
| * |
| * @param bundle the bundle |
| */ |
| public void deactivate(Bundle bundle) { |
| List<DefaultExtensionDeclaration> declarations = m_extensions.get(bundle); |
| if (declarations != null) { |
| for (DefaultExtensionDeclaration declaration : declarations) { |
| declaration.stop(); |
| } |
| m_extensions.remove(bundle); |
| } |
| } |
| |
| /** |
| * iPOJO is starting. |
| * Nothing to do. |
| */ |
| public void start() { |
| // Nothing to do |
| } |
| |
| /** |
| * iPOJO is stopping. |
| * We clean up all extension in the reverse order of their installation. |
| */ |
| public void stop() { |
| // Construct a new instance to avoid ConcurrentModificationException since deactivate also change the extensions |
| // list |
| // Ignored, for a simple ordered shutdown, use ReverseBundleProcessor |
| } |
| |
| /** |
| * Parses an IPOJO-Extension manifest header and then creates |
| * iPOJO extensions (factory types). |
| * |
| * @param bundle the bundle containing the header. |
| * @param header the header to parse. |
| */ |
| private void activateExtensions(Bundle bundle, String header) { |
| String[] extensions = ParseUtils.split(header, ","); |
| for (int i = 0; extensions != null && i < extensions.length; i++) { |
| String[] segments = ParseUtils.split(extensions[i], ":"); |
| |
| /* |
| * Get the fully qualified type name. |
| * type = [namespace] name |
| */ |
| String[] nameparts = ParseUtils.split(segments[0].trim(), " \t"); |
| String type = nameparts.length == 1 ? nameparts[0] : nameparts[0] + ":" + nameparts[1]; |
| String classname = segments[1]; |
| |
| Class<? extends IPojoFactory> clazz; |
| try { |
| clazz = bundle.loadClass(classname).asSubclass(IPojoFactory.class); |
| } catch (ClassNotFoundException e) { |
| String message = String.format("Cannot load class '%s' from bundle %s (%s) for extension '%s'", |
| classname, |
| bundle.getSymbolicName(), |
| bundle.getVersion(), |
| type); |
| m_logger.log(Logger.ERROR, message, e); |
| return; |
| } |
| |
| try { |
| ReflectiveFactoryBuilder builder = new ReflectiveFactoryBuilder(clazz.getConstructor(BundleContext.class, Element.class)); |
| DefaultExtensionDeclaration declaration = new DefaultExtensionDeclaration(bundle.getBundleContext(), builder, type); |
| |
| getBundleDeclarations(bundle).add(declaration); |
| |
| declaration.start(); |
| |
| m_logger.log(Logger.DEBUG, "New factory type available: " + type); |
| } catch (NoSuchMethodException e) { |
| m_logger.log(Logger.ERROR, |
| String.format("Extension '%s' is missing the required (BundleContext, Element) public " + |
| "constructor", clazz.getName())); |
| } |
| } |
| } |
| |
| /** |
| * Gets the list of declaration for the given method. |
| * |
| * @param bundle the bundle |
| * @return the list of extension declaration associated to the given bundle, <code>null</code> otherwise. |
| */ |
| private List<DefaultExtensionDeclaration> getBundleDeclarations(Bundle bundle) { |
| List<DefaultExtensionDeclaration> declarations = m_extensions.get(bundle); |
| if (declarations == null) { |
| declarations = new ArrayList<DefaultExtensionDeclaration>(); |
| m_extensions.put(bundle, declarations); |
| } |
| return declarations; |
| } |
| |
| } |