/* | |
* 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.ArrayList; | |
import java.util.Comparator; | |
import java.util.Dictionary; | |
import java.util.List; | |
import java.util.Properties; | |
import org.apache.felix.ipojo.PolicyServiceContext; | |
import org.apache.felix.ipojo.util.DependencyModel; | |
import org.osgi.framework.BundleContext; | |
import org.osgi.framework.Filter; | |
import org.osgi.framework.ServiceReference; | |
import org.osgi.framework.ServiceRegistration; | |
/** | |
* Import a service form the parent to the internal service registry. | |
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a> | |
*/ | |
public class ServiceImporter extends DependencyModel { | |
/** | |
* Reference on the handler. | |
*/ | |
private ServiceDependencyHandler m_handler; | |
private final class Record { | |
/** | |
* External Reference. | |
*/ | |
private ServiceReference m_ref; | |
/** | |
* Internal Registration. | |
*/ | |
private ServiceRegistration m_reg; | |
/** | |
* Exposed Object. | |
*/ | |
private Object m_svcObject; | |
/** | |
* Constructor. | |
* @param ref : service reference. | |
*/ | |
protected Record(ServiceReference ref) { | |
m_ref = ref; | |
} | |
/** | |
* Register the current import. | |
*/ | |
private void register() { | |
if (m_reg != null) { | |
m_reg.unregister(); | |
} | |
m_svcObject = getService(m_ref); | |
m_reg = m_handler.getCompositeManager().getServiceContext() | |
.registerService(getSpecification().getName(), m_svcObject, getProps(m_ref)); | |
} | |
/** | |
* Update the current import. | |
*/ | |
private void update() { | |
if (m_reg != null) { | |
m_reg.setProperties(getProps(m_ref)); | |
} | |
} | |
/** | |
* Unregister and release the current import. | |
*/ | |
private void dispose() { | |
if (m_reg != null) { | |
m_reg.unregister(); | |
m_svcObject = null; | |
m_reg = null; | |
} | |
m_ref = null; | |
} | |
/** | |
* Test object equality. | |
* @param object : object to confront against the current object. | |
* @return true if the two objects are equals (same service reference). | |
* @see java.lang.Object#equals(java.lang.Object) | |
*/ | |
public boolean equals(Object object) { | |
if (object instanceof Record) { | |
Record rec = (Record) object; | |
return rec.m_ref == m_ref; | |
} | |
return false; | |
} | |
/** | |
* Hash code method. | |
* @return the hash code by calling the parent method. | |
*/ | |
public int hashCode() { | |
return super.hashCode(); | |
} | |
} | |
/** | |
* List of managed records. | |
*/ | |
private List/*<Record>*/m_records = new ArrayList()/* <Record> */; | |
/** | |
* Requirement Id. | |
*/ | |
private String m_id; | |
/** | |
* Is this requirement attached to a service-level requirement. | |
*/ | |
private boolean m_specLevelReq; | |
/** | |
* Is the set of used provider frozen ? | |
*/ | |
private boolean m_isFrozen; | |
/** | |
* Constructor. | |
* | |
* @param specification : targeted specification | |
* @param filter : LDAP filter | |
* @param multiple : should the importer imports several services ? | |
* @param optional : is the import optional ? | |
* @param cmp : comparator to use for the tracking | |
* @param policy : resolving policy | |
* @param context : bundle context to use for the tracking (can be a servie context) | |
* @param identitity : requirement id (may be null) | |
* @param handler : handler | |
*/ | |
public ServiceImporter(Class specification, Filter filter, boolean multiple, boolean optional, Comparator cmp, int policy, BundleContext context, String identitity | |
, ServiceDependencyHandler handler) { | |
super(specification, multiple, optional, filter, cmp, policy, context, handler, handler.getCompositeManager()); | |
this.m_handler = handler; | |
if (m_id == null) { | |
m_id = super.getSpecification().getName(); | |
} else { | |
m_id = identitity; | |
} | |
} | |
/** | |
* Get the properties for the exposed service from the given reference. | |
* | |
* @param ref : the reference. | |
* @return the property dictionary | |
*/ | |
private static Dictionary getProps(ServiceReference ref) { | |
Properties prop = new Properties(); | |
String[] keys = ref.getPropertyKeys(); | |
for (int i = 0; i < keys.length; i++) { | |
prop.put(keys[i], ref.getProperty(keys[i])); | |
} | |
return prop; | |
} | |
/** | |
* Freeze the set of used provider. | |
* This method allow to fix the set of provider when the static binding policy is used. | |
*/ | |
public void freeze() { | |
m_isFrozen = true; | |
} | |
/** | |
* Unfreezes. | |
*/ | |
public void unfreeze() { | |
m_isFrozen = false; | |
} | |
public boolean isFrozen() { | |
return m_isFrozen; | |
} | |
/** | |
* Stop the management of the import. | |
*/ | |
public void stop() { | |
super.stop(); | |
for (int i = 0; i < m_records.size(); i++) { | |
Record rec = (Record) m_records.get(i); | |
rec.dispose(); | |
} | |
m_records.clear(); | |
} | |
/** | |
* Get the record list using the given reference. | |
* | |
* @param ref : the reference | |
* @return the list containing all record using the given reference | |
*/ | |
private List/* <Record> */getRecordsByRef(ServiceReference ref) { | |
List list = new ArrayList(); | |
for (int i = 0; i < m_records.size(); i++) { | |
Record rec = (Record) m_records.get(i); | |
if (rec.m_ref == ref) { | |
list.add(rec); | |
} | |
} | |
return list; | |
} | |
/** | |
* Build the list of imported service provider. | |
* @return the list of all imported services. | |
*/ | |
public List getProviders() { | |
List list = new ArrayList(); | |
for (int i = 0; i < m_records.size(); i++) { | |
list.add((((Record) m_records.get(i)).m_ref).getProperty("instance.name")); | |
} | |
return list; | |
} | |
/** | |
* Set that this dependency is a service level dependency. | |
* This forces the scoping policy to be STRICT. | |
* @param b | |
*/ | |
public void setServiceLevelDependency() { | |
m_specLevelReq = true; | |
PolicyServiceContext context = new PolicyServiceContext(m_handler.getCompositeManager().getGlobalContext(), m_handler.getCompositeManager().getParentServiceContext(), PolicyServiceContext.LOCAL); | |
setBundleContext(context); | |
} | |
public String getId() { | |
return m_id; | |
} | |
public boolean isServiceLevelRequirement() { | |
return m_specLevelReq; | |
} | |
/** | |
* 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 by the tracker. | |
* This method create a 'Record' and register it. | |
* @param ref : new service reference. | |
* @see org.apache.felix.ipojo.util.DependencyModel#onServiceArrival(org.osgi.framework.ServiceReference) | |
*/ | |
public void onServiceArrival(ServiceReference ref) { | |
Record rec = new Record(ref); | |
m_records.add(rec); | |
// Always register the reference, as the method is call only when needed. | |
rec.register(); | |
} | |
/** | |
* A used service disappears. | |
* This method find the implicated 'Record', dispose it and remove it from the list. | |
* @param ref : leaving service reference. | |
* @see org.apache.felix.ipojo.util.DependencyModel#onServiceDeparture(org.osgi.framework.ServiceReference) | |
*/ | |
public void onServiceDeparture(ServiceReference ref) { | |
List list = getRecordsByRef(ref); | |
for (int i = 0; i < list.size(); i++) { // Stop the implied record | |
Record rec = (Record) list.get(i); | |
rec.dispose(); | |
} | |
m_records.removeAll(list); | |
} | |
/** | |
* A used service is modified. | |
* @param ref : modified service reference. | |
* @see org.apache.felix.ipojo.util.DependencyModel#onServiceModification(org.osgi.framework.ServiceReference) | |
*/ | |
public void onServiceModification(ServiceReference ref) { | |
List list = getRecordsByRef(ref); | |
for (int i = 0; i < list.size(); i++) { // Stop the implied record | |
Record rec = (Record) list.get(i); | |
rec.update(); | |
} | |
} | |
} |