FELIX-4305: All aspect dependency callbacks are proxied in order to propagate original service properties modification.
Added setServiceProperties used to update current aspect service properties.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1551348 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java
index 08d6a3a..871691b 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java
@@ -19,15 +19,22 @@
package org.apache.felix.dm.impl;
import java.util.ArrayList;
+import java.util.Dictionary;
import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.ComponentStateListener;
import org.apache.felix.dm.Dependency;
import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.DependencyService;
import org.apache.felix.dm.ServiceDependency;
+import org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
@@ -38,10 +45,23 @@
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class AspectServiceImpl extends FilterService {
+ private final String m_add;
+ private final String m_change;
+ private final String m_remove;
+ private final String m_swap;
+ private final String m_aspectFilter;
+ private final int m_ranking; // the aspect ranking
+
public AspectServiceImpl(DependencyManager dm, Class aspectInterface, String aspectFilter, int ranking, String autoConfig, String add, String change, String remove, String swap)
{
super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
- m_component.setImplementation(new AspectImpl(aspectInterface, aspectFilter, ranking, autoConfig, add, change, remove, swap))
+ m_ranking = ranking;
+ m_add = add;
+ m_change = change;
+ m_remove = remove;
+ m_swap = swap;
+ m_aspectFilter = aspectFilter;
+ m_component.setImplementation(new AspectImpl(aspectInterface, autoConfig))
.add(dm.createServiceDependency()
.setService(aspectInterface, createDependencyFilterForAspect(aspectFilter))
.setAutoConfig(false)
@@ -59,53 +79,84 @@
}
}
+ private Properties getServiceProperties(ServiceReference ref) {
+ Properties props = new Properties();
+ String[] keys = ref.getPropertyKeys();
+ for (int i = 0; i < keys.length; i++) {
+ String key = keys[i];
+ if (key.equals(Constants.SERVICE_ID) || key.equals(Constants.SERVICE_RANKING) || key.equals(DependencyManager.ASPECT) || key.equals(Constants.OBJECTCLASS)) {
+ // do not copy these
+ }
+ else {
+ props.put(key, ref.getProperty(key));
+ }
+ }
+ if (m_serviceProperties != null) {
+ Enumeration e = m_serviceProperties.keys();
+ while (e.hasMoreElements()) {
+ Object key = e.nextElement();
+ props.put(key, m_serviceProperties.get(key));
+ }
+ }
+ // finally add our aspect property
+ props.put(DependencyManager.ASPECT, ref.getProperty(Constants.SERVICE_ID));
+ // and the ranking
+ props.put(Constants.SERVICE_RANKING, Integer.valueOf(m_ranking));
+ return props;
+ }
+
/**
* This class is the Aspect Implementation. It will create the actual Aspect Service, and
* will use the Aspect Service parameters provided by our enclosing class.
*/
class AspectImpl extends AbstractDecorator {
- private final Class m_aspectInterface; // the service decorated by this aspect
- private final String m_aspectFilter; // the service filter decorated by this aspect
- private final int m_ranking; // the aspect ranking
private final String m_autoConfig; // the aspect impl field name where to inject decorated service
- private final String m_add;
- private final String m_change;
- private final String m_remove;
- private final String m_swap;
+ private final Class m_aspectInterface; // the service decorated by this aspect
- public AspectImpl(Class aspectInterface, String aspectFilter, int ranking, String autoConfig, String add, String change, String remove, String swap) {
+ public AspectImpl(Class aspectInterface, String autoConfig) {
m_aspectInterface = aspectInterface;
- m_aspectFilter = aspectFilter;
- m_ranking = ranking;
m_autoConfig = autoConfig;
- m_add = add;
- m_change = change;
- m_remove = remove;
- m_swap = swap;
}
+ /**
+ * Creates an aspect implementation component for a new original service.
+ * @param param First entry contains the ref to the original service
+ */
public Component createService(Object[] params) {
- List dependencies = m_component.getDependencies();
- // remove our internal dependency
- dependencies.remove(0);
- // replace it with one that points to the specific service that just was passed in
- Properties serviceProperties = getServiceProperties(params);
- String[] serviceInterfaces = getServiceInterfaces();
+ // Get the new original service reference.
ServiceReference ref = (ServiceReference) params[0];
- ServiceDependency dependency = m_manager.createServiceDependency().setService(m_aspectInterface, createAspectFilter(ref)).setRequired(true);
+ List dependencies = m_component.getDependencies();
+ // remove our internal dependency, replace it with one that points to the specific service that just was passed in.
+ dependencies.remove(0);
+ Properties serviceProperties = getServiceProperties(ref);
+ String[] serviceInterfaces = getServiceInterfaces();
+
+ ServiceDependency aspectDependency = (ServiceDependencyImpl)
+ m_manager.createServiceDependency().setService(m_aspectInterface, createAspectFilter(ref)).setRequired(true);
+
+// aspectDependency.setDebug("AspectDependency#" +
+// (m_serviceImpl instanceof Class ? (((Class) m_serviceImpl).getSimpleName()) : m_serviceImpl));
+
+ aspectDependency.setCallbacks(new CallbackProxy(aspectDependency, ref),
+ m_add != null ? "addAspect" : null,
+ "changeAspect", // We have to propagate in case aspect does not have a change callback
+ m_remove != null ? "removeAspect" : null,
+ m_swap != null ? "swapAspect" : null);
+
if (m_autoConfig != null) {
- dependency.setAutoConfig(m_autoConfig);
+ aspectDependency.setAutoConfig(m_autoConfig);
+ } else if (m_add == null && m_change == null && m_remove == null && m_swap == null) {
+ // Since we have set callbacks, we must reactivate setAutoConfig because user has not specified any callbacks.
+ aspectDependency.setAutoConfig(true);
}
- if (m_add != null || m_change != null || m_remove != null || m_swap != null) {
- dependency.setCallbacks(m_add, m_change, m_remove, m_swap);
- }
+
Component service = m_manager.createComponent()
.setInterface(serviceInterfaces, serviceProperties)
.setImplementation(m_serviceImpl)
.setFactory(m_factory, m_factoryCreateMethod) // if not set, no effect
.setComposition(m_compositionInstance, m_compositionMethod) // if not set, no effect
.setCallbacks(m_callbackObject, m_init, m_start, m_stop, m_destroy) // if not set, no effect
- .add(dependency);
+ .add(aspectDependency);
configureAutoConfigState(service, m_component);
@@ -119,33 +170,23 @@
return service;
}
- private Properties getServiceProperties(Object[] params) {
- ServiceReference ref = (ServiceReference) params[0];
- Properties props = new Properties();
- String[] keys = ref.getPropertyKeys();
- for (int i = 0; i < keys.length; i++) {
- String key = keys[i];
- if (key.equals(Constants.SERVICE_ID) || key.equals(Constants.SERVICE_RANKING) || key.equals(DependencyManager.ASPECT) || key.equals(Constants.OBJECTCLASS)) {
- // do not copy these
- }
- else {
- props.put(key, ref.getProperty(key));
- }
+ /**
+ * Modify some specific aspect service properties.
+ */
+ public void setServiceProperties(Dictionary props) {
+ Map services = super.getServices();
+ Iterator it = services.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ ServiceReference originalServiceRef = (ServiceReference) entry.getKey();
+ Component c = (Component) entry.getValue();
+ // m_serviceProperties is already set to the new service properties; and the getServiceProperties will
+ // merge m_serviceProperties with the original service properties.
+ Dictionary newProps = getServiceProperties(originalServiceRef);
+ c.setServiceProperties(newProps);
}
- if (m_serviceProperties != null) {
- Enumeration e = m_serviceProperties.keys();
- while (e.hasMoreElements()) {
- Object key = e.nextElement();
- props.put(key, m_serviceProperties.get(key));
- }
- }
- // finally add our aspect property
- props.put(DependencyManager.ASPECT, ref.getProperty(Constants.SERVICE_ID));
- // and the ranking
- props.put(Constants.SERVICE_RANKING, Integer.valueOf(m_ranking));
- return props;
}
-
+
private String[] getServiceInterfaces() {
List serviceNames = new ArrayList();
// Of course, we provide the aspect interface.
@@ -170,4 +211,43 @@
return "Aspect for " + m_aspectInterface + ((m_aspectFilter != null) ? " with filter " + m_aspectFilter : "");
}
}
+
+ class CallbackProxy {
+ private final ServiceDependencyImpl m_aspectDependency;
+ private final ServiceReference m_originalServiceRef;
+
+ CallbackProxy(ServiceDependency aspectDependency, ServiceReference originalServiceRef) {
+ m_aspectDependency = (ServiceDependencyImpl) aspectDependency;
+ m_originalServiceRef = originalServiceRef;
+ }
+
+ private void addAspect(Component c, ServiceReference ref, Object service) {
+ // Just forward "add" service dependency callback.
+ m_aspectDependency.invoke(c.getCompositionInstances(), (DependencyService) c, ref, service, m_add);
+ }
+
+ private void changeAspect(Component c, ServiceReference ref, Object service) {
+ // Invoke "change" service dependency callback
+ if (m_change != null) {
+ m_aspectDependency.invoke(c.getCompositionInstances(), (DependencyService) c, ref, service, m_change);
+ }
+ // Propagate change to immediate higher aspect, or to client using our aspect.
+ // We always propagate our own properties, and the ones from the original service, but we don't inherit
+ // from lower ranked aspect service properties.
+ Dictionary props = getServiceProperties(m_originalServiceRef);
+ c.setServiceProperties(props);
+ }
+
+ private void removeAspect(Component c, ServiceReference ref, Object service) {
+ // Just forward "remove" service dependency callback.
+ m_aspectDependency.invoke(c.getCompositionInstances(), (DependencyService) c, ref, service, m_remove);
+ }
+
+ private void swapAspect(Component c, ServiceReference prevRef, Object prev, ServiceReference currRef,
+ Object curr) {
+ // Just forward "swap" service dependency callback.
+ m_aspectDependency.invokeSwappedCallback(c.getCompositionInstances(), (DependencyService) c, prevRef, prev,
+ currRef, curr, m_swap);
+ }
+ }
}