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.architecture;
020
021import org.apache.felix.ipojo.Factory;
022import org.apache.felix.ipojo.IPojoFactory;
023import org.apache.felix.ipojo.metadata.Attribute;
024import org.apache.felix.ipojo.metadata.Element;
025import org.osgi.framework.BundleContext;
026import org.osgi.framework.Constants;
027import org.osgi.service.cm.ManagedServiceFactory;
028
029import java.util.Dictionary;
030import java.util.Enumeration;
031import java.util.Hashtable;
032
033/**
034 * Component Type description.
035 *
036 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
037 */
038public class ComponentTypeDescription {
039
040    /**
041     * Represented factory.
042     */
043    private final IPojoFactory m_factory;
044    /**
045     * Provided service by the component type.
046     */
047    private String[] m_providedServiceSpecification = new String[0];
048    /**
049     * Configuration Properties accepted by the component type.
050     */
051    private PropertyDescription[] m_properties = new PropertyDescription[0];
052    /*
053     * Used by custom handlers to keep and retrieve custom info.
054     */
055    private Dictionary m_handlerInfoSlot = new Hashtable();
056
057    /**
058     * Constructor.
059     *
060     * @param factory : represented factory.
061     */
062    public ComponentTypeDescription(IPojoFactory factory) {
063        m_factory = factory;
064    }
065
066    /**
067     * Gets the attached factory.
068     *
069     * @return the factory
070     */
071    public IPojoFactory getFactory() {
072        return m_factory;
073    }
074
075    /**
076     * Gets a printable form of the current component type description.
077     *
078     * @return printable form of the component type description
079     * @see java.lang.Object#toString()
080     */
081    public String toString() {
082        return getDescription().toString();
083    }
084
085    /**
086     * Gets the implementation class of this component type.
087     *
088     * @return the component type implementation class name.
089     * @deprecated
090     */
091    public String getClassName() {
092        return m_factory.getClassName();
093    }
094
095    /**
096     * Gets the component type version.
097     *
098     * @return the component type version or
099     *         <code>null</code> if not set.
100     */
101    public String getVersion() {
102        return m_factory.getVersion();
103    }
104
105    /**
106     * Gets component-type properties.
107     *
108     * @return the list of configuration properties accepted by the component type type.
109     */
110    public PropertyDescription[] getProperties() {
111        return m_properties;
112    }
113
114    /**
115     * Adds a String property in the component type.
116     *
117     * @param name  : property name.
118     * @param value : property value.
119     */
120    public void addProperty(String name, String value) {
121        addProperty(name, value, false);
122    }
123
124    /**
125     * Adds a String property in the component type.
126     *
127     * @param name      : property name.
128     * @param value     : property value.
129     * @param immutable : the property is immutable.
130     */
131    public void addProperty(String name, String value, boolean immutable) {
132        addProperty(new PropertyDescription(name, String.class.getName(), value, immutable));
133    }
134
135    /**
136     * Adds a configuration properties to the component type.
137     *
138     * @param pd : the property to add
139     */
140    public void addProperty(PropertyDescription pd) { //NOPMD remove the instance name of the 'name' property.
141        String name = pd.getName();
142
143        // Check if the property is not already in the array
144        for (int i = 0; i < m_properties.length; i++) {
145            PropertyDescription desc = m_properties[i];
146            if (desc.getName().equals(name)) {
147                return;
148            }
149        }
150
151        PropertyDescription[] newProps = new PropertyDescription[m_properties.length + 1];
152        System.arraycopy(m_properties, 0, newProps, 0, m_properties.length);
153        newProps[m_properties.length] = pd;
154        m_properties = newProps;
155    }
156
157    /**
158     * Adds the HandlerInfo for specified handler.
159     *
160     * @param handlerNs   Handler's namespace
161     * @param handlerName Handler's name
162     * @param info        HandlerInfo associated with the given custom handler.
163     */
164    public void setHandlerInfo(String handlerNs, String handlerName, CustomHandlerInfo info) {
165        String fullHandlerName = handlerNs + ":" + handlerName;
166
167        if (info == null) {
168            m_handlerInfoSlot.remove(fullHandlerName);
169        } else {
170            m_handlerInfoSlot.put(fullHandlerName, info);
171        }
172    }
173
174    public CustomHandlerInfo getHandlerInfo(String handlerNs, String handlerName) {
175        String fullHandlerName = handlerNs + ":" + handlerName;
176        return (CustomHandlerInfo) m_handlerInfoSlot.get(fullHandlerName);
177    }
178
179    /**
180     * Gets the list of provided service offered by instances of this type.
181     *
182     * @return the list of the provided service.
183     */
184    public String[] getprovidedServiceSpecification() {
185        return m_providedServiceSpecification;
186    }
187
188    /**
189     * Adds a provided service to the component type.
190     *
191     * @param serviceSpecification : the provided service to add (interface name)
192     */
193    public void addProvidedServiceSpecification(String serviceSpecification) {
194        String[] newSs = new String[m_providedServiceSpecification.length + 1];
195        System.arraycopy(m_providedServiceSpecification, 0, newSs, 0, m_providedServiceSpecification.length);
196        newSs[m_providedServiceSpecification.length] = serviceSpecification;
197        m_providedServiceSpecification = newSs;
198    }
199
200    /**
201     * Returns the component-type name.
202     *
203     * @return the name of this component type
204     */
205    public String getName() {
206        return m_factory.getName();
207    }
208
209    /**
210     * Computes the default service properties to publish :
211     * factory.name, service.pid, component.providedServiceSpecification, component.properties, component.description, factory.State.
212     *
213     * @return : the dictionary of properties to publish.
214     */
215    public Dictionary<String, Object> getPropertiesToPublish() {
216        Hashtable<String, Object> props = new Hashtable<String, Object>();
217
218        props.put("factory.name", m_factory.getName());
219        props.put(Constants.SERVICE_PID, m_factory.getName()); // Service PID is required for the integration in the configuration admin.
220
221        // Add the version if set
222        String v = getVersion();
223        if (v != null) {
224            props.put(Factory.FACTORY_VERSION_PROPERTY, v);
225        }
226
227        props.put("component.providedServiceSpecifications", m_providedServiceSpecification);
228        props.put("component.properties", m_properties);
229        props.put("component.description", this);
230
231        // add every immutable property
232        for (PropertyDescription m_property : m_properties) {
233            if (m_property.isImmutable() && m_property.getValue() != null) {
234                props.put(m_property.getName(), m_property.getObjectValue(m_factory.getBundleContext()));
235            }
236        }
237
238        // Add factory state
239        props.put("factory.state", m_factory.getState());
240
241        return props;
242
243    }
244
245    /**
246     * Gets the interfaces published by the factory.
247     * By default publish both {@link Factory} and {@link ManagedServiceFactory}.
248     *
249     * @return : the list of interface published by the factory.
250     */
251    public String[] getFactoryInterfacesToPublish() {
252        return new String[]{Factory.class.getName()};
253    }
254
255    /**
256     * Gets the component type description.
257     *
258     * @return : the description
259     */
260    public Element getDescription() {
261        Element desc = new Element("Factory", "");
262
263        desc.addAttribute(new Attribute("name", m_factory.getName()));
264        desc.addAttribute(
265                new Attribute("bundle",
266                        Long.toString(m_factory.getBundleContext().getBundle().getBundleId())));
267
268        String state = "valid";
269        if (m_factory.getState() == Factory.INVALID) {
270            state = "invalid";
271        }
272        desc.addAttribute(new Attribute("state", state));
273
274        // Display required & missing handlers
275        Element req = new Element("RequiredHandlers", "");
276        req.addAttribute(new Attribute("list", m_factory.getRequiredHandlers().toString()));
277        Element missing = new Element("MissingHandlers", "");
278        missing.addAttribute(new Attribute("list", m_factory.getMissingHandlers().toString()));
279        desc.addElement(req);
280        desc.addElement(missing);
281
282        for (int i = 0; i < m_providedServiceSpecification.length; i++) {
283            Element prov = new Element("provides", "");
284            prov.addAttribute(new Attribute("specification", m_providedServiceSpecification[i]));
285            desc.addElement(prov);
286        }
287
288        for (int i = 0; i < m_properties.length; i++) {
289            Element prop = new Element("property", "");
290            prop.addAttribute(new Attribute("name", m_properties[i].getName()));
291            prop.addAttribute(new Attribute("type", m_properties[i].getType()));
292            if (m_properties[i].isMandatory() && m_properties[i].getValue() == null) {
293                prop.addAttribute(new Attribute("value", "REQUIRED"));
294            } else {
295                prop.addAttribute(new Attribute("value", m_properties[i].getValue()));
296            }
297            desc.addElement(prop);
298        }
299
300        if (m_handlerInfoSlot.size() > 0) {
301            Enumeration keys = m_handlerInfoSlot.keys();
302
303            while (keys.hasMoreElements()) {
304                String fullHandlerName = (String) keys.nextElement();
305
306                CustomHandlerInfo handlerInfo = (CustomHandlerInfo) m_handlerInfoSlot.get(fullHandlerName);
307                desc.addElement(handlerInfo.getDescription());
308            }
309        }
310
311        return desc;
312    }
313
314    public BundleContext getBundleContext() {
315        return m_factory.getBundleContext();
316    }
317
318}