blob: d61d347a9fc8acb5dbe424cd17f2229aa21af767 [file] [log] [blame]
/*
* 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.
}
}