/* * 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.composite.service.instantiator; import java.util.Comparator; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.Set; import org.apache.felix.ipojo.ComponentInstance; import org.apache.felix.ipojo.ConfigurationException; import org.apache.felix.ipojo.Factory; import org.apache.felix.ipojo.MissingHandlerException; import org.apache.felix.ipojo.UnacceptableConfiguration; import org.apache.felix.ipojo.architecture.ComponentTypeDescription; import org.apache.felix.ipojo.architecture.PropertyDescription; import org.apache.felix.ipojo.util.DependencyModel; import org.osgi.framework.Filter; import org.osgi.framework.ServiceReference; /** * Manage a service instantiation. This service create component instance providing the required service specification. * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> */ public class SvcInstance extends DependencyModel { /** * Configuration to push to the instance. */ private Dictionary m_configuration; /** * Handler creating the service instance. */ private ServiceDependencyHandler m_handler; /** * Map of matching factories Service Reference => instance or null (null if the service reference is not actually used). */ private Map /* <ServiceReference, Instance> */m_factories = new HashMap(); /** * Required specification. */ private String m_specification; /** * Is the service provider frozen ? (Is used for static biding policy) */ private boolean m_isFrozen; /** * Constructor. * @param handler : the handler. * @param spec : required specification. * @param conf : instance configuration. * @param isAgg : is the service instance an aggregate service ? * @param isOpt : is the service instance optional ? * @param filt : LDAP filter * @param cmp : comparator to use for the tracking * @param policy : binding policy * @throws ConfigurationException : an attribute cannot be parsed correctly, or is incorrect. */ public SvcInstance(ServiceDependencyHandler handler, String spec, Dictionary conf, boolean isAgg, boolean isOpt, Filter filt, Comparator cmp, int policy) throws ConfigurationException { super(Factory.class, isAgg, isOpt, filt, cmp, policy, null, handler, handler.getCompositeManager()); m_specification = spec; m_handler = handler; setBundleContext(m_handler.getCompositeManager().getServiceContext()); m_configuration = conf; } /** * Stop the service instance. */ public void stop() { super.stop(); Set keys = m_factories.keySet(); Iterator iterator = keys.iterator(); while (iterator.hasNext()) { ServiceReference ref = (ServiceReference) iterator.next(); Object object = m_factories.get(ref); if (object != null) { m_handler.info("Dispose a service instance when stopping the handler " + ((ComponentInstance) object).getInstanceName()); ((ComponentInstance) object).dispose(); } } m_factories.clear(); } public boolean isFrozen() { return m_isFrozen; } /** * Freeze the set of used provider. * This method is when the static binding policy is applied. */ public void freeze() { m_isFrozen = true; } /** * Unfreezes. */ public void unfreeze() { m_isFrozen = false; } /** * Create an instance for the given reference. The instance is not added inside the map. * @param factory : the factory from which we need to create the instance. * @return the created component instance. * @throws ConfigurationException : the instance cannot be configured correctly. * @throws MissingHandlerException : the factory is invalid. * @throws UnacceptableConfiguration : the given configuration is invalid for the given factory. */ private ComponentInstance createInstance(Factory factory) throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException { // Recreate the configuration to avoid sharing. Properties props = new Properties(); Enumeration keys = m_configuration.keys(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); props.put(key, m_configuration.get(key)); } ComponentInstance instance = null; instance = factory.createComponentInstance(props); m_handler.info("Creation of a service instance " + instance.getInstanceName()); return instance; } /** * Does the service instance match with the given factory ? * @param fact : the factory to test. * @return true if the factory match, false otherwise. */ public boolean match(ServiceReference fact) { // Check if the factory can provide the specification ComponentTypeDescription desc = (ComponentTypeDescription) fact.getProperty("component.description"); if (desc == null) { return false; // No component type description. } String[] provides = desc.getprovidedServiceSpecification(); for (int i = 0; provides != null && i < provides.length; i++) { if (provides[i].equals(m_specification)) { // Check that the factory needs every properties contained in // the configuration PropertyDescription[] props = desc.getProperties(); Properties conf = new Properties(); Enumeration keys = m_configuration.keys(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); if (!containsProperty(key, props)) { return false; } conf.put(key, m_configuration.get(key)); } Factory factory = (Factory) getService(fact); return factory.isAcceptable(conf); } } return false; } /** * Does the factory support the given property ? This method check if the property is contained in the given property description array. * @param name : name of the property * @param props : list of property description * @return true if the factory support this property */ private boolean containsProperty(String name, org.apache.felix.ipojo.architecture.PropertyDescription[] props) { for (int i = 0; props != null && i < props.length; i++) { if (props[i].getName().equalsIgnoreCase(name)) { return true; } } if (name.equalsIgnoreCase("name")) { return true; } // Skip the name property return false; } /** * Get the required specification. * @return the required specification. */ public String getServiceSpecification() { return m_specification; } /** * Get the map of used references [reference, component instance]. * @return the map of used references. */ protected Map getMatchingFactories() { return m_factories; } /** * On Dependency Reconfiguration notification method. * @param departs : leaving service references. * @param arrivals : new injected service references. * @see org.apache.felix.ipojo.util.DependencyModel#onDependencyReconfiguration(org.osgi.framework.ServiceReference[], org.osgi.framework.ServiceReference[]) */ public void onDependencyReconfiguration(ServiceReference[] departs, ServiceReference[] arrivals) { for (int i = 0; departs != null && i < departs.length; i++) { onServiceDeparture(departs[i]); } for (int i = 0; arrivals != null && i < arrivals.length; i++) { onServiceArrival(arrivals[i]); } } /** * A new service is injected. * This method create the sub-service instance in the composite. * @param ref : service reference. * @see org.apache.felix.ipojo.util.DependencyModel#onServiceArrival(org.osgi.framework.ServiceReference) */ public void onServiceArrival(ServiceReference ref) { // The given factory matches. try { Factory fact = (Factory) getService(ref); if (m_factories.get(ref) == null) { ComponentInstance instance = createInstance(fact); m_factories.put(ref, instance); } else { m_handler .info("An arriving factory is already used, ignore the creation : " + fact.getName()); } } catch (UnacceptableConfiguration e) { m_handler.error("A matching factory refuses the actual configuration : " + e.getMessage()); m_handler.getCompositeManager().stop(); } catch (MissingHandlerException e) { m_handler.error("A matching factory is no more valid : " + e.getMessage()); m_handler.getCompositeManager().stop(); } catch (ConfigurationException e) { m_handler.error("A matching configuration is refused by the instance : " + e.getMessage()); m_handler.getCompositeManager().stop(); } } /** * A used service is leaving. * This method dispose the created instance. * @param ref : leaving service reference. * @see org.apache.felix.ipojo.util.DependencyModel#onServiceDeparture(org.osgi.framework.ServiceReference) */ public void onServiceDeparture(ServiceReference ref) { // Remove the reference is contained Object instance = m_factories.remove(ref); if (instance != null) { m_handler.info("Dispose the instance (departure of the factory) " + ((ComponentInstance) instance).getInstanceName()); ((ComponentInstance) instance).dispose(); } } /** * A factory is modified. This should not happen. * @param arg0 the service reference * @see org.apache.felix.ipojo.util.DependencyModel#onServiceModification(org.osgi.framework.ServiceReference) */ public void onServiceModification(ServiceReference arg0) { // Nothing to do. } }