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);
+}