/* | |
* 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. | |
} | |
} |