001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.felix.ipojo;
020
021import java.util.ArrayList;
022import java.util.Dictionary;
023import java.util.List;
024
025import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
026import org.apache.felix.ipojo.metadata.Element;
027import org.osgi.framework.BundleContext;
028
029/**
030 * Implementation of the handler factory interface.
031 * This factory is able to create handler manager.
032 * A handler manager is an iPOJO instance containing a handler object.
033 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
034 */
035public class HandlerManagerFactory extends ComponentFactory implements HandlerFactory {
036
037    /**
038     * The Handler type (<code>composite</code> or <code>primitive</code>).
039     */
040    private final String m_type;
041
042    /**
043     * The iPOJO Handler Namespace.
044     * (Uses the iPOJO default namespace is not specified)
045     */
046    private final String m_namespace;
047
048    /**
049     * The handler start level.
050     * Lower levels are priority and so are configured and started
051     * before higher levels, and are stopped after.
052     */
053    private final int m_level;
054
055    /**
056     * Creates a handler factory.
057     * @param context the bundle context
058     * @param metadata the metadata of the component to create
059     * @throws ConfigurationException if the element describing the factory is malformed.
060     */
061    public HandlerManagerFactory(BundleContext context, Element metadata) throws ConfigurationException {
062        super(context, metadata);
063
064        // Get the name
065        m_factoryName = metadata.getAttribute("name");
066        if (m_factoryName == null) { throw new ConfigurationException("A Handler needs a name"); }
067
068        // Get the type
069        String type = metadata.getAttribute("type");
070        if (type != null) {
071            m_type = type;
072        } else {
073            m_type = "primitive"; // Set to primitive if not specified.
074        }
075
076        String level = metadata.getAttribute("level");
077        if (level != null) {
078            m_level = new Integer(level).intValue();
079        } else {
080            m_level = Integer.MAX_VALUE; // Set to max if not specified.
081        }
082
083        // Get the namespace
084        String namespace = metadata.getAttribute("namespace");
085        if (namespace != null) {
086            m_namespace = namespace.toLowerCase();
087        } else {
088            m_namespace = IPOJO_NAMESPACE; // Set to the iPOJO default namespace if not specified.
089        }
090    }
091
092    public String getNamespace() {
093        return m_namespace;
094    }
095
096    public String getHandlerName() {
097        return m_namespace + ":" + getName();
098    }
099
100    public String getType() {
101        return m_type;
102    }
103
104    public int getStartLevel() {
105        return m_level;
106    }
107
108    public ComponentTypeDescription getComponentTypeDescription() {
109        return new HandlerTypeDescription(this);
110    }
111
112    public String getFactoryName() {
113        if ("composite".equals(m_type) && IPOJO_NAMESPACE.equals(m_namespace)) {
114            // Artificially change the factory name, to avoid name clash when we generate the instance name.
115            return m_namespace + ".composite:" + getName();
116        }
117        return getHandlerName();
118    }
119
120    /**
121     * Stops the factory.
122     * This method does not disposed created instances.
123     * These instances will be disposed by the instance managers.
124     * This method is called with the lock.
125     */
126    public void stopping() {
127        if (m_tracker != null) {
128            m_tracker.close();
129            m_tracker = null;
130        }
131    }
132
133    /**
134     * Creates an instance. The given configuration needs to contain the 'name'
135     * property. This method is called when holding the lock.
136     * @param configuration the configuration of the created instance.
137     * @param context  the service context to push for this instance.
138     * @param handlers the handler array to attach to the instance.
139     * @return the created {@link HandlerManager}.
140     * @throws org.apache.felix.ipojo.ConfigurationException if the instance configuration failed.
141     * @see org.apache.felix.ipojo.Factory#createComponentInstance(java.util.Dictionary)
142     */
143    public ComponentInstance createInstance(Dictionary configuration, IPojoContext context, HandlerManager[] handlers) throws ConfigurationException {
144        HandlerManager instance = new HandlerManager(this, context, handlers);
145        instance.configure(m_componentMetadata, configuration);
146        return instance;
147    }
148
149
150    /**
151     * Computes required handlers. This method does not manipulate any
152     * non-immutable fields, so does not need to be synchronized.
153     * This method is overridden to avoid using the same detection rules
154     * than 'primitive' components. Indeed, architecture is disable by default,
155     * and a handler is never immediate.
156     * @return the required handler list.
157     */
158    public List<RequiredHandler> getRequiredHandlerList() {
159        List<RequiredHandler> list = new ArrayList<RequiredHandler>();
160        Element[] elems = m_componentMetadata.getElements();
161        for (int i = 0; i < elems.length; i++) {
162            Element current = elems[i];
163            if (!"manipulation".equals(current.getName())) { // Remove the manipulation element
164                RequiredHandler req = new RequiredHandler(current.getName(),
165                        current.getNameSpace());
166                if (!list.contains(req)) {
167                    list.add(req);
168                }
169            }
170        }
171
172        // Unlike normal components, the architecture is enable only when
173        // specified.
174        String arch = m_componentMetadata.getAttribute("architecture");
175        if (arch != null && arch.equalsIgnoreCase("true")) {
176            list.add(new RequiredHandler("architecture", null));
177        }
178
179        // The auto-attached handler list is ignored for handlers to avoid loops.
180
181        return list;
182    }
183
184    /**
185     * Defines the handler type description.
186     * @see ComponentTypeDescription
187     */
188    private class HandlerTypeDescription extends ComponentTypeDescription {
189
190        /**
191         * Creates the HandlerTypeDescription.
192         * @param factory the factory.
193         */
194        public HandlerTypeDescription(IPojoFactory factory) {
195            super(factory);
196        }
197
198        /**
199         * Add properties to publish.
200         * <li>handler.name</li>
201         * <li>handler.namespace</li>
202         * <li>handler.type</li>
203         * <li>handler.level if the level is not Integer.MAX</li>
204         * @return returns the dictionary to publish.
205         * @see org.apache.felix.ipojo.architecture.ComponentTypeDescription#getPropertiesToPublish()
206         */
207        public Dictionary getPropertiesToPublish() {
208            Dictionary props = super.getPropertiesToPublish();
209
210            props.put(Handler.HANDLER_NAME_PROPERTY, m_factoryName);
211            props.put(Handler.HANDLER_NAMESPACE_PROPERTY, m_namespace);
212            props.put(Handler.HANDLER_TYPE_PROPERTY, m_type);
213            if (m_level != Integer.MAX_VALUE) {
214                props.put(Handler.HANDLER_LEVEL_PROPERTY, new Integer(m_level));
215            }
216            return props;
217        }
218
219        public String[] getFactoryInterfacesToPublish() {
220            return new String[] {HandlerFactory.class.getName()};
221        }
222    }
223}