/* * 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; import java.util.ArrayList; import java.util.Dictionary; import java.util.List; import org.apache.felix.ipojo.architecture.ComponentTypeDescription; import org.apache.felix.ipojo.metadata.Element; import org.osgi.framework.BundleContext; /** * Implementation of the handler factory interface. * This factory is able to create handler manager. * A handler manager is an iPOJO instance containing a handler object. * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class HandlerManagerFactory extends ComponentFactory implements HandlerFactory { /** * The Handler type (<code>composite</code> or <code>primitive</code>). */ private final String m_type; /** * The iPOJO Handler Namespace. * (Uses the iPOJO default namespace is not specified) */ private final String m_namespace; /** * The handler start level. * Lower levels are priority and so are configured and started * before higher levels, and are stopped after. */ private final int m_level; /** * Creates a handler factory. * @param context the bundle context * @param metadata the metadata of the component to create * @throws ConfigurationException if the element describing the factory is malformed. */ public HandlerManagerFactory(BundleContext context, Element metadata) throws ConfigurationException { super(context, metadata); // Get the name m_factoryName = metadata.getAttribute("name"); if (m_factoryName == null) { throw new ConfigurationException("A Handler needs a name"); } // Get the type String type = metadata.getAttribute("type"); if (type != null) { m_type = type; } else { m_type = "primitive"; // Set to primitive if not specified. } String level = metadata.getAttribute("level"); if (level != null) { m_level = new Integer(level).intValue(); } else { m_level = Integer.MAX_VALUE; // Set to max if not specified. } // Get the namespace String namespace = metadata.getAttribute("namespace"); if (namespace != null) { m_namespace = namespace.toLowerCase(); } else { m_namespace = IPOJO_NAMESPACE; // Set to the iPOJO default namespace if not specified. } } public String getNamespace() { return m_namespace; } public String getHandlerName() { return m_namespace + ":" + getName(); } public String getType() { return m_type; } public int getStartLevel() { return m_level; } public ComponentTypeDescription getComponentTypeDescription() { return new HandlerTypeDescription(this); } public String getFactoryName() { if ("composite".equals(m_type) && IPOJO_NAMESPACE.equals(m_namespace)) { // Artificially change the factory name, to avoid name clash when we generate the instance name. return m_namespace + ".composite:" + getName(); } return getHandlerName(); } /** * Stops the factory. * This method does not disposed created instances. * These instances will be disposed by the instance managers. * This method is called with the lock. */ public void stopping() { if (m_tracker != null) { m_tracker.close(); m_tracker = null; } } /** * Creates an instance. The given configuration needs to contain the 'name' * property. This method is called when holding the lock. * @param configuration the configuration of the created instance. * @param context the service context to push for this instance. * @param handlers the handler array to attach to the instance. * @return the created {@link HandlerManager}. * @throws org.apache.felix.ipojo.ConfigurationException if the instance configuration failed. * @see org.apache.felix.ipojo.Factory#createComponentInstance(java.util.Dictionary) */ public ComponentInstance createInstance(Dictionary configuration, IPojoContext context, HandlerManager[] handlers) throws ConfigurationException { HandlerManager instance = new HandlerManager(this, context, handlers); instance.configure(m_componentMetadata, configuration); return instance; } /** * Computes required handlers. This method does not manipulate any * non-immutable fields, so does not need to be synchronized. * This method is overridden to avoid using the same detection rules * than 'primitive' components. Indeed, architecture is disable by default, * and a handler is never immediate. * @return the required handler list. */ public List<RequiredHandler> getRequiredHandlerList() { List<RequiredHandler> list = new ArrayList<RequiredHandler>(); Element[] elems = m_componentMetadata.getElements(); for (int i = 0; i < elems.length; i++) { Element current = elems[i]; if (!"manipulation".equals(current.getName())) { // Remove the manipulation element RequiredHandler req = new RequiredHandler(current.getName(), current.getNameSpace()); if (!list.contains(req)) { list.add(req); } } } // Unlike normal components, the architecture is enable only when // specified. String arch = m_componentMetadata.getAttribute("architecture"); if (arch != null && arch.equalsIgnoreCase("true")) { list.add(new RequiredHandler("architecture", null)); } // The auto-attached handler list is ignored for handlers to avoid loops. return list; } /** * Defines the handler type description. * @see ComponentTypeDescription */ private class HandlerTypeDescription extends ComponentTypeDescription { /** * Creates the HandlerTypeDescription. * @param factory the factory. */ public HandlerTypeDescription(IPojoFactory factory) { super(factory); } /** * Add properties to publish. * <li>handler.name</li> * <li>handler.namespace</li> * <li>handler.type</li> * <li>handler.level if the level is not Integer.MAX</li> * @return returns the dictionary to publish. * @see org.apache.felix.ipojo.architecture.ComponentTypeDescription#getPropertiesToPublish() */ public Dictionary getPropertiesToPublish() { Dictionary props = super.getPropertiesToPublish(); props.put(Handler.HANDLER_NAME_PROPERTY, m_factoryName); props.put(Handler.HANDLER_NAMESPACE_PROPERTY, m_namespace); props.put(Handler.HANDLER_TYPE_PROPERTY, m_type); if (m_level != Integer.MAX_VALUE) { props.put(Handler.HANDLER_LEVEL_PROPERTY, new Integer(m_level)); } return props; } public String[] getFactoryInterfacesToPublish() { return new String[] {HandlerFactory.class.getName()}; } } }