You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2014/09/30 22:30:23 UTC
svn commit: r1628547 [2/2] - in
/felix/sandbox/pderop/dependencymanager-prototype: cnf/
org.apache.felix.dependencymanager.itest/src/org/apache/felix/dm/itest/
org.apache.felix.dependencymanager.runtime.itest/src/org/apache/felix/dm/runtime/itest/tests...
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleDependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleDependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleDependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -21,6 +21,7 @@ package org.apache.felix.dm.impl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.Dictionary;
+import java.util.Set;
import org.apache.felix.dm.BundleDependency;
import org.apache.felix.dm.ComponentDependencyDeclaration;
@@ -74,23 +75,15 @@ public class BundleDependencyImpl extend
}
@Override
- public void start() {
- boolean wasStarted = isStarted();
- super.start();
- if (!wasStarted) {
- m_tracker = new BundleTracker(m_context, m_stateMask, this);
- m_tracker.open();
- }
+ protected void startTracking() {
+ m_tracker = new BundleTracker(m_context, m_stateMask, this);
+ m_tracker.open();
}
@Override
- public void stop() {
- boolean wasStarted = isStarted();
- super.stop();
- if (wasStarted) {
- m_tracker.close();
- m_tracker = null;
- }
+ protected void stopTracking() {
+ m_tracker.close();
+ m_tracker = null;
}
@Override
@@ -179,19 +172,15 @@ public class BundleDependencyImpl extend
}
@Override
- public Object getAutoConfigInstance() {
- return getService();
- }
-
- @Override
public Class<?> getAutoConfigType() {
return Bundle.class;
}
-
+
@Override
public Dictionary<?,?> getProperties() {
- Bundle bundle = (Bundle) getService();
- if (bundle != null) {
+ Event event = getService();
+ if (event != null) {
+ Bundle bundle = (Bundle) event.getEvent();
if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
try {
return (Dictionary<?,?>) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ Bundle.class }}, new Object[][] {{ bundle }});
@@ -214,29 +203,9 @@ public class BundleDependencyImpl extend
}
@Override
- protected Object getService() {
- Bundle service = null;
- if (isStarted()) {
- BundleEventImpl be = (BundleEventImpl) m_component.getDependencyEvent(this);
- return be != null ? be.getBundle() : null;
- }
- else {
- Bundle[] bundles = m_context.getBundles();
- for (int i = 0; i < bundles.length; i++) {
- if ((bundles[i].getState() & m_stateMask) > 0) {
- Filter filter = m_filter;
- if (filter == null) {
- service = bundles[i];
- break;
- }
- else if (filter.match(bundles[i].getHeaders())) {
- service = bundles[i];
- break;
- }
- }
- }
- }
- if (service == null && isAutoConfig()) {
+ public Object getDefaultService() {
+ Object service = null;
+ if (isAutoConfig()) {
// TODO does it make sense to add support for custom bundle impls?
// service = getDefaultImplementation();
if (service == null) {
@@ -245,7 +214,7 @@ public class BundleDependencyImpl extend
}
return service;
}
-
+
private Bundle getNullObject() {
if (m_nullObject == null) {
try {
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleEventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleEventImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleEventImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/BundleEventImpl.java Tue Sep 30 20:30:21 2014
@@ -18,6 +18,8 @@
*/
package org.apache.felix.dm.impl;
+import java.util.Dictionary;
+
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleEvent;
@@ -30,6 +32,16 @@ public class BundleEventImpl extends Eve
m_event = event;
}
+ @Override
+ public Object getEvent() {
+ return getBundle();
+ }
+
+ @Override
+ public Dictionary getProperties() {
+ return m_bundle.getHeaders();
+ }
+
public Bundle getBundle() {
return m_bundle;
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ComponentImpl.java Tue Sep 30 20:30:21 2014
@@ -29,6 +29,7 @@ import java.lang.reflect.InvocationTarge
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
@@ -71,8 +72,7 @@ public class ComponentImpl implements Co
private final Logger m_logger;
private final BundleContext m_context;
private final DependencyManager m_manager;
- private final Object SYNC = new Object();
- private Object m_componentDefinition;
+ private Object m_componentDefinition;
private Object m_componentInstance;
private volatile Object m_serviceName;
private volatile Dictionary m_serviceProperties;
@@ -81,6 +81,7 @@ public class ComponentImpl implements Co
private final Map m_autoConfigInstance = new ConcurrentHashMap();
private final long m_id;
private static AtomicLong m_idGenerator = new AtomicLong();
+ // Holds all the services of a given dependency context. Caution: the last entry in the skiplist is the highest ranked service.
private final Map<DependencyContext, ConcurrentSkipListSet<Event>> m_dependencyEvents = new HashMap<>();
private volatile boolean m_active;
@@ -248,87 +249,110 @@ public class ComponentImpl implements Co
if (debug) {
System.out.println("*" + debugKey + " T" + Thread.currentThread().getId() + " handleAdded " + e);
}
-
- Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
- dependencyEvents.add(e);
- dc.setAvailable(true);
-
- switch (m_state) {
- case WAITING_FOR_REQUIRED:
- if (dc.isRequired())
- handleChange();
- break;
- case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
- if (!dc.isInstanceBound()) {
- if (dc.isRequired()) {
- dc.invokeAdd(e);
- }
- updateInstance(dc);
- }
- else {
+
+ Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
+ dependencyEvents.add(e);
+ dc.setAvailable(true);
+
+ // Recalculate state changes. We only do this if the dependency is started. If the dependency is not started,
+ // it means it is actually starting. And in this case, we don't recalculate state changes now. We'll do it
+ // once all currently available services are found, and then after, we'll recalculate state change
+ // (see the startDependencies method).
+ // All this is done for two reasons:
+ // 1- optimization: it is preferable to recalculate state changes once we know about all currently available dependency services
+ // (after the tracker has returned from its open method).
+ // 2- This also allows to determine the list of currently available dependency services from within the component start method callback
+ // (this will be extremely useful when porting the Felix SCR on top of DM4).
+
+ if (dc.isStarted()) {
+ switch (m_state) {
+ case WAITING_FOR_REQUIRED:
if (dc.isRequired())
handleChange();
+ break;
+ case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+ if (!dc.isInstanceBound()) {
+ if (dc.isRequired()) {
+ dc.invokeAdd(e);
+ }
+ updateInstance(dc, e, false, true);
+ }
+ else {
+ if (dc.isRequired())
+ handleChange();
+ }
+ break;
+ case TRACKING_OPTIONAL:
+ dc.invokeAdd(e);
+ updateInstance(dc, e, false, true);
+ break;
+ default:
}
- break;
- case TRACKING_OPTIONAL:
- dc.invokeAdd(e);
- updateInstance(dc);
- break;
- default:
- }
+ }
}
-
+
@Override
public void handleChanged(DependencyContext dc, Event e) {
Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
dependencyEvents.remove(e);
dependencyEvents.add(e);
- switch (m_state) {
- case TRACKING_OPTIONAL:
- dc.invokeChange(e);
- updateInstance(dc);
- break;
-
- case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
- if (!dc.isInstanceBound()) {
+ if (dc.isStarted()) {
+ switch (m_state) {
+ case TRACKING_OPTIONAL:
dc.invokeChange(e);
- updateInstance(dc);
+ updateInstance(dc, e, true, false);
+ break;
+
+ case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+ if (!dc.isInstanceBound()) {
+ dc.invokeChange(e);
+ updateInstance(dc, e, true, false);
+ }
+ break;
}
- break;
}
}
@Override
public void handleRemoved(DependencyContext dc, Event e) {
+ // Check if the dependency is still available.
Set<Event> dependencyEvents = m_dependencyEvents.get(dc);
int size = dependencyEvents.size();
if (dependencyEvents.contains(e)) {
size --; // the dependency is currently registered and is about to be removed.
}
dc.setAvailable(size > 0);
- handleChange();
- // Now, really remove the dependency event, because next, we'll possibly invoke updateInstance, which will
- // trigger getAutoConfigInstance, and at this point, we don't want to return the removed service, which might
- // be the highest ranked service.
- dependencyEvents.remove(e);
+ // If the dependency is now unavailable, we have to recalculate state change. This will result in invoking the
+ // "removed" callback with the removed dependency (which we have not yet removed from our dependency events list.).
+ // But we don't recalculate the state if the dependency is not started (if not started, it means that it is currently starting,
+ // and the tracker is detecting a removed service).
+ if (size == 0 && dc.isStarted()) {
+ handleChange();
+ }
+
+ // Now, really remove the dependency event.
+ dependencyEvents.remove(e);
- // Depending on the state, we possible have to invoke the callbacks and update the component instance.
- switch (m_state) {
- case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
- if (! dc.isInstanceBound()) {
- if (dc.isRequired()) {
- dc.invokeRemove(e);
- }
- updateInstance(dc);
- }
- break;
- case TRACKING_OPTIONAL:
- dc.invokeRemove(e);
- updateInstance(dc);
- break;
- default:
+ // Only check if the component instance has to be updated if the dependency is really started.
+ if (dc.isStarted()) {
+ // Depending on the state, we possible have to invoke the callbacks and update the component instance.
+ switch (m_state) {
+ case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+ if (!dc.isInstanceBound()) {
+ if (dc.isRequired()) {
+ dc.invokeRemove(e);
+ }
+ updateInstance(dc, e, false, false);
+ }
+ break;
+ case TRACKING_OPTIONAL:
+ dc.invokeRemove(e);
+ updateInstance(dc, e, false, false);
+ break;
+ default:
+ }
}
}
@@ -337,23 +361,25 @@ public class ComponentImpl implements Co
dependencyEvents.remove(event);
dependencyEvents.add(newEvent);
- // Depending on the state, we possible have to invoke the callbacks and update the component instance.
- switch (m_state) {
- case WAITING_FOR_REQUIRED:
- // No need to swap, we don't have yet injected anything
- break;
- case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
- // Only swap *non* instance-bound dependencies
- if (!dc.isInstanceBound()) {
- if (dc.isRequired()) {
- dc.invokeSwap(event, newEvent);
- }
- }
- break;
- case TRACKING_OPTIONAL:
- dc.invokeSwap(event, newEvent);
- break;
- default:
+ if (dc.isStarted()) {
+ // Depending on the state, we possible have to invoke the callbacks and update the component instance.
+ switch (m_state) {
+ case WAITING_FOR_REQUIRED:
+ // No need to swap, we don't have yet injected anything
+ break;
+ case INSTANTIATED_AND_WAITING_FOR_REQUIRED:
+ // Only swap *non* instance-bound dependencies
+ if (!dc.isInstanceBound()) {
+ if (dc.isRequired()) {
+ dc.invokeSwap(event, newEvent);
+ }
+ }
+ break;
+ case TRACKING_OPTIONAL:
+ dc.invokeSwap(event, newEvent);
+ break;
+ default:
+ }
}
}
@@ -363,6 +389,11 @@ public class ComponentImpl implements Co
return events.size() > 0 ? events.last() : null;
}
+ @Override
+ public Set<Event> getDependencyEvents(DependencyContext dc) {
+ return m_dependencyEvents.get(dc);
+ }
+
public Component setAutoConfig(Class clazz, boolean autoConfig) {
m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
return this;
@@ -530,12 +561,21 @@ public class ComponentImpl implements Co
}
return false;
}
-
- private void updateInstance(DependencyContext d) {
- if (d.isAutoConfig()) {
- configureImplementation(d.getAutoConfigType(), d.getAutoConfigInstance(), d.getAutoConfigName());
+
+ /**
+ * Updates the component instance(s).
+ * @param dc the dependency context for the updating dependency service
+ * @param event the event holding the updating service (service + properties)
+ * @param update true if dependency service properties are updating, false if not. If false, it means
+ * that a dependency service is being added or removed. (see the "add" flag).
+ * @param add true if the dependency service has been added, false if it has been removed. This flag is
+ * ignored if the "update" flag is true (because the dependency properties are just being updated).
+ */
+ private void updateInstance(DependencyContext dc, Event event, boolean update, boolean add) {
+ if (dc.isAutoConfig()) {
+ updateImplementation(dc.getAutoConfigType(), dc, dc.getAutoConfigName(), event, update, add);
}
- if (d.isPropagated() && m_registration != null) {
+ if (dc.isPropagated() && m_registration != null) {
m_registration.setProperties(calculateServiceProperties());
}
}
@@ -563,6 +603,8 @@ public class ComponentImpl implements Co
}
d.start();
}
+ // The started dependencies has probably called our handleAdded method: we now have to run our state machine.
+ handleChange();
}
private void stopDependencies() {
@@ -740,7 +782,7 @@ public class ComponentImpl implements Co
private void invokeAutoConfigDependencies() {
for (DependencyContext d : m_dependencies) {
if (d.isAutoConfig() && !d.isInstanceBound()) {
- configureImplementation(d.getAutoConfigType(), d.getAutoConfigInstance(), d.getAutoConfigName());
+ configureImplementation(d.getAutoConfigType(), d, d.getAutoConfigName());
}
}
}
@@ -748,7 +790,7 @@ public class ComponentImpl implements Co
private void invokeAutoConfigInstanceBoundDependencies() {
for (DependencyContext d : m_dependencies) {
if (d.isAutoConfig() && d.isInstanceBound()) {
- configureImplementation(d.getAutoConfigType(), d.getAutoConfigInstance(), d.getAutoConfigName());
+ configureImplementation(d.getAutoConfigType(), d, d.getAutoConfigName());
}
}
}
@@ -890,46 +932,39 @@ public class ComponentImpl implements Co
* and for each of these fields, the specified instance is filled in.
*
* @param clazz the class to search for
- * @param instance the instance to fill in
+ * @param inject the object to fill in the implementation class(es) field
* @param instanceName the name of the instance to fill in, or <code>null</code> if not used
*/
- private void configureImplementation(Class clazz, Object instance, String instanceName) {
- Object[] instances = getInstances();
- if (instances != null && instance != null && clazz != null) {
- for (int i = 0; i < instances.length; i++) {
- Object serviceInstance = instances[i];
- Class serviceClazz = serviceInstance.getClass();
- if (Proxy.isProxyClass(serviceClazz)) {
- serviceInstance = Proxy.getInvocationHandler(serviceInstance);
- serviceClazz = serviceInstance.getClass();
- }
- while (serviceClazz != null) {
- Field[] fields = serviceClazz.getDeclaredFields();
- for (int j = 0; j < fields.length; j++) {
- Field field = fields[j];
- Class type = field.getType();
- if ((instanceName == null && type.equals(clazz))
- || (instanceName != null && field.getName().equals(instanceName) && type.isAssignableFrom(clazz))) {
- try {
- field.setAccessible(true);
- // synchronized makes sure the field is actually written to immediately
- synchronized (SYNC) {
- field.set(serviceInstance, instance);
- }
- }
- catch (Exception e) {
- m_logger.log(Logger.LOG_ERROR, "Could not set field " + field, e);
- return;
- }
- }
- }
- serviceClazz = serviceClazz.getSuperclass();
- }
- }
- }
+ private void configureImplementation(Class clazz, Object inject, String fieldName) {
+ Object[] targets = getInstances();
+ FieldUtil.injectField(targets, fieldName, clazz, inject, m_logger);
}
- @Override
+ private void configureImplementation(Class clazz, DependencyContext dc, String fieldName) {
+ Object[] targets = getInstances();
+ FieldUtil.injectDependencyField(targets, fieldName, clazz, dc, m_logger);
+ }
+
+ /**
+ * Update the component instances.
+ *
+ * @param clazz the class of the dependency service to inject in the component instances
+ * @param dc the dependency context for the updating dependency service
+ * @param fieldName the component instances fieldname to fill in with the updated dependency service
+ * @param event the event holding the updating service (service + properties)
+ * @param update true if dependency service properties are updating, false if not. If false, it means
+ * that a dependency service is being added or removed. (see the "add" flag).
+ * @param add true if the dependency service has been added, false if it has been removed. This flag is
+ * ignored if the "update" flag is true (because the dependency properties are just being updated).
+ */
+ private void updateImplementation(Class clazz, DependencyContext dc, String fieldName, Event event, boolean update,
+ boolean add)
+ {
+ Object[] targets = getInstances();
+ FieldUtil.updateDependencyField(targets, fieldName, update, add, clazz, event, dc, m_logger);
+ }
+
+ @Override
public ServiceRegistration getServiceRegistration() {
return m_registration;
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationDependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -21,6 +21,7 @@ package org.apache.felix.dm.impl;
import java.lang.reflect.InvocationTargetException;
import java.util.Dictionary;
import java.util.Properties;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.felix.dm.ConfigurationDependency;
@@ -77,8 +78,7 @@ public class ConfigurationDependencyImpl
}
@Override
- public void start() {
- super.start();
+ protected void startTracking() {
if (m_context != null) { // If null, we are in a test environment
Properties props = new Properties();
props.put(Constants.SERVICE_PID, m_pid);
@@ -91,8 +91,7 @@ public class ConfigurationDependencyImpl
}
@Override
- public void stop() {
- super.stop();
+ protected void stopTracking() {
if (m_registration != null) {
try {
m_registration.unregister();
@@ -118,12 +117,7 @@ public class ConfigurationDependencyImpl
public String getType() {
return "configuration";
}
-
- @Override
- protected Object getService() {
- return m_settings;
- }
-
+
public ConfigurationDependency add(PropertyMetaData properties)
{
createMetaTypeImpl();
@@ -190,17 +184,17 @@ public class ConfigurationDependencyImpl
if ((oldSettings == null) && (settings != null)) {
// Notify the component that our dependency is available.
- add(new EventImpl());
+ add(new ConfigurationEventImpl(m_pid, settings));
}
else if ((oldSettings != null) && (settings != null)) {
// Notify the component that our dependency has changed.
- change(new EventImpl());
+ change(new ConfigurationEventImpl(m_pid, settings));
}
else if ((oldSettings != null) && (settings == null)) {
// Notify the component that our dependency has been removed.
// Notice that the component will be stopped, and then all required dependencies will be unbound
// (including our configuration dependency).
- remove(new EventImpl());
+ remove(new ConfigurationEventImpl(m_pid, oldSettings));
}
}
Added: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationEventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationEventImpl.java?rev=1628547&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationEventImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ConfigurationEventImpl.java Tue Sep 30 20:30:21 2014
@@ -0,0 +1,26 @@
+package org.apache.felix.dm.impl;
+
+import java.util.Dictionary;
+
+public class ConfigurationEventImpl extends EventImpl {
+ private final Dictionary<?,?> m_conf;
+ private final String m_pid;
+
+ public ConfigurationEventImpl(String pid, Dictionary<?,?> conf) {
+ m_pid = pid;
+ m_conf = conf;
+ }
+
+ public String getPid() {
+ return m_pid;
+ }
+
+ public Dictionary<?,?> getConf() {
+ return m_conf;
+ }
+
+ @Override
+ public Object getEvent() {
+ return m_conf;
+ }
+}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/DependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/DependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/DependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/DependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -18,7 +18,11 @@
*/
package org.apache.felix.dm.impl;
+import java.util.Collection;
import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
import org.apache.felix.dm.ComponentDependencyDeclaration;
import org.apache.felix.dm.Dependency;
@@ -143,14 +147,18 @@ public class DependencyImpl<T extends De
@Override
public void start() {
- m_isStarted = true;
- // you would normally start tracking this dependency here, so for example
- // for a service dependency you might start a service tracker here
+ if (! m_isStarted) {
+ startTracking();
+ m_isStarted = true;
+ }
}
@Override
public void stop() {
- m_isStarted = false;
+ if (m_isStarted) {
+ stopTracking();
+ m_isStarted = false;
+ }
}
@Override
@@ -272,11 +280,6 @@ public class DependencyImpl<T extends De
}
@Override
- public Object getAutoConfigInstance() {
- return getService();
- }
-
- @Override
public boolean isAutoConfig() {
return m_autoConfig;
}
@@ -313,11 +316,49 @@ public class DependencyImpl<T extends De
}
}
- protected Object getService() {
- // only real dependencies can return actual service.
- return null;
+ @Override
+ public Event getService() {
+ Event event = m_component.getDependencyEvent(this);
+ if (event == null) {
+ Object defaultService = getDefaultService();
+ if (defaultService != null) {
+ event = new EventImpl(0, defaultService);
+ }
+ }
+ return event;
+ }
+
+ @Override
+ public void copyToCollection(Collection<Object> services) {
+ Set<Event> events = m_component.getDependencyEvents(this);
+ if (events.size() > 0) {
+ for (Event e : events) {
+ services.add(e.getEvent());
+ }
+ } else {
+ Object defaultService = getDefaultService();
+ if (defaultService != null) {
+ services.add(defaultService);
+ }
+ }
}
+ @Override
+ public void copyToMap(Map<Object, Dictionary> map) {
+ Set<Event> events = m_component.getDependencyEvents(this);
+ if (events.size() > 0) {
+ for (Event e : events) {
+ map.put(e.getEvent(), e.getProperties());
+ }
+ } else {
+ Object defaultService = getDefaultService();
+ if (defaultService != null) {
+ map.put(defaultService, new Hashtable());
+ }
+ }
+ }
+
+ @Override
public boolean isStarted() {
return m_isStarted;
}
@@ -337,9 +378,19 @@ public class DependencyImpl<T extends De
return m_component;
}
+ protected Object getDefaultService() {
+ return null;
+ }
+
protected void ensureNotActive() {
if (isStarted()) {
throw new IllegalStateException("Cannot modify state while active.");
}
}
+
+ protected void startTracking() {
+ }
+
+ protected void stopTracking() {
+ }
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/EventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/EventImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/EventImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/EventImpl.java Tue Sep 30 20:30:21 2014
@@ -18,23 +18,32 @@
*/
package org.apache.felix.dm.impl;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
import org.apache.felix.dm.context.Event;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
/* in real life, this event might contain a service reference and service instance
* or something similar
*/
public class EventImpl implements Event {
private final int m_id;
+ private final Object m_event; // the actual event object (a Service, a Bundle, a Configuration, etc ...)
+ private final static Dictionary m_emptyProperties = new Hashtable();
public EventImpl() {
this(1);
}
/** By constructing events with different IDs, we can simulate different unique instances. */
public EventImpl(int id) {
- m_id = id;
+ this (id, null);
+ }
+
+ public EventImpl(int id, Object event) {
+ m_id = id;
+ m_event = event;
}
+
@Override
public int hashCode() {
@@ -66,4 +75,14 @@ public class EventImpl implements Event
@Override
public void close() {
}
+
+ @Override
+ public Object getEvent() {
+ return m_event;
+ }
+
+ @Override
+ public Dictionary getProperties() {
+ return m_emptyProperties;
+ }
}
Added: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java?rev=1628547&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java (added)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FieldUtil.java Tue Sep 30 20:30:21 2014
@@ -0,0 +1,285 @@
+package org.apache.felix.dm.impl;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Map;
+
+import org.apache.felix.dm.context.DependencyContext;
+import org.apache.felix.dm.context.Event;
+
+/**
+ * Reflection Helper methods, used to inject autoconfig fields in component instances.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FieldUtil {
+ /**
+ * Callbacks for fields to be injected
+ */
+ private interface FieldFunction {
+ // Inject an updated service in the given field for the the given target component instance.
+ void injectField(Field f, Object target);
+
+ // Inject a Collection field in the given field for the the given target component instance.
+ void injectCollectionField(Field f, Object target);
+
+ // Inject a Map field (key = dependency service, value = Dictionary with dependency service properties).
+ void injectMapField(Field f, Object target);
+ }
+
+ /**
+ * Injects some component instances (on a given field, if provided), with an object of a given class.
+ * @param targets the component instances to fill in
+ * @param fieldName the fieldname, or null. If null, the field must exaclty match the injected service classname.
+ * @param clazz the injected service class
+ * @param service the injected service
+ * @param logger the component logger.
+ */
+ public static void injectField(Object[] targets, String fieldName, Class<?> clazz, final Object service,
+ final Logger logger)
+ {
+ if (service == null) {
+ return;
+ }
+ mapField(true, clazz, targets, fieldName, logger, new FieldFunction() {
+ public void injectField(Field f, Object target) {
+ try {
+ f.setAccessible(true);
+ f.set(target, service);
+ } catch (Throwable e) {
+ logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+ + target.getClass().getName(), e);
+ }
+ }
+
+ public void injectCollectionField(Field f, Object target) { // never called
+ }
+
+ public void injectMapField(Field f, Object target) { // never called
+ }
+ });
+ }
+
+ /**
+ * Injects a dependency service in some component instances.
+ * Here, we'll inject the dependency services in the component if the field is of the same type of the injected services,
+ * or if the field is a Collection of the injected service, or if the field is a Map<Injected Service class, Dictionary).
+ * @param targets the component instances to fill in
+ * @param fieldName the fieldname, or null. If null, the field must exaclty match the injected service classname.
+ * @param clazz the injected service class
+ * @param service the injected service
+ * @param logger the component logger.
+ */
+ public static void injectDependencyField(Object[] targets, String fieldName, Class<?> clazz,
+ final DependencyContext dc, final Logger logger)
+ {
+ final Event event = dc.getService();
+ if (event == null) {
+ return;
+ }
+ mapField(false, clazz, targets, fieldName, logger, new FieldFunction() {
+ public void injectField(Field f, Object target) {
+ try {
+ f.setAccessible(true);
+ f.set(target, event.getEvent());
+ } catch (Throwable e) {
+ logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+ + target.getClass().getName(), e);
+ }
+ }
+
+ public void injectCollectionField(Field f, Object target) {
+ f.setAccessible(true);
+ Class<?> type = f.getType();
+
+ try {
+ Collection<Object> coll = (Collection) type.newInstance();
+ dc.copyToCollection(coll);
+ f.set(target, coll);
+ } catch (Throwable e) {
+ logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+ + target.getClass().getName(), e);
+ }
+ }
+
+ @Override
+ public void injectMapField(Field f, Object target) {
+ f.setAccessible(true);
+ Class<?> type = f.getType();
+
+ try {
+ Map map = (Map) type.newInstance();
+ dc.copyToMap(map);
+ f.set(target, map);
+ } catch (Throwable e) {
+ logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+ + target.getClass().getName(), e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Adds, or removes, or update some component instances with an updated dependency service
+ * @param targets the component instances to fill in with the updated service
+ * @param fieldName the component instance fieldname
+ * @param update true if it's a dependency service update, false if the dependency service is added or removed
+ * @param add true if the dependency service has been added, false the dependency service has been removed.
+ * This flag is ignored if the "update" parameter is "true".
+ * @param clazz the clazz of the dependency service
+ * @param event the event holding the dependency service
+ * @param dc the dependency service context
+ * @param logger the logger used when problems occure.
+ */
+ public static void updateDependencyField(Object[] targets, String fieldName, final boolean update,
+ final boolean add, Class<?> clazz, final Event event, final DependencyContext dc, final Logger logger)
+ {
+ mapField(false, clazz, targets, fieldName, logger, new FieldFunction() {
+ public void injectField(Field f, Object target) {
+ try {
+ f.setAccessible(true);
+ f.set(target, dc.getService().getEvent());
+ } catch (Throwable e) {
+ logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+ + target.getClass().getName(), e);
+ }
+ }
+
+ public void injectCollectionField(Field f, Object target) {
+ if (update) {
+ return;
+ }
+
+ f.setAccessible(true);
+ Class<?> type = f.getType();
+
+ try {
+ Collection coll = (Collection) f.get(target);
+ if (add) {
+ coll.add(event.getEvent());
+ } else {
+ coll.remove(event.getEvent());
+ }
+ } catch (Throwable e) {
+ logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+ + target.getClass().getName(), e);
+ }
+ }
+
+ @Override
+ public void injectMapField(Field f, Object target) {
+ f.setAccessible(true);
+ Class<?> type = f.getType();
+
+ try {
+ Map<Object, Dictionary> map = (Map) f.get(target);
+ if (add) {
+ map.put(event.getEvent(), event.getProperties());
+ } else {
+ map.remove(event.getEvent());
+ }
+ } catch (Throwable e) {
+ logger.log(Logger.LOG_ERROR, "Could not set field " + f + " in class "
+ + target.getClass().getName(), e);
+ }
+ }
+ });
+ }
+
+ /**
+ * Scans component instances for fields having either the same dependency service type, or being a
+ * Collection of the dependency service, or being a Map<Dependency Service class, Dictionary> (the Dictionary
+ * corresponds to the dependency service properties).
+ * @param strict true if we are only looking for fields having exactly the same type as the dependency service.
+ * In other words, if strict = true, we don't lookup for fields of "Collection" or "Map" types.
+ * @param clazz the dependency service class
+ * @param targets the component instances
+ * @param fieldName the component instances field name or null
+ * @param logger a logger used when exceptions are occuring
+ * @param func the callback used to notify when we find either a field with the same dependency service type, or
+ * with a "Collection" type, or with a "Map" type.
+ */
+ private static void mapField(boolean strict, Class<?> clazz, Object[] targets, String fieldName, Logger logger,
+ FieldFunction func)
+ {
+ if (targets != null && clazz != null) {
+ for (int i = 0; i < targets.length; i++) {
+ Object target = targets[i];
+ Class<?> targetClass = target.getClass();
+ if (Proxy.isProxyClass(targetClass)) {
+ target = Proxy.getInvocationHandler(target);
+ targetClass = target.getClass();
+ }
+ while (targetClass != null) {
+ Field[] fields = targetClass.getDeclaredFields();
+ for (int j = 0; j < fields.length; j++) {
+ Field field = fields[j];
+ Class<?> fieldType = field.getType();
+
+ if (fieldName == null) {
+ // Field type class must match injected service type
+ if (fieldType.equals(clazz)) {
+ func.injectField(field, target);
+ } else if (!strict && mayInjectToCollection(clazz, field, true)) {
+ func.injectCollectionField(field, target);
+ } else if (!strict && mayInjectToMap(clazz, field, true)) {
+ func.injectMapField(field, target);
+ }
+ } else if (field.getName().equals(fieldName)) {
+ // Field type may be a superclass of the service type
+ if (fieldType.isAssignableFrom(clazz)) {
+ func.injectField(field, target);
+ } else if (!strict && mayInjectToCollection(clazz, field, false)) {
+ func.injectCollectionField(field, target);
+ } else if (!strict && mayInjectToMap(clazz, field, false)) {
+ func.injectMapField(field, target);
+ } else {
+ logger.log(
+ Logger.LOG_ERROR,
+ "Could not set field " + field + " in class " + target.getClass().getName()
+ + ": the type of the field type should be either assignable from "
+ + clazz.getName() + " or Collection, or Map");
+ }
+ }
+ }
+ targetClass = targetClass.getSuperclass();
+ }
+ }
+ }
+ }
+
+ private static boolean mayInjectToCollection(Class<?> clazz, Field field, boolean strictClassEquality) {
+ Class<?> fieldType = field.getType();
+ if (Collection.class.isAssignableFrom(fieldType)) {
+ ParameterizedType parameterType = (ParameterizedType) field.getGenericType();
+ if (parameterType == null) {
+ return false;
+ }
+ Class<?> parameterizedTypeClass = (Class<?>) parameterType.getActualTypeArguments()[0];
+ return strictClassEquality ? parameterizedTypeClass.equals(clazz)
+ : parameterizedTypeClass.isAssignableFrom(clazz);
+ }
+ return false;
+ }
+
+ private static boolean mayInjectToMap(Class<?> clazz, Field field, boolean strictClassEquality) {
+ Class<?> fieldType = field.getType();
+ if (Map.class.isAssignableFrom(fieldType)) {
+ ParameterizedType parameterType = (ParameterizedType) field.getGenericType();
+ if (parameterType == null) {
+ return false;
+ }
+ Class<?> K = (Class<?>) parameterType.getActualTypeArguments()[0];
+ Class<?> V = (Class<?>) parameterType.getActualTypeArguments()[1];
+
+ if (!V.equals(Dictionary.class)) {
+ return false;
+ }
+ return strictClassEquality ? K.equals(clazz) : K.isAssignableFrom(clazz);
+ }
+ return false;
+ }
+}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/FilterComponent.java Tue Sep 30 20:30:21 2014
@@ -20,6 +20,7 @@ package org.apache.felix.dm.impl;
import java.util.Dictionary;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -311,10 +312,16 @@ public class FilterComponent implements
return m_component.getInstances();
}
+ @Override
public Event getDependencyEvent(DependencyContext dc) {
return m_component.getDependencyEvent(dc);
}
+ @Override
+ public Set<Event> getDependencyEvents(DependencyContext dc) {
+ return m_component.getDependencyEvents(dc);
+ }
+
public ComponentDeclaration getComponentDeclaration() {
return this;
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceDependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceDependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceDependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -23,6 +23,7 @@ import java.net.URL;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Properties;
+import java.util.Set;
import org.apache.felix.dm.Component;
import org.apache.felix.dm.ComponentDependencyDeclaration;
@@ -61,33 +62,24 @@ public class ResourceDependencyImpl exte
}
@Override
- public void start() {
- boolean wasStarted = isStarted();
- super.start();
- if (!wasStarted) {
- Dictionary props = null;
- if (m_trackedResource != null) {
+ protected void startTracking() {
+ Dictionary props = null;
+ if (m_trackedResource != null) {
+ props = new Properties();
+ props.put(ResourceHandler.URL, m_trackedResource);
+ } else {
+ if (m_resourceFilter != null) {
props = new Properties();
- props.put(ResourceHandler.URL, m_trackedResource);
- }
- else {
- if (m_resourceFilter != null) {
- props = new Properties();
- props.put(ResourceHandler.FILTER, m_resourceFilter);
- }
+ props.put(ResourceHandler.FILTER, m_resourceFilter);
}
- m_registration = m_context.registerService(ResourceHandler.class.getName(), this, props);
}
+ m_registration = m_context.registerService(ResourceHandler.class.getName(), this, props);
}
@Override
- public void stop() {
- boolean wasStarted = isStarted();
- super.stop();
- if (wasStarted) {
- m_registration.unregister();
- m_registration = null;
- }
+ protected void stopTracking() {
+ m_registration.unregister();
+ m_registration = null;
}
public void added(URL resource) {
@@ -130,7 +122,7 @@ public class ResourceDependencyImpl exte
public void invoke(String method, Event e) {
ResourceEventImpl re = (ResourceEventImpl) e;
URL serviceInstance = re.getResource();
- Dictionary<?,?> resourceProperties = re.getResourceProperties();
+ Dictionary<?,?> resourceProperties = re.getProperties();
m_component.invokeCallbackMethod(getInstances(), method,
new Class[][] {
@@ -171,12 +163,6 @@ public class ResourceDependencyImpl exte
}
@Override
- protected Object getService() {
- ResourceEventImpl re = (ResourceEventImpl) m_component.getDependencyEvent(this);
- return re != null ? re.getResource() : null;
- }
-
- @Override
public Class<?> getAutoConfigType() {
return URL.class;
}
@@ -185,7 +171,7 @@ public class ResourceDependencyImpl exte
ResourceEventImpl re = (ResourceEventImpl) m_component.getDependencyEvent(this);
if (re != null) {
URL resource = re.getResource();
- Dictionary<?,?> resourceProperties = re.getResourceProperties();
+ Dictionary<?,?> resourceProperties = re.getProperties();
if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
try {
return (Dictionary<?,?>) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ URL.class }}, new Object[][] {{ resource }});
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceEventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceEventImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceEventImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ResourceEventImpl.java Tue Sep 30 20:30:21 2014
@@ -30,14 +30,20 @@ public class ResourceEventImpl extends E
m_resourceProperties = resourceProperties;
}
- public URL getResource() {
- return m_resource;
+ @Override
+ public Object getEvent() {
+ return getResource();
}
-
- public Dictionary<?, ?> getResourceProperties() {
+
+ @Override
+ public Dictionary getProperties() {
return m_resourceProperties;
}
-
+
+ public URL getResource() {
+ return m_resource;
+ }
+
@Override
public boolean equals(Object obj) {
if (obj instanceof ResourceEventImpl) {
@@ -45,8 +51,8 @@ public class ResourceEventImpl extends E
ResourceEventImpl r2 = (ResourceEventImpl) obj;
boolean match = r1.getResource().equals(r2.getResource());
if (match) {
- Dictionary<?,?> d1 = getResourceProperties();
- Dictionary<?,?> d2 = r2.getResourceProperties();
+ Dictionary<?,?> d1 = getProperties();
+ Dictionary<?,?> d2 = r2.getProperties();
if (d1 == null) {
return d2 == null ? match : false;
@@ -64,7 +70,7 @@ public class ResourceEventImpl extends E
final int prime = 31;
int result = 1;
result = prime * result + getResource().hashCode();
- result = prime * result + ((getResourceProperties() == null) ? 0 : getResourceProperties().hashCode());
+ result = prime * result + ((getProperties() == null) ? 0 : getProperties().hashCode());
return result;
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceDependencyImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceDependencyImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceDependencyImpl.java Tue Sep 30 20:30:21 2014
@@ -23,7 +23,9 @@ import java.lang.reflect.Proxy;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Dictionary;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@@ -200,41 +202,33 @@ public class ServiceDependencyImpl exten
}
@Override
- public void start() {
- boolean wasStarted = isStarted();
- super.start();
-
- if (!wasStarted) {
- if (m_trackedServiceName != null) {
- if (m_trackedServiceFilter != null) {
- try {
- m_tracker = new ServiceTracker(m_context, m_context.createFilter(m_trackedServiceFilter), this);
- } catch (InvalidSyntaxException e) {
- throw new IllegalStateException("Invalid filter definition for dependency: " + m_trackedServiceFilter);
- }
- } else if (m_trackedServiceReference != null) {
- m_tracker = new ServiceTracker(m_context, m_trackedServiceReference, this);
- } else {
- m_tracker = new ServiceTracker(m_context, m_trackedServiceName.getName(), this);
+ protected void startTracking() {
+ if (m_trackedServiceName != null) {
+ if (m_trackedServiceFilter != null) {
+ try {
+ m_tracker = new ServiceTracker(m_context, m_context.createFilter(m_trackedServiceFilter), this);
+ } catch (InvalidSyntaxException e) {
+ throw new IllegalStateException("Invalid filter definition for dependency: "
+ + m_trackedServiceFilter);
}
+ } else if (m_trackedServiceReference != null) {
+ m_tracker = new ServiceTracker(m_context, m_trackedServiceReference, this);
} else {
- throw new IllegalStateException("Could not create tracker for dependency, no service name specified.");
- }
- if (debug) {
- m_tracker.setDebug(debugKey);
+ m_tracker = new ServiceTracker(m_context, m_trackedServiceName.getName(), this);
}
- m_tracker.open();
+ } else {
+ throw new IllegalStateException("Could not create tracker for dependency, no service name specified.");
+ }
+ if (debug) {
+ m_tracker.setDebug(debugKey);
}
+ m_tracker.open();
}
@Override
- public void stop() {
- boolean wasStarted = isStarted();
- super.stop();
- if (wasStarted) {
- m_tracker.close();
- m_tracker = null;
- }
+ protected void stopTracking() {
+ m_tracker.close();
+ m_tracker = null;
}
@Override
@@ -245,7 +239,7 @@ public class ServiceDependencyImpl exten
@Override
public void addedService(ServiceReference reference, Object service) {
if (debug) {
- System.out.println(debugKey + " addedService");
+ System.out.println(debugKey + " addedService: ref=" + reference + ", service=" + service);
}
add(new ServiceEventImpl(m_bundle, m_context, reference, service));
}
@@ -281,20 +275,20 @@ public class ServiceDependencyImpl exten
{Map.class, m_trackedServiceName}},
new Object[][]{
- {m_component, se.getReference(), se.getService()},
- {m_component, se.getReference(), se.getService()},
+ {m_component, se.getReference(), se.getEvent()},
+ {m_component, se.getReference(), se.getEvent()},
{m_component, se.getReference()},
- {m_component, se.getService()},
- {m_component, se.getService()},
+ {m_component, se.getEvent()},
+ {m_component, se.getEvent()},
{m_component},
- {m_component, new ServicePropertiesMap(se.getReference()), se.getService()},
- {se.getReference(), se.getService()},
- {se.getReference(), se.getService()},
+ {m_component, new ServicePropertiesMap(se.getReference()), se.getEvent()},
+ {se.getReference(), se.getEvent()},
+ {se.getReference(), se.getEvent()},
{se.getReference()},
- {se.getService()},
- {se.getService()},
+ {se.getEvent()},
+ {se.getEvent()},
{},
- {new ServicePropertiesMap(se.getReference()), se.getService()}}
+ {new ServicePropertiesMap(se.getReference()), se.getEvent()}}
);
}
@@ -347,7 +341,7 @@ public class ServiceDependencyImpl exten
try {
return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod,
new Class[][]{{ServiceReference.class, Object.class}, {ServiceReference.class}}, new Object[][]{
- {se.getReference(), se.getService()}, {se.getReference()}});
+ {se.getReference(), se.getEvent()}, {se.getReference()}});
} catch (InvocationTargetException e) {
m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
} catch (Exception e) {
@@ -369,11 +363,6 @@ public class ServiceDependencyImpl exten
}
}
- @Override
- public boolean isPropagated() {
- return m_propagate;
- }
-
private BundleContext getBundleContext() {
return m_context;
}
@@ -413,12 +402,9 @@ public class ServiceDependencyImpl exten
}
@Override
- protected Object getService() {
+ public Object getDefaultService() {
Object service = null;
- ServiceEventImpl se = (ServiceEventImpl) m_component.getDependencyEvent(this);
- if (se != null) {
- service = se.getService();
- } else if (isAutoConfig()) {
+ if (isAutoConfig()) {
service = getDefaultImplementation();
if (service == null) {
service = getNullObject();
@@ -426,7 +412,7 @@ public class ServiceDependencyImpl exten
}
return service;
}
-
+
private Object getNullObject() {
if (m_nullObject == null) {
Class trackedServiceName;
@@ -466,7 +452,7 @@ public class ServiceDependencyImpl exten
public void invokeSwap(Event event, Event newEvent) {
ServiceEventImpl oldE = (ServiceEventImpl) event;
ServiceEventImpl newE = (ServiceEventImpl) newEvent;
- invokeSwap(m_swap, oldE.getReference(), oldE.getService(), newE.getReference(), newE.getService(), getInstances());
+ invokeSwap(m_swap, oldE.getReference(), oldE.getEvent(), newE.getReference(), newE.getEvent(), getInstances());
}
public void invokeSwap(String swapMethod, ServiceReference previousReference, Object previous,
@@ -512,5 +498,5 @@ public class ServiceDependencyImpl exten
addedService(newReference, newService);
removedService(reference, service);
}
- }
+ }
}
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceEventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceEventImpl.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceEventImpl.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceEventImpl.java Tue Sep 30 20:30:21 2014
@@ -18,6 +18,8 @@
*/
package org.apache.felix.dm.impl;
+import java.util.Dictionary;
+
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
@@ -78,12 +80,15 @@ public class ServiceEventImpl extends Ev
return m_reference;
}
- /**
- * Returns the service dependency instance.
- */
- public Object getService() {
- return m_service;
- }
+ @Override
+ public Object getEvent() {
+ return m_service;
+ }
+
+ @Override
+ public Dictionary getProperties() {
+ return ServiceUtil.propertiesToDictionary(m_reference);
+ }
@Override
public boolean equals(Object obj) {
Modified: felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceUtil.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceUtil.java?rev=1628547&r1=1628546&r2=1628547&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceUtil.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/ServiceUtil.java Tue Sep 30 20:30:21 2014
@@ -18,7 +18,12 @@
*/
package org.apache.felix.dm.impl;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import org.apache.felix.dm.DependencyManager;
import org.osgi.framework.Bundle;
@@ -173,4 +178,66 @@ public class ServiceUtil {
}
return buf.toString();
}
+
+ /**
+ * Wraps ServiceReference properties behind a Dictionary object.
+ * @param ref the ServiceReference to wrap
+ * @return a new Dictionary used to wrap the ServiceReference properties
+ */
+ public static Dictionary<String, ?> propertiesToDictionary(final ServiceReference ref) {
+ return new Dictionary<String, Object>() {
+ private Dictionary<String, Object> m_wrapper;
+
+ @Override
+ public int size() {
+ return getWrapper().size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return getWrapper().isEmpty();
+ }
+
+ @Override
+ public Enumeration<String> keys() {
+ return getWrapper().keys();
+ }
+
+ @Override
+ public Enumeration<Object> elements() {
+ return getWrapper().elements();
+ }
+
+ @Override
+ public Object get(Object key) {
+ return ref.getProperty(key.toString());
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ throw new UnsupportedOperationException("Unmodified Dictionary.");
+ }
+
+ @Override
+ public Object remove(Object key) {
+ throw new UnsupportedOperationException("Unmodified Dictionary.");
+ }
+
+ @Override
+ public String toString() {
+ return getWrapper().toString();
+ }
+
+ private synchronized Dictionary<String, Object> getWrapper() {
+ if (m_wrapper == null) {
+ m_wrapper = new Hashtable<String, Object>();
+ String[] keys = ref.getPropertyKeys();
+ for (String key : keys) {
+ m_wrapper.put(key, ref.getProperty(key));
+ }
+ }
+ return m_wrapper;
+ }
+ };
+ }
}