Hi Marcel,

On 2/15/07, Marcel Offermans <[EMAIL PROTECTED]> wrote:
1. Add an API to externally query service dependencies and state.
2. Implement shell commands for the Felix shell.

I would like to add the first thing in a generic way (that, for
example, will also allow you to hook up to JMX).
attached a suggestion on how that is achieved right now, WDYT?


I would then be interested in a contribution for the second part.
That is in the repo at OPS4J at
https://scm.ops4j.org/repos/ops4j/laboratory/users/peter/, you can
just check it out as an Eclipse project or build it with maven. If you
like the approach, i will add the Felix Shell commands, too. This one
is just for Equinox, and there is one for the Knopflerfish console.

/peter
Index: 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/Dependency.java
===================================================================
--- 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/Dependency.java
 (revision 502604)
+++ 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/Dependency.java
 (working copy)
@@ -62,5 +62,5 @@
      * <code>dependencyUnavaible()</code> before stopping itself to ensure
      * that dependencies that aren't "active" are unavailable.
      */
-    public void stop(Service service);
+       public void stop(Service service);
 }
Index: 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/DependencyActivatorBase.java
===================================================================
--- 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/DependencyActivatorBase.java
    (revision 502604)
+++ 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/DependencyActivatorBase.java
    (working copy)
@@ -91,7 +91,7 @@
      * @return the new service
      */
     public Service createService() {
-        return new ServiceImpl(m_context);
+        return new MonitorEnabledServiceImpl(m_context);
     }
     
     /**
Index: 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/DependencyManager.java
===================================================================
--- 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/DependencyManager.java
  (revision 502604)
+++ 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/DependencyManager.java
  (working copy)
@@ -68,7 +68,7 @@
      * @return the new service
      */
     public Service createService() {
-        return new ServiceImpl(m_context);
+        return new MonitorEnabledServiceImpl(m_context);
     }
     
     /**
Index: 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/MonitorEnabledServiceImpl.java
===================================================================
--- 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/MonitorEnabledServiceImpl.java
  (revision 0)
+++ 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/MonitorEnabledServiceImpl.java
  (revision 0)
@@ -0,0 +1,789 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed 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.dependencymanager;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Service implementation.
+ * 
+ * @author Marcel Offermans
+ */
+public class MonitorEnabledServiceImpl implements Service {
+
+       private final class ServiceDescriptionImpl implements 
ServiceDescription {
+               public String[] getServiceNames() {
+                       if (null != m_serviceName) {
+                               if (m_serviceName.getClass().isArray()) {
+                                       return (String[]) m_serviceName;
+                               } else {
+                                       return new String[] { (String) 
m_serviceName };
+                               }
+                       }
+                       return new String[] { "Unknown service" };
+               }
+
+               public String getImplementation() {
+                       if (m_implementation == null) {
+                               return "Unknown service impl";
+                       }
+
+                       if (m_implementation instanceof String) {
+                               return (String) m_implementation;
+                       }
+
+                       if (m_implementation instanceof Class) {
+                               return ((Class) m_implementation).getName();
+                       }
+
+                       return m_implementation.getClass().getName();
+               }
+
+               public Dictionary getServiceProperties() {
+                       return m_serviceProperties;
+               }
+
+               public Dependency[] getDependencies() {
+                       return (Dependency[]) MonitorEnabledServiceImpl.this
+                                       .getDependencies().toArray(new 
Dependency[0]);
+               }
+
+               public Dependency[] getDependencies(boolean available,
+                               boolean onlyRequired) {
+                       List askedForDeps = new ArrayList();
+                       Dependency[] deps = getDependencies();
+                       for (int i = 0; i < deps.length; i++) {
+                               Dependency dependency = deps[i];
+                               if (dependency.isAvailable() == available) {
+                                       if (onlyRequired == 
dependency.isRequired()
+                                                       || !onlyRequired) {
+                                               askedForDeps.add(dependency);
+                                       }
+                               }
+                       }
+                       return (Dependency[]) askedForDeps.toArray(new 
Dependency[0]);
+               }
+
+               public String toString() {
+                       return "ServiceDescription [" + getImplementation() + 
"]";
+               }
+       }
+
+       private static final ServiceRegistration NULL_REGISTRATION;
+
+       private BundleContext m_context;
+
+       private ServiceRegistration m_registration;
+
+       private String m_callbackInit;
+
+       private String m_callbackStart;
+
+       private String m_callbackStop;
+
+       private String m_callbackDestroy;
+
+       private List m_listeners = new ArrayList();
+
+       private ArrayList m_dependencies = new ArrayList();
+
+       private int m_state;
+
+       private Object m_service;
+
+       private Object m_implementation;
+
+       private Object m_serviceName;
+
+       private Dictionary m_serviceProperties;
+
+       private ServiceTracker m_monitorServiceTracker;
+
+       private ServiceDescription m_serviceDescription;
+
+       private boolean m_startAsync = false;
+
+       // ----- DEPENDENCIES
+
+       public MonitorEnabledServiceImpl(BundleContext context) {
+               m_context = context;
+               m_callbackInit = "init";
+               m_callbackStart = "start";
+               m_callbackStop = "stop";
+               m_callbackDestroy = "destroy";
+               m_serviceDescription = new ServiceDescriptionImpl();
+               m_state = ServiceMonitor.STARTING;
+       }
+
+       public synchronized Service add(Dependency dependency) {
+               synchronized (m_dependencies) {
+                       m_dependencies.add(dependency);
+               }
+               logDependencyAdded(dependency);
+
+               if (getState() == ServiceMonitor.WAITING_FOR_REQUIRED) {
+                       // if we're waiting for required dependencies, and
+                       // this is a required dependency, start tracking it
+                       // ...otherwise, we don't need to do anything yet
+                       if (dependency.isRequired()) {
+                               dependency.start(this);
+                       }
+               } else if (getState() == ServiceMonitor.TRACKING_OPTIONAL) {
+                       // start tracking the dependency
+                       dependency.start(this);
+                       if (dependency.isRequired() && 
!dependency.isAvailable()) {
+                               // if this is a required dependency and it can 
not
+                               // be resolved right away, then we need to go 
back to
+                               // the waiting for required state, until this
+                               // dependency is available
+                               deactivateService();
+                       }
+               }
+               return this;
+       }
+
+       public synchronized Service remove(Dependency dependency) {
+               synchronized (m_dependencies) {
+                       m_dependencies.remove(dependency);
+               }
+               logDependencyRemoved(dependency);
+
+               if (getState() == ServiceMonitor.TRACKING_OPTIONAL) {
+                       // if we're tracking optional dependencies, then any
+                       // dependency that is removed can be stopped without
+                       // causing state changes
+                       dependency.stop(this);
+               } else if (getState() == ServiceMonitor.WAITING_FOR_REQUIRED) {
+                       // if we're waiting for required dependencies, then
+                       // we only need to stop tracking the dependency if it
+                       // too is required; this might trigger a state change
+                       dependency.stop(this);
+                       if (allRequiredDependenciesAvailable()) {
+                               activateService();
+                       }
+               }
+               return this;
+       }
+
+       public List getDependencies() {
+               List list;
+               synchronized (m_dependencies) {
+                       list = (List) m_dependencies.clone();
+               }
+               return list;
+       }
+
+       public ServiceRegistration getServiceRegistration() {
+               return m_registration;
+       }
+
+       public Object getService() {
+               return m_service;
+       }
+
+       public synchronized void dependencyAvailable(Dependency dependency) {
+               if ((dependency.isRequired())
+                               && (getState() == 
ServiceMonitor.WAITING_FOR_REQUIRED)
+                               && (allRequiredDependenciesAvailable())) {
+                       activateService();
+               }
+               if ((!dependency.isRequired())
+                               && (getState() == 
ServiceMonitor.TRACKING_OPTIONAL)) {
+                       updateInstance(dependency);
+               }
+               logDependencyAvailable(dependency);
+       }
+
+       public void dependencyChanged(Dependency dependency) {
+               if (getState() == ServiceMonitor.TRACKING_OPTIONAL) {
+                       updateInstance(dependency);
+               }
+       }
+
+       public synchronized void dependencyUnavailable(Dependency dependency) {
+               if (dependency.isRequired()) {
+                       if (getState() == ServiceMonitor.TRACKING_OPTIONAL) {
+                               if (!allRequiredDependenciesAvailable()) {
+                                       deactivateService();
+                               }
+                       }
+               } else {
+                       // optional dependency
+               }
+               if (getState() == ServiceMonitor.TRACKING_OPTIONAL) {
+                       updateInstance(dependency);
+               }
+               logDependencyUnavailable(dependency);
+       }
+
+       public synchronized void start() {
+               if ((getState() != ServiceMonitor.STARTING)
+                               && (getState() != ServiceMonitor.STOPPING)) {
+                       throw new IllegalStateException("Cannot start from 
state "
+                                       + 
ServiceMonitor.STATE_NAMES[getState()]);
+               }
+               openMonitorServiceTracker();
+               startTrackingRequired();
+               if (allRequiredDependenciesAvailable()
+                               && (getState() == 
ServiceMonitor.WAITING_FOR_REQUIRED)) {
+                       activateService();
+               }
+       }
+
+       public synchronized void stop() {
+               if ((getState() != ServiceMonitor.WAITING_FOR_REQUIRED)
+                               && (getState() != 
ServiceMonitor.TRACKING_OPTIONAL)) {
+                       if ((getState() > 0)
+                                       && (getState() < 
ServiceMonitor.STATE_NAMES.length)) {
+                               throw new IllegalStateException("Cannot stop 
from state "
+                                               + 
ServiceMonitor.STATE_NAMES[getState()]);
+                       } else {
+                               throw new IllegalStateException(
+                                               "Cannot stop from unknown 
state.");
+                       }
+               }
+               if (getState() == ServiceMonitor.TRACKING_OPTIONAL) {
+                       deactivateService();
+               }
+               stopTrackingRequired();
+               closeMonitorServiceTracker();
+       }
+
+       private synchronized void activateService() {
+               if (isStartAsync()) {
+                       new Thread("activating" + 
m_serviceDescription.getImplementation()) {
+                               public void run() {
+                                       activateServiceInternal();
+                               }
+                       }.start();
+               } else {
+                       activateServiceInternal();
+               }
+       }
+
+       private void deactivateService() {
+               // service deactivation logic, first inform the state listeners
+               // we're stopping
+               stateListenersStopping();
+               // then, unregister the service from the framework
+               unregisterService();
+               // invoke the stop callback
+               invoke(m_callbackStop);
+               // stop tracking optional services
+               stopTrackingOptional();
+               // inform the state listeners we've stopped
+               stateListenersStopped();
+               // invoke the destroy callback
+               invoke(m_callbackDestroy);
+               // destroy the service instance
+               destroyService();
+       }
+
+       private void invoke(String name) {
+               if (name != null) {
+                       // invoke method if it exists
+                       AccessibleObject.setAccessible(m_service.getClass()
+                                       .getDeclaredMethods(), true);
+                       try {
+                               m_service.getClass().getDeclaredMethod(name, 
(Class[]) null)
+                                               .invoke(m_service, (Object[]) 
null);
+                       } catch (NoSuchMethodException e) {
+                               // ignore this, we don't care if the method 
does not exist
+                       } catch (Exception e) {
+                               logExceptionOccured(name, e);
+                       }
+               }
+       }
+
+       private synchronized void stateListenersStarting() {
+               Iterator i = m_listeners.iterator();
+               while (i.hasNext()) {
+                       ServiceStateListener ssl = (ServiceStateListener) 
i.next();
+                       ssl.starting(this);
+               }
+       }
+
+       private synchronized void stateListenersStarted() {
+               Iterator i = m_listeners.iterator();
+               while (i.hasNext()) {
+                       ServiceStateListener ssl = (ServiceStateListener) 
i.next();
+                       ssl.started(this);
+               }
+       }
+
+       private synchronized void stateListenersStopping() {
+               Iterator i = m_listeners.iterator();
+               while (i.hasNext()) {
+                       ServiceStateListener ssl = (ServiceStateListener) 
i.next();
+                       ssl.stopping(this);
+               }
+       }
+
+       private synchronized void stateListenersStopped() {
+               Iterator i = m_listeners.iterator();
+               while (i.hasNext()) {
+                       ServiceStateListener ssl = (ServiceStateListener) 
i.next();
+                       ssl.stopped(this);
+               }
+       }
+
+       private boolean allRequiredDependenciesAvailable() {
+               for (Iterator iter = getDependencies().iterator(); 
iter.hasNext();) {
+                       Dependency dependency = (Dependency) iter.next();
+                       if (dependency.isRequired() && 
!dependency.isAvailable()) {
+                               return false;
+                       }
+               }
+               return true;
+       }
+
+       private synchronized void startTrackingOptional() {
+               setState(ServiceMonitor.TRACKING_OPTIONAL);
+               for (Iterator iter = getDependencies().iterator(); 
iter.hasNext();) {
+                       Dependency dependency = (Dependency) iter.next();
+                       if (!dependency.isRequired()) {
+                               dependency.start(this);
+                       }
+               }
+       }
+
+       private synchronized void stopTrackingOptional() {
+               setState(ServiceMonitor.WAITING_FOR_REQUIRED);
+               for (Iterator iter = getDependencies().iterator(); 
iter.hasNext();) {
+                       Dependency dependency = (Dependency) iter.next();
+                       if (!dependency.isRequired()) {
+                               dependency.stop(this);
+                       }
+               }
+       }
+
+       private synchronized void startTrackingRequired() {
+               setState(ServiceMonitor.WAITING_FOR_REQUIRED);
+               for (Iterator iter = getDependencies().iterator(); 
iter.hasNext();) {
+                       Dependency dependency = (Dependency) iter.next();
+                       if (dependency.isRequired()) {
+                               dependency.start(this);
+                       }
+               }
+       }
+
+       private synchronized void stopTrackingRequired() {
+               setState(ServiceMonitor.STOPPING);
+               for (Iterator iter = getDependencies().iterator(); 
iter.hasNext();) {
+                       Dependency dependency = (Dependency) iter.next();
+                       if (dependency.isRequired()) {
+                               dependency.stop(this);
+                       }
+               }
+       }
+
+       private void initService() {
+               if (m_implementation instanceof Class) {
+                       // instantiate
+                       try {
+                               m_service = ((Class) 
m_implementation).newInstance();
+                       } catch (InstantiationException e) {
+                               logExceptionOccured("_init", e);
+                       } catch (IllegalAccessException e) {
+                               logExceptionOccured("_init", e);
+                       }
+               } else {
+                       m_service = m_implementation;
+               }
+
+               // configure the service
+               configureImplementation(BundleContext.class, m_context);
+               configureImplementation(ServiceRegistration.class, 
NULL_REGISTRATION);
+               configureImplementation(Service.class, this);
+
+               openMonitorServiceTracker();
+       }
+
+       private void configureService() {
+               // configure all services (the optional dependencies might be 
configured
+               // as null objects but that's what we want at this point)
+               configureServices();
+       }
+
+       private void destroyService() {
+               unconfigureServices();
+               m_service = null;
+       }
+
+       private void registerService() {
+               if (m_serviceName != null) {
+                       ServiceRegistrationImpl wrapper = new 
ServiceRegistrationImpl();
+                       m_registration = wrapper;
+                       configureImplementation(ServiceRegistration.class, 
wrapper);
+                       // service name can either be a string or an array of 
strings
+                       ServiceRegistration registration;
+                       if (m_serviceName instanceof String) {
+                               registration = m_context.registerService(
+                                               (String) m_serviceName, 
m_service, m_serviceProperties);
+                       } else {
+                               registration = m_context.registerService(
+                                               (String[]) m_serviceName, 
m_service,
+                                               m_serviceProperties);
+                       }
+                       wrapper.setServiceRegistration(registration);
+               }
+       }
+
+       private void unregisterService() {
+               if (m_serviceName != null) {
+                       m_registration.unregister();
+                       configureImplementation(ServiceRegistration.class,
+                                       NULL_REGISTRATION);
+               }
+       }
+
+       private void updateInstance(Dependency dependency) {
+               if (dependency instanceof ServiceDependency) {
+                       ServiceDependency sd = (ServiceDependency) dependency;
+                       // update the dependency in the service instance (it 
will use
+                       // a null object if necessary)
+                       if (sd.isAutoConfig()) {
+                               configureImplementation(sd.getInterface(), 
sd.getService());
+                       }
+               }
+       }
+
+       /**
+        * Configure a field in the service implementation. The service
+        * implementation is searched for fields that have the same type as the
+        * class that was specified 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
+        */
+       private void configureImplementation(Class clazz, Object instance) {
+               Class serviceClazz = m_service.getClass();
+               while (serviceClazz != null) {
+                       Field[] fields = serviceClazz.getDeclaredFields();
+                       AccessibleObject.setAccessible(fields, true);
+                       for (int j = 0; j < fields.length; j++) {
+                               if (fields[j].getType().equals(clazz)) {
+                                       try {
+                                               // synchronized makes sure the 
field is actually written
+                                               // to immediately
+                                               synchronized (new Object()) {
+                                                       
fields[j].set(m_service, instance);
+                                               }
+                                       } catch (Exception e) {
+                                               /*
+                                                * 
System.err.println("Exception while trying to set " +
+                                                * fields[j].getName() + " of 
type " +
+                                                * 
fields[j].getType().getName() + " which should equal
+                                                * type " + clazz.getName() + " 
on " + m_serviceInstance + "
+                                                * of type " + 
serviceClazz.getName() + "\nDumping
+                                                * stack:" ); 
e.printStackTrace();
+                                                */
+                                               throw new 
IllegalStateException("Could not set field "
+                                                               + 
fields[j].getName() + " on " + m_service);
+                                       }
+                               }
+                       }
+                       serviceClazz = serviceClazz.getSuperclass();
+               }
+       }
+
+       private void configureServices() {
+               for (Iterator iter = getDependencies().iterator(); 
iter.hasNext();) {
+                       Dependency dependency = (Dependency) iter.next();
+                       if (dependency instanceof ServiceDependency) {
+                               ServiceDependency sd = (ServiceDependency) 
dependency;
+                               if (sd.isAutoConfig()) {
+                                       
configureImplementation(sd.getInterface(), sd.getService());
+                               }
+                               // for required dependencies, we invoke any 
callbacks here
+                               if (sd.isRequired()) {
+                                       sd.invokeAdded();
+                               }
+                       }
+               }
+       }
+
+       private void unconfigureServices() {
+               for (Iterator iter = getDependencies().iterator(); 
iter.hasNext();) {
+                       Dependency dependency = (Dependency) iter.next();
+                       if (dependency instanceof ServiceDependency) {
+                               ServiceDependency sd = (ServiceDependency) 
dependency;
+                               // for required dependencies, we invoke any 
callbacks here
+                               if (sd.isRequired()) {
+                                       sd.invokeRemoved();
+                               }
+                       }
+               }
+       }
+
+       // ----- LISTENERS
+
+       public synchronized void addStateListener(ServiceStateListener 
listener) {
+               m_listeners.add(listener);
+               if (getState() == ServiceMonitor.TRACKING_OPTIONAL) {
+                       listener.starting(this);
+                       listener.started(this);
+               }
+       }
+
+       public synchronized void removeStateListener(ServiceStateListener 
listener) {
+               m_listeners.remove(listener);
+       }
+
+       synchronized void removeStateListeners() {
+               m_listeners.clear();
+       }
+
+       // ----- CREATION
+
+       /**
+        * Sets if a thread should be created before the start method is called 
on
+        * the service. This is needed because the start method in OSGi is not
+        * allowed to block.
+        * 
+        * @return
+        * 
+        */
+       public synchronized Service setStartAsync(boolean startASync) {
+               m_startAsync = startASync;
+               return this;
+       }
+
+       /**
+        * @see #setStartAsync(boolean)
+        */
+       public boolean isStartAsync() {
+               return m_startAsync;
+       }
+
+       public synchronized Service setInterface(String serviceName,
+                       Dictionary properties) {
+               ensureNotActive();
+               m_serviceName = serviceName;
+               m_serviceProperties = properties;
+               return this;
+       }
+
+       public synchronized Service setInterface(String[] serviceName,
+                       Dictionary properties) {
+               ensureNotActive();
+               m_serviceName = serviceName;
+               m_serviceProperties = properties;
+               return this;
+       }
+
+       public synchronized Service setCallbacks(String init, String start,
+                       String stop, String destroy) {
+               ensureNotActive();
+               m_callbackInit = init;
+               m_callbackStart = start;
+               m_callbackStop = stop;
+               m_callbackDestroy = destroy;
+               return this;
+       }
+
+       public synchronized Service setImplementation(Object implementation) {
+               ensureNotActive();
+               m_implementation = implementation;
+
+               // initialize the service instance itself
+               // meaning it is created if necessary and the bundle context is 
set
+               initService();
+
+               return this;
+       }
+
+       private void ensureNotActive() {
+               if ((getState() == ServiceMonitor.TRACKING_OPTIONAL)
+                               || (getState() == 
ServiceMonitor.WAITING_FOR_REQUIRED)) {
+                       throw new IllegalStateException("Cannot modify state 
while active.");
+               }
+       }
+
+       boolean isRegistered() {
+               return (getState() == ServiceMonitor.TRACKING_OPTIONAL);
+       }
+
+       public String toString() {
+               return "ServiceImpl["
+                               + (m_serviceName == null ? "(no interface)" : 
m_serviceName)
+                               + " " + m_implementation + "]";
+       }
+
+       public synchronized Dictionary getServiceProperties() {
+               if (m_serviceProperties != null) {
+                       return (Dictionary) ((Hashtable) 
m_serviceProperties).clone();
+               } else {
+                       return null;
+               }
+       }
+
+       public synchronized void setServiceProperties(Dictionary 
serviceProperties) {
+               m_serviceProperties = serviceProperties;
+               if (isRegistered() && (m_serviceName != null)
+                               && (m_serviceProperties != null)) {
+                       m_registration.setProperties(m_serviceProperties);
+               }
+       }
+
+       private void setState(int state) {
+               if (state == m_state)
+                       return;
+               // if ( state == ServiceMonitor.TRACKING_OPTIONAL )
+               // {
+               // Exception e = new Exception( "Tracking optional for " +
+               // m_serviceDescription.getImplementation() );
+               // e.printStackTrace();
+               // ( ( ServiceDescriptionImpl ) m_serviceDescription 
).exception = e;
+               // }
+               m_state = state;
+               logCurrentState();
+       }
+
+       private int getState() {
+               return m_state;
+       }
+
+       // 
------------------------------------------------------------------------
+       // ServiceDependencyMonitor stuff
+       // 
------------------------------------------------------------------------
+
+       private void openMonitorServiceTracker() {
+               if (m_monitorServiceTracker != null)
+                       return;
+               m_monitorServiceTracker = new ServiceTracker(m_context,
+                               ServiceMonitor.class.getName(), null);
+               m_monitorServiceTracker.open();
+               logCurrentState();
+       }
+
+       private void closeMonitorServiceTracker() {
+               if (m_monitorServiceTracker == null)
+                       return;
+               m_monitorServiceTracker.close();
+               m_monitorServiceTracker = null;
+       }
+
+       private void logCurrentState() {
+               ServiceMonitor monitor = getServiceDependencyMonitor();
+               if (monitor == null) {
+                       return;
+               }
+               monitor.serviceStateChanged(m_serviceDescription, getState());
+       }
+
+       private void logDependencyAvailable(Dependency dependency) {
+               ServiceMonitor monitor = getServiceDependencyMonitor();
+               if (monitor == null) {
+                       return;
+               }
+               monitor.dependencyAvailable(m_serviceDescription, dependency);
+       }
+
+       private void logDependencyUnavailable(Dependency dependency) {
+               ServiceMonitor monitor = getServiceDependencyMonitor();
+               if (monitor == null) {
+                       return;
+               }
+               monitor.dependencyUnavailable(m_serviceDescription, dependency);
+       }
+
+       public void logExceptionOccured(String method, Throwable e) {
+               ServiceMonitor monitor = getServiceDependencyMonitor();
+               if (monitor == null) {
+                       e.printStackTrace();
+                       return;
+               }
+               monitor.exceptionOccured(m_serviceDescription, method, e);
+       }
+
+       private void logDependencyAdded(Dependency dependency) {
+               ServiceMonitor monitor = getServiceDependencyMonitor();
+               if (monitor == null) {
+                       return;
+               }
+               monitor.dependencyAdded(m_serviceDescription, dependency);
+       }
+
+       private void logDependencyRemoved(Dependency dependency) {
+               ServiceMonitor monitor = getServiceDependencyMonitor();
+               if (monitor == null) {
+                       return;
+               }
+               monitor.dependencyRemoved(m_serviceDescription, dependency);
+       }
+
+       private ServiceMonitor getServiceDependencyMonitor() {
+               if (m_monitorServiceTracker == null)
+                       return null; // the service tracker has not started yet
+               return (ServiceMonitor) m_monitorServiceTracker.getService();
+       }
+
+       // 
------------------------------------------------------------------------
+
+       private synchronized void activateServiceInternal() {
+               if (getState() == ServiceMonitor.TRACKING_OPTIONAL) {
+                       // System.out.println("already tracking optional for " +
+                       // m_serviceDescription.getImplementation());
+                       return;
+                       // 
((ServiceDescriptionImpl)m_serviceDescription).exception.printStackTrace();
+                       // System.out.println("activateServiceInternal() 
==============");
+                       // throw new RuntimeException("Already activated 
service " +
+                       // m_serviceDescription.getImplementation());
+
+               }
+               if (null == m_service) {
+                       initService();
+               }
+
+               // Invoke the init callback so the service can further 
initialize
+               // itself
+               invoke(m_callbackInit);
+               // now is the time to configure the service, meaning all 
required
+               // dependencies will be set and any callbacks called
+               configureService();
+               // inform the state listeners we're starting
+               stateListenersStarting();
+               // start tracking optional services
+               startTrackingOptional();
+               // invoke the start callback, since we're now ready to be used
+               invoke(m_callbackStart);
+               // register the service in the framework's service registry
+               registerService();
+               // inform the state listeners we've started
+               stateListenersStarted();
+       }
+
+       static {
+               NULL_REGISTRATION = (ServiceRegistration) 
Proxy.newProxyInstance(
+                               
MonitorEnabledServiceImpl.class.getClassLoader(),
+                               new Class[] { ServiceRegistration.class },
+                               new DefaultNullObject());
+       }
+}

Property changes on: 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/MonitorEnabledServiceImpl.java
___________________________________________________________________
Name: svn:executable
   + *

Index: 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/Service.java
===================================================================
--- 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/Service.java
    (revision 502604)
+++ 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/Service.java
    (working copy)
@@ -192,4 +192,28 @@
      * for this service.
      */
     public void stop();
+    
+
+    
+    /**
+     * Sets if a thread should be created before the start method is called
+     * on the service.
+     * This can be needed because the start method in the OSGi Activator is 
not allowed to block.
+     * Default is false if it is not set.
+     */
+    public Service setStartAsync(boolean startASync);
+ 
+       /**
+        * Notifies ServiceMonitor (if available) that an exception has occured.
+        * 
+        * @param method the name of the method in the service in which the 
exception occurred
+        * @param e the exception that occured
+        */
+       public void logExceptionOccured(String method, Throwable e);
+    
+    
+    /**
+     * @see #setStartAsync(boolean)
+     */
+    public boolean isStartAsync();
 }
Index: 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceDescription.java
===================================================================
--- 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceDescription.java
 (revision 0)
+++ 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceDescription.java
 (revision 0)
@@ -0,0 +1,41 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed 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.dependencymanager;
+
+
+
+import java.util.Dictionary;
+
+
+
+
+public interface ServiceDescription {
+
+       String[] getServiceNames();
+
+    String getImplementation();
+
+       Dictionary getServiceProperties();
+
+       Dependency[] getDependencies(); 
+
+    Dependency[] getDependencies( boolean available, boolean onlyRequired );
+
+    
+
+}
+
Index: 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java
===================================================================
--- 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java
        (revision 502604)
+++ 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java
        (working copy)
@@ -573,4 +573,19 @@
     static {
         NULL_REGISTRATION = (ServiceRegistration) 
Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(), new Class[] 
{ServiceRegistration.class}, new DefaultNullObject()); 
     }
+
+       public boolean isStartAsync() {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       public void logExceptionOccured(String method, Throwable e) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       public Service setStartAsync(boolean startASync) {
+               // TODO Auto-generated method stub
+               return null;
+       }
 }
Index: 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceMonitor.java
===================================================================
--- 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceMonitor.java
     (revision 0)
+++ 
/Users/peter/code/felix/org.apache.felix.dependencymanager/src/main/java/org/apache/felix/dependencymanager/ServiceMonitor.java
     (revision 0)
@@ -0,0 +1,73 @@
+/*
+ *   Copyright 2006 The Apache Software Foundation
+ *
+ *   Licensed 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.dependencymanager;
+
+import org.apache.felix.dependencymanager.Dependency;
+import org.apache.felix.dependencymanager.ServiceDescription;
+
+
+/**
+ * A OSGi service that can listen for dependency events.
+ * If this service is not available then no tracking of dependency event will 
occure.
+ * 
+ * @author Andreas Ronge
+ *
+ */
+public interface ServiceMonitor {
+
+       int UNKNOWN = 0;
+       int STARTING = 1;
+       int WAITING_FOR_REQUIRED = 2;
+       int TRACKING_OPTIONAL = 3;
+       int STOPPING = 4;
+       String[] STATE_NAMES = {
+       "(unknown)", 
+       "starting", 
+       "waiting for required dependencies", 
+       "tracking optional dependencies", 
+       "stopping"};
+
+
+       /**
+        * Called when the state of a service has changed.
+        * @param service the service which has changed the state.
+        * @param the new state
+        */
+       void serviceStateChanged(ServiceDescription service,  int newState );
+       
+       void dependencyAdded(ServiceDescription service, Dependency 
addedDependency );
+       
+       void dependencyRemoved(ServiceDescription service, Dependency 
removedDependency );
+       
+       /***
+        * called when a dependency was added to the service.
+        */
+       void dependencyAvailable(ServiceDescription service,  Dependency 
availableDependency );
+       
+       /**
+        * called when a dependency was removed to the service
+        */
+       void dependencyUnavailable(ServiceDescription service,  Dependency 
unavailableDependency );
+
+       /**
+        * Called when a service throws an exception in a service callback 
method or constructor.
+        * @param service
+        * @param serviceCallbackMethod the callback method which throwed an 
exception ("_init" for constructor).
+        * @param e
+        */
+       void exceptionOccured(ServiceDescription service, String 
serviceCallbackMethod, Throwable e);
+}

Reply via email to