Preparing move.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@882947 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager.temp/LICENSE b/dependencymanager.temp/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/dependencymanager.temp/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/dependencymanager.temp/NOTICE b/dependencymanager.temp/NOTICE
new file mode 100644
index 0000000..cfc3633
--- /dev/null
+++ b/dependencymanager.temp/NOTICE
@@ -0,0 +1,26 @@
+Apache Felix Dependency Manager
+Copyright 2009 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+
+II. Used Software
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2007).
+Licensed under the Apache License 2.0.
+
+
+III. License Summary
+- Apache License 2.0
diff --git a/dependencymanager.temp/pom.xml b/dependencymanager.temp/pom.xml
new file mode 100644
index 0000000..9012544
--- /dev/null
+++ b/dependencymanager.temp/pom.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+  <!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements. See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to you under the Apache License, Version
+    2.0 (the "License"); you may not use this file except in compliance
+    with the License. You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+    applicable law or agreed to in writing, software distributed under
+    the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
+    OR CONDITIONS OF ANY KIND, either express or implied. See the
+    License for the specific language governing permissions and
+    limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.apache.felix</groupId>
+    <artifactId>felix</artifactId>
+    <version>1.0.4</version>
+    <relativePath>../pom/pom.xml</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <packaging>bundle</packaging>
+  <name>Apache Felix Dependency Manager</name>
+  <version>3.0.0-SNAPSHOT</version>
+  <artifactId>org.apache.felix.dependencymanager</artifactId>
+  <dependencies>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <version>1.2.0</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <version>1.2.0</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam</artifactId>
+      <version>1.2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam-container-default</artifactId>
+      <version>1.2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.ops4j.pax.exam</groupId>
+      <artifactId>pax-exam-junit</artifactId>
+      <version>1.2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.7</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>1.4.0</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>org.apache.felix.dependencymanager</Bundle-SymbolicName>
+            <Bundle-Name>Apache Felix Dependency Manager</Bundle-Name>
+            <Bundle-Description>A bundle that provides a run-time
+              service dependency manager.</Bundle-Description>
+            <Bundle-Vendor>The Apache Software Foundation</Bundle-Vendor>
+            <Export-Package>org.apache.felix.dependencymanager</Export-Package>
+            <Import-Package>!org.apache.felix.dependencymanager,*</Import-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>default-testCompile</id>
+            <configuration>
+              <source>1.5</source>
+              <target>1.5</target>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.ops4j.pax.exam</groupId>
+        <artifactId>maven-paxexam-plugin</artifactId>
+        <version>1.2.0</version>
+        <executions>
+          <execution>
+            <id>generate-config</id>
+            <goals>
+              <goal>generate-depends-file</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:svn:https://svn.apache.org/repos/asf/felix/releases/org.apache.felix.dependencymanager-3.0.0</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/felix/releases/org.apache.felix.dependencymanager-3.0.0</developerConnection>
+    <url>scm:svn:https://svn.apache.org/repos/asf/felix/releases/org.apache.felix.dependencymanager-3.0.0</url>
+  </scm>
+</project>
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ConfigurationDependency.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ConfigurationDependency.java
new file mode 100644
index 0000000..f7ac01b
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ConfigurationDependency.java
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Dictionary;
+import java.util.Properties;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedService;
+
+/**
+ * Configuration dependency that can track the availability of a (valid) configuration.
+ * To use it, specify a PID for the configuration. The dependency is always required,
+ * because if it is not, it does not make sense to use the dependency manager. In that
+ * scenario, simply register your service as a <code>ManagedService(Factory)</code> and
+ * handle everything yourself. Also, only managed services are supported, not factories.
+ * There are a couple of things you need to be aware of when implementing the
+ * <code>updated(Dictionary)</code> method:
+ * <ul>
+ * <li>Make sure it throws a <code>ConfigurationException</code> when you get a
+ * configuration that is invalid. In this case, the dependency will not change:
+ * if it was not available, it will still not be. If it was available, it will
+ * remain available and implicitly assume you keep working with your old
+ * configuration.</li>
+ * <li>This method will be called before all required dependencies are available.
+ * Make sure you do not depend on these to parse your settings.</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ConfigurationDependency implements Dependency, ManagedService, ServiceComponentDependency {
+	private BundleContext m_context;
+	private String m_pid;
+	private ServiceRegistration m_registration;
+	private volatile Service m_service;
+	private Dictionary m_settings;
+	private boolean m_propagate;
+	private final Logger m_logger;
+    private String m_callback;
+	
+	public ConfigurationDependency(BundleContext context, Logger logger) {
+		m_context = context;
+		m_logger = logger;
+	}
+	
+	public synchronized boolean isAvailable() {
+		return m_settings != null;
+	}
+
+	/**
+	 * Will always return <code>true</code> as optional configuration dependencies
+	 * do not make sense. You might as well just implement <code>ManagedService</code>
+	 * yourself in those cases.
+	 */
+	public boolean isRequired() {
+		return true;
+	}
+	
+	/**
+	 * Returns <code>true</code> when configuration properties should be propagated
+	 * as service properties.
+	 */
+	public boolean isPropagated() {
+		return m_propagate;
+	}
+	
+	public Dictionary getConfiguration() {
+		return m_settings;
+	}
+	
+	public void start(Service service) {
+		m_service = service;
+		Properties props = new Properties();
+		props.put(Constants.SERVICE_PID, m_pid);
+		m_registration = m_context.registerService(ManagedService.class.getName(), this, props);
+	}
+
+	public void stop(Service service) {
+		m_registration.unregister();
+		m_service = null;
+	}
+
+        public Dependency setCallback(String callback) {
+		m_callback = callback;
+		return this;
+	}
+
+	public void updated(Dictionary settings) throws ConfigurationException {
+		// if non-null settings come in, we have to instantiate the service and
+		// apply these settings
+		((ServiceImpl) m_service).initService();
+		Object service = m_service.getService();
+				
+		Dictionary oldSettings = null; 
+		synchronized (this) {
+			oldSettings = m_settings;
+		}
+		
+		if (oldSettings == null && settings == null) {
+	       // CM has started but our configuration is not still present in the CM database: ignore
+	       return;
+		}
+		
+        if (service != null) {
+          	String callback = (m_callback == null) ? "updated" : m_callback;
+      	  	Method m;
+			try {
+			  	m = service.getClass().getDeclaredMethod(callback, new Class[] { Dictionary.class });
+			  	m.setAccessible(true);
+			  	// if exception is thrown here, what does that mean for the
+			  	// state of this dependency? how smart do we want to be??
+			  	// it's okay like this, if the new settings contain errors, we
+			  	// remain in the state we were, assuming that any error causes
+			  	// the "old" configuration to stay in effect.
+			  	// CM will log any thrown exceptions.
+			  	m.invoke(service, new Object[] { settings });
+			} 
+      	  	catch (InvocationTargetException e) {
+                // The component has thrown an exception during it's callback invocation.
+                if (e.getTargetException() instanceof ConfigurationException) {
+                    // the callback threw an OSGi ConfigurationException: just re-throw it.
+                    throw (ConfigurationException) e.getTargetException();
+                }
+                else {
+                    // wrap the callback exception into a ConfigurationException.
+                    throw new ConfigurationException(null, "Service " + m_service + " with " + this.toString() + " could not be updated", e.getTargetException());
+                }
+            }
+            catch (Throwable t) {
+                // wrap any other exception as a ConfigurationException.
+                throw new ConfigurationException(null, "Service " + m_service + " with " + this.toString() + " could not be updated", t);
+            }
+        }
+        else {
+            m_logger.log(Logger.LOG_ERROR, "Service " + m_service + " with configuration dependency " + this + " could not be instantiated.");
+            return;
+        }
+
+		// If these settings did not cause a configuration exception, we determine if they have 
+		// caused the dependency state to change
+		synchronized (this) {
+			m_settings = settings;
+		}
+
+		if ((oldSettings == null) && (settings != null)) {
+			m_service.dependencyAvailable(this);
+		}
+		if ((oldSettings != null) && (settings == null)) {
+			m_service.dependencyUnavailable(this);
+		}
+		if ((oldSettings != null) && (settings != null)) {
+			m_service.dependencyChanged(this);
+		}
+	}
+
+	/**
+	 * Sets the <code>service.pid</code> of the configuration you
+	 * are depending on.
+	 */
+	public ConfigurationDependency setPid(String pid) {
+		ensureNotActive();
+		m_pid = pid;
+		return this;
+	}
+
+	/**
+	 * Sets propagation of the configuration properties to the service
+	 * properties. Any additional service properties specified directly
+	 * are merged with these.
+	 */
+	public ConfigurationDependency setPropagate(boolean propagate) {
+		ensureNotActive();
+		m_propagate = propagate;
+		return this;
+	}
+	
+	private void ensureNotActive() {
+	  	if (m_service != null) {
+	  	  throw new IllegalStateException("Cannot modify state while active.");
+	  	}
+    }
+    
+    public String toString() {
+    	return "ConfigurationDependency[" + m_pid + "]";
+    }
+
+    public String getName() {
+        return m_pid;
+    }
+
+    public int getState() {
+        return (isAvailable() ? 1 : 0) + (isRequired() ? 2 : 0);
+    }
+
+    public String getType() {
+        return "configuration";
+    }
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/DefaultNullObject.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/DefaultNullObject.java
new file mode 100644
index 0000000..79bb240
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/DefaultNullObject.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+
+/**
+ * Default null object implementation. Uses a dynamic proxy. Null objects are used
+ * as placeholders for services that are not available.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class DefaultNullObject implements InvocationHandler {
+    private static final Boolean DEFAULT_BOOLEAN = Boolean.FALSE;
+    private static final Byte DEFAULT_BYTE = new Byte((byte) 0);
+    private static final Short DEFAULT_SHORT = new Short((short) 0);
+    private static final Integer DEFAULT_INT = new Integer(0);
+    private static final Long DEFAULT_LONG = new Long(0);
+    private static final Float DEFAULT_FLOAT = new Float(0.0f);
+    private static final Double DEFAULT_DOUBLE = new Double(0.0);
+    
+    /**
+     * Invokes a method on this null object. The method will return a default
+     * value without doing anything.
+     */
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        Class returnType = method.getReturnType();
+        if (returnType.equals(Boolean.class) || returnType.equals(Boolean.TYPE)) {
+            return DEFAULT_BOOLEAN;
+        }
+        else if (returnType.equals(Byte.class) || returnType.equals(Byte.TYPE)) {
+            return DEFAULT_BYTE;
+        } 
+        else if (returnType.equals(Short.class) || returnType.equals(Short.TYPE)) {
+            return DEFAULT_SHORT;
+        } 
+        else if (returnType.equals(Integer.class) || returnType.equals(Integer.TYPE)) {
+            return DEFAULT_INT;
+        } 
+        else if (returnType.equals(Long.class) || returnType.equals(Long.TYPE)) {
+            return DEFAULT_LONG;
+        } 
+        else if (returnType.equals(Float.class) || returnType.equals(Float.TYPE)) {
+            return DEFAULT_FLOAT;
+        } 
+        else if (returnType.equals(Double.class) || returnType.equals(Double.TYPE)) {
+            return DEFAULT_DOUBLE;
+        } 
+        else {
+            return null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/Dependency.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/Dependency.java
new file mode 100644
index 0000000..64d241a
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/Dependency.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+/**
+ * Generic dependency for a service. A dependency can be required or not.
+ * A dependency will be activated by the service it belongs to. The service
+ * will call the <code>start(Service service)</code> and 
+ * <code>stop(Service service)</code> methods.
+ * 
+ * After it has been started, a dependency must callback
+ * the associated service's <code>dependencyAvailable()</code> and 
+ * <code>dependencyUnavailable()</code>
+ * methods. State changes of the dependency itself may only be made as long as
+ * the dependency is not 'active', meaning it is associated with a running service.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Dependency {
+    /**
+     * Returns <code>true</code> if this a required dependency. Required dependencies
+     * are dependencies that must be available before the service can be activated.
+     * 
+     * @return <code>true</code> if the dependency is required
+     */
+    public boolean isRequired();
+    
+    /**
+     * Returns <code>true</code> if the dependency is available.
+     * 
+     * @return <code>true</code> if the dependency is available
+     */
+    public boolean isAvailable();
+    
+    /**
+     * Starts tracking the dependency. This activates some implementation
+     * specific mechanism to do the actual tracking. If the tracking discovers
+     * that the dependency becomes available, it should call 
+     * <code>dependencyAvailable()</code> on the service.
+     * 
+     * @param service the service that is associated with this dependency
+     */
+    public void start(Service service);
+    
+    /**
+     * Stops tracking the dependency. This deactivates the tracking. If the
+     * dependency was available, the tracker should call 
+     * <code>dependencyUnavaible()</code> before stopping itself to ensure
+     * that dependencies that aren't "active" are unavailable.
+     */
+    public void stop(Service service);
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/DependencyActivatorBase.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/DependencyActivatorBase.java
new file mode 100644
index 0000000..2fa8b13
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/DependencyActivatorBase.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.util.List;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Base bundle activator class. Subclass this activator if you want to use dependency
+ * management in your bundle. There are two methods you should implement:
+ * <code>init()</code> and <code>destroy()</code>. Both methods take two arguments,
+ * the bundle context and the dependency manager. The dependency manager can be used
+ * to define all the dependencies.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class DependencyActivatorBase implements BundleActivator {
+    private BundleContext m_context;
+    private DependencyManager m_manager;
+    private Logger m_logger;
+    
+    /**
+     * Initialize the dependency manager. Here you can add all services and their dependencies.
+     * If something goes wrong and you do not want your bundle to be started, you can throw an
+     * exception. This exception will be passed on to the <code>start()</code> method of the
+     * bundle activator, causing the bundle not to start.
+     * 
+     * @param context the bundle context
+     * @param manager the dependency manager
+     * @throws Exception if the initialization fails
+     */
+    public abstract void init(BundleContext context, DependencyManager manager) throws Exception;
+    
+    /**
+     * Destroy the dependency manager. Here you can remove all services and their dependencies.
+     * Actually, the base class will clean up your dependencies anyway, so most of the time you
+     * don't need to do anything here.
+     * If something goes wrong and you do not want your bundle to be stopped, you can throw an
+     * exception. This exception will be passed on to the <code>stop()</code> method of the
+     * bundle activator, causing the bundle not to stop.
+     * 
+     * @param context the bundle context
+     * @param manager the dependency manager
+     * @throws Exception if the destruction fails
+     */
+    public abstract void destroy(BundleContext context, DependencyManager manager) throws Exception;
+
+    /**
+     * Start method of the bundle activator. Initializes the dependency manager
+     * and calls <code>init()</code>.
+     * 
+     * @param context the bundle context
+     */
+    public void start(BundleContext context) throws Exception {
+        m_context = context;
+        m_logger = new Logger(context);
+        m_manager = new DependencyManager(context, m_logger);
+        init(m_context, m_manager);
+    }
+
+    /**
+     * Stop method of the bundle activator. Calls the <code>destroy()</code> method
+     * and cleans up all left over dependencies.
+     * 
+     * @param context the bundle context
+     */
+    public void stop(BundleContext context) throws Exception {
+        destroy(m_context, m_manager);
+        cleanup(m_manager);
+        m_manager = null;
+        m_context = null;
+    }
+    
+    /**
+     * Creates a new service.
+     * 
+     * @return the new service
+     */
+    public Service createService() {
+        return new ServiceImpl(m_context, m_manager, m_logger);
+    }
+    
+    /**
+     * Creates a new service dependency.
+     * 
+     * @return the service dependency
+     */
+    public ServiceDependency createServiceDependency() {
+        return new ServiceDependency(m_context, m_logger);
+    }
+    
+    /**
+     * Creates a new configuration dependency.
+     * 
+     * @return the configuration dependency
+     */
+    public ConfigurationDependency createConfigurationDependency() {
+    	return new ConfigurationDependency(m_context, m_logger);
+    }
+
+    /**
+     * Cleans up all services and their dependencies.
+     * 
+     * @param manager the dependency manager
+     */
+    private void cleanup(DependencyManager manager) {
+        List services = manager.getServices();
+        for (int i = services.size() - 1; i >= 0; i--) {
+            Service service = (Service) services.get(i);
+            manager.remove(service);
+            // remove any state listeners that are still registered
+            if (service instanceof ServiceImpl) {
+                ServiceImpl si = (ServiceImpl) service;
+                si.removeStateListeners();
+            }
+        }
+    }
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/DependencyManager.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/DependencyManager.java
new file mode 100644
index 0000000..5c99c7b
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/DependencyManager.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * The dependency manager. Manages all services and their dependencies.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DependencyManager {
+    private final BundleContext m_context;
+    private final Logger m_logger;
+    private List m_services = Collections.synchronizedList(new ArrayList());
+
+    /**
+     * Creates a new dependency manager.
+     * 
+     * @param context the bundle context
+     * @param logger 
+     */
+    public DependencyManager(BundleContext context, Logger logger) {
+        m_context = context;
+        m_logger = logger;
+    }
+    
+    /**
+     * Adds a new service to the dependency manager. After the service was added
+     * it will be started immediately.
+     * 
+     * @param service the service to add
+     */
+    public void add(Service service) {
+        m_services.add(service);
+        service.start();
+    }
+
+    /**
+     * Removes a service from the dependency manager. Before the service is removed
+     * it is stopped first.
+     * 
+     * @param service the service to remove
+     */
+    public void remove(Service service) {
+        service.stop();
+        m_services.remove(service);
+    }
+
+    /**
+     * Creates a new service.
+     * 
+     * @return the new service
+     */
+    public Service createService() {
+        return new ServiceImpl(m_context, this, m_logger);
+    }
+    
+    /**
+     * Creates a new service dependency.
+     * 
+     * @return the service dependency
+     */
+    public ServiceDependency createServiceDependency() {
+        return new ServiceDependency(m_context, m_logger);
+    }
+    
+    public ConfigurationDependency createConfigurationDependency() {
+        return new ConfigurationDependency(m_context, m_logger);
+    }
+    
+    /**
+     * Returns a list of services.
+     * 
+     * @return a list of services
+     */
+    public List getServices() {
+        return Collections.unmodifiableList(m_services);
+    }
+
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/Logger.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/Logger.java
new file mode 100644
index 0000000..ab85366
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/Logger.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This class mimics the standard OSGi <tt>LogService</tt> interface. An
+ * instance of this class is used by the dependency manager for all logging. 
+ * By default this class logs messages to standard out. The log level can be set to
+ * control the amount of logging performed, where a higher number results in
+ * more logging. A log level of zero turns off logging completely.
+ * 
+ * The log levels match those specified in the OSGi Log Service.
+ * This class also tracks log services and will use the highest ranking 
+ * log service, if present, as a back end instead of printing to standard
+ * out. The class uses reflection to invoking the log service's method to 
+ * avoid a dependency on the log interface. This class is in many ways similar
+ * to the one used in the system bundle for that same purpose.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Logger implements ServiceListener {
+    public static final int LOG_ERROR = 1;
+    public static final int LOG_WARNING = 2;
+    public static final int LOG_INFO = 3;
+    public static final int LOG_DEBUG = 4;
+
+    private final BundleContext m_context;
+
+    private final static int LOGGER_OBJECT_IDX = 0;
+    private final static int LOGGER_METHOD_IDX = 1;
+    private ServiceReference m_logRef = null;
+    private Object[] m_logger = null;
+
+    public Logger(BundleContext context) {
+        m_context = context;
+        startListeningForLogService();
+    }
+
+    public final void log(int level, String msg) {
+        _log(null, level, msg, null);
+    }
+
+    public final void log(int level, String msg, Throwable throwable) {
+        _log(null, level, msg, throwable);
+    }
+
+    public final void log(ServiceReference sr, int level, String msg) {
+        _log(sr, level, msg, null);
+    }
+
+    public final void log(ServiceReference sr, int level, String msg, Throwable throwable) {
+        _log(sr, level, msg, throwable);
+    }
+
+    protected void doLog(ServiceReference sr, int level, String msg, Throwable throwable) {
+        String s = (sr == null) ? null : "SvcRef " + sr;
+        s = (s == null) ? msg : s + " " + msg;
+        s = (throwable == null) ? s : s + " (" + throwable + ")";
+        switch (level) {
+            case LOG_DEBUG:
+                System.out.println("DEBUG: " + s);
+                break;
+            case LOG_ERROR:
+                System.out.println("ERROR: " + s);
+                if (throwable != null) {
+                    if ((throwable instanceof BundleException) && (((BundleException) throwable).getNestedException() != null)) {
+                        throwable = ((BundleException) throwable).getNestedException();
+                    }
+                    throwable.printStackTrace();
+                }
+                break;
+            case LOG_INFO:
+                System.out.println("INFO: " + s);
+                break;
+            case LOG_WARNING:
+                System.out.println("WARNING: " + s);
+                break;
+            default:
+                System.out.println("UNKNOWN[" + level + "]: " + s);
+        }
+    }
+
+    private void _log(ServiceReference sr, int level, String msg, Throwable throwable) {
+        // Save our own copy just in case it changes. We could try to do
+        // more conservative locking here, but let's be optimistic.
+        Object[] logger = m_logger;
+        // Use the log service if available.
+        if (logger != null) {
+            _logReflectively(logger, sr, level, msg, throwable);
+        }
+        // Otherwise, default logging action.
+        else {
+            doLog(sr, level, msg, throwable);
+        }
+    }
+
+    private void _logReflectively(Object[] logger, ServiceReference sr, int level, String msg, Throwable throwable) {
+        if (logger != null) {
+            Object[] params = { sr, new Integer(level), msg, throwable };
+            try {
+                ((Method) logger[LOGGER_METHOD_IDX]).invoke(logger[LOGGER_OBJECT_IDX], params);
+            }
+            catch (InvocationTargetException ex) {
+                System.err.println("Logger: " + ex);
+            }
+            catch (IllegalAccessException ex) {
+                System.err.println("Logger: " + ex);
+            }
+        }
+    }
+
+    /**
+     * This method is called when the bundle context is set;
+     * it simply adds a service listener so that the bundle can track
+     * log services to be used as the back end of the logging mechanism. It also
+     * attempts to get an existing log service, if present, but in general
+     * there will never be a log service present since the system bundle is
+     * started before every other bundle.
+     */
+    private synchronized void startListeningForLogService() {
+        // Add a service listener for log services.
+        try {
+            m_context.addServiceListener(this, "(objectClass=org.osgi.service.log.LogService)");
+        }
+        catch (InvalidSyntaxException ex) {
+            // This will never happen since the filter is hard coded.
+        }
+        // Try to get an existing log service.
+        m_logRef = m_context.getServiceReference("org.osgi.service.log.LogService");
+        // Get the service object if available and set it in the logger.
+        if (m_logRef != null) {
+            setLogger(m_context.getService(m_logRef));
+        }
+    }
+
+    /**
+     * This method implements the callback for the ServiceListener interface.
+     * It is public as a byproduct of implementing the interface and should
+     * not be called directly. This method tracks run-time changes to log
+     * service availability. If the log service being used by the framework's
+     * logging mechanism goes away, then this will try to find an alternative.
+     * If a higher ranking log service is registered, then this will switch
+     * to the higher ranking log service.
+     */
+    public final synchronized void serviceChanged(ServiceEvent event) {
+        // If no logger is in use, then grab this one.
+        if ((event.getType() == ServiceEvent.REGISTERED) && (m_logRef == null)) {
+            m_logRef = event.getServiceReference();
+            // Get the service object and set it in the logger.
+            setLogger(m_context.getService(m_logRef));
+        }
+        // If a logger is in use, but this one has a higher ranking, then swap
+        // it for the existing logger.
+        else if ((event.getType() == ServiceEvent.REGISTERED) && (m_logRef != null)) {
+            ServiceReference ref = m_context.getServiceReference("org.osgi.service.log.LogService");
+            if (!ref.equals(m_logRef)) {
+                m_context.ungetService(m_logRef);
+                m_logRef = ref;
+                setLogger(m_context.getService(m_logRef));
+            }
+        }
+        // If the current logger is going away, release it and try to
+        // find another one.
+        else if ((event.getType() == ServiceEvent.UNREGISTERING) && m_logRef.equals(event.getServiceReference())) {
+            // Unget the service object.
+            m_context.ungetService(m_logRef);
+            // Try to get an existing log service.
+            m_logRef = m_context.getServiceReference("org.osgi.service.log.LogService");
+            // Get the service object if available and set it in the logger.
+            if (m_logRef != null) {
+                setLogger(m_context.getService(m_logRef));
+            }
+            else {
+                setLogger(null);
+            }
+        }
+    }
+
+    /**
+     * This method sets the new log service object. It also caches the method to
+     * invoke. The service object and method are stored in array to optimistically
+     * eliminate the need to locking when logging.
+     */
+    private void setLogger(Object logObj) {
+        if (logObj == null) {
+            m_logger = null;
+        }
+        else {
+            Class[] formalParams = { ServiceReference.class, Integer.TYPE, String.class, Throwable.class };
+            try {
+                Method logMethod = logObj.getClass().getMethod("log", formalParams);
+                logMethod.setAccessible(true);
+                m_logger = new Object[] { logObj, logMethod };
+            }
+            catch (NoSuchMethodException ex) {
+                System.err.println("Logger: " + ex);
+                m_logger = null;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/SerialExecutor.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/SerialExecutor.java
new file mode 100644
index 0000000..72063c3
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/SerialExecutor.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+/**
+ * Allows you to enqueue tasks from multiple threads and then execute
+ * them on one thread sequentially. It assumes more than one thread will
+ * try to execute the tasks and it will make an effort to pick the first
+ * task that comes along whilst making sure subsequent tasks return
+ * without waiting.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class SerialExecutor {
+    private final LinkedList m_workQueue = new LinkedList();
+    private Runnable m_active;
+    
+    /**
+     * Enqueue a new task for later execution. This method is
+     * thread-safe, so multiple threads can contribute tasks.
+     * 
+     * @param runnable the runnable containing the actual task
+     */
+    public synchronized void enqueue(final Runnable runnable) {
+    	m_workQueue.addLast(new Runnable() {
+			public void run() {
+				try {
+					runnable.run();
+				}
+				finally {
+					scheduleNext();
+				}
+			}
+		});
+    }
+    
+    /**
+     * Execute any pending tasks. This method is thread safe,
+     * so multiple threads can try to execute the pending
+     * tasks, but only the first will be used to actually do
+     * so. Other threads will return immediately.
+     */
+    public void execute() {
+    	Runnable active;
+    	synchronized (this) {
+    		active = m_active;
+    	}
+    	if (active == null) {
+    		scheduleNext();
+    	}
+    }
+
+    private void scheduleNext() {
+    	Runnable active;
+    	synchronized (this) {
+    		try {
+    			m_active = (Runnable) m_workQueue.removeFirst();
+    		}
+    		catch (NoSuchElementException e) {
+    			m_active = null;
+    		}
+    		active = m_active;
+    	}
+    	if (active != null) {
+            active.run();
+        }
+    }
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/Service.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/Service.java
new file mode 100644
index 0000000..dddc800
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/Service.java
@@ -0,0 +1,250 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.util.Dictionary;
+import java.util.List;
+
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Service interface.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface Service {
+    /**
+     * Adds a new dependency to this service.
+     * 
+     * @param dependency the dependency to add
+     * @return this service
+     */
+    public Service add(Dependency dependency);
+    
+    /**
+     * Removes a dependency from this service.
+     * 
+     * @param dependency the dependency to remove
+     * @return this service
+     */
+    public Service remove(Dependency dependency);
+
+    /**
+     * Sets the public interface under which this service should be registered
+     * in the OSGi service registry.
+     *  
+     * @param serviceName the name of the service interface
+     * @param properties the properties for this service
+     * @return this service
+     */
+    public Service setInterface(String serviceName, Dictionary properties);
+    
+    /**
+     * Sets the public interfaces under which this service should be registered
+     * in the OSGi service registry.
+     *  
+     * @param serviceNames the names of the service interface
+     * @param properties the properties for this service
+     * @return this service
+     */
+    public Service setInterface(String[] serviceNames, Dictionary properties);
+    
+    /**
+     * Sets the implementation for this service. You can actually specify
+     * an instance you have instantiated manually, or a <code>Class</code>
+     * that will be instantiated using its default constructor when the
+     * required dependencies are resolved (effectively giving you a lazy
+     * instantiation mechanism).
+     * 
+     * There are four special methods that are called when found through
+     * reflection to give you some life-cycle management options:
+     * <ol>
+     * <li><code>init()</code> is invoked right after the instance has been
+     * created, and before any dependencies are resolved, and can be used to
+     * initialize the internal state of the instance</li>
+     * <li><code>start()</code> is invoked after the required dependencies
+     * are resolved and injected, and before the service is registered</li>
+     * <li><code>stop()</code> is invoked right after the service is
+     * unregistered</li>
+     * <li><code>destroy()</code> is invoked after all dependencies are
+     * removed</li>
+     * </ol>
+     * In short, this allows you to initialize your instance before it is
+     * registered, perform some post-initialization and pre-destruction code
+     * as well as final cleanup. If a method is not defined, it simply is not
+     * called, so you can decide which one(s) you need. If you need even more
+     * fine-grained control, you can register as a service state listener too.
+     * 
+     * @param implementation the implementation
+     * @return this service
+     * @see ServiceStateListener
+     */
+    public Service setImplementation(Object implementation);
+    
+    /**
+     * Returns a list of dependencies.
+     * 
+     * @return a list of dependencies
+     */
+    public List getDependencies();
+    
+    /**
+     * Returns the service registration for this service. The method
+     * will return <code>null</code> if no service registration is
+     * available.
+     * 
+     * @return the service registration
+     */
+    public ServiceRegistration getServiceRegistration();
+    
+    /**
+     * Returns the service instance for this service. The method will
+     * return <code>null</code> if no service instance is available.
+     * 
+     * @return the service instance
+     */
+    public Object getService();
+
+    /**
+     * Returns the service properties associated with the service.
+     * 
+     * @return the properties or <code>null</code> if there are none
+     */
+    public Dictionary getServiceProperties();
+    
+    /**
+     * Sets the service properties associated with the service. If the service
+     * was already registered, it will be updated.
+     * 
+     * @param serviceProperties the properties
+     */
+    public void setServiceProperties(Dictionary serviceProperties);
+    
+    /**
+     * Sets the names of the methods used as callbacks. These methods, when found, are
+     * invoked as part of the life-cycle management of the service implementation. The
+     * methods should not have any parameters.
+     * 
+     * @param init the name of the init method
+     * @param start the name of the start method
+     * @param stop the name of the stop method
+     * @param destroy the name of the destroy method
+     * @return the service instance
+     */
+    public Service setCallbacks(String init, String start, String stop, String destroy);
+
+    // listener
+    /**
+     * Adds a service state listener to this service.
+     * 
+     * @param listener the state listener
+     */
+    public void addStateListener(ServiceStateListener listener);
+
+    /**
+     * Removes a service state listener from this service.
+     * 
+     * @param listener the state listener
+     */
+    public void removeStateListener(ServiceStateListener listener);
+    
+    // events, must be fired when the dependency is started/active
+    
+    /**
+     * Will be called when the dependency becomes available.
+     * 
+     * @param dependency the dependency
+     */
+    public void dependencyAvailable(Dependency dependency);
+    
+    /**
+     * Will be called when the dependency changes.
+     * 
+     * @param dependency the dependency
+     */
+    public void dependencyUnavailable(Dependency dependency);
+    
+    /**
+     * Will be called when the dependency becomes unavailable.
+     * 
+     * @param dependency the dependency
+     */
+    public void dependencyChanged(Dependency dependency);
+
+    /**
+     * Starts the service. This activates the dependency tracking mechanism
+     * for this service.
+     */
+    public void start();
+    
+    /**
+     * Stops the service. This deactivates the dependency tracking mechanism
+     * for this service.
+     */
+    public void stop();
+    
+    /**
+     * Sets the factory to use to create the implementation. You can specify
+     * both the factory class and method to invoke. The method should return
+     * the implementation, and can use any method to create it. Actually, this
+     * can be used together with <code>setComposition</code> to create a
+     * composition of instances that work together to implement a service. The
+     * factory itself can also be instantiated lazily by not specifying an
+     * instance, but a <code>Class</code>.
+     * 
+     * @param factory the factory instance or class
+     * @param createMethod the name of the create method
+     */
+	public Service setFactory(Object factory, String createMethod);
+	
+	/**
+	 * Sets the factory to use to create the implementation. You specify the
+	 * method to invoke. The method should return the implementation, and can
+	 * use any method to create it. Actually, this can be used together with
+	 * <code>setComposition</code> to create a composition of instances that
+	 * work together to implement a service.
+	 * <p>
+	 * Note that currently, there is no default for the factory, so please use
+	 * <code>setFactory(factory, createMethod)</code> instead.
+	 * 
+	 * @param createMethod the name of the create method
+	 */
+	public Service setFactory(String createMethod);
+	
+	/**
+	 * Sets the instance and method to invoke to get back all instances that
+	 * are part of a composition and need dependencies injected. All of them
+	 * will be searched for any of the dependencies. The method that is
+	 * invoked must return an <code>Object[]</code>.
+	 * 
+	 * @param instance the instance that has the method
+	 * @param getMethod the method to invoke
+	 */
+	public Service setComposition(Object instance, String getMethod);
+	
+	/**
+	 * Sets the method to invoke on the service implementation to get back all
+	 * instances that are part of a composition and need dependencies injected.
+	 * All of them will be searched for any of the dependencies. The method that
+	 * is invoked must return an <code>Object[]</code>.
+	 * 
+	 * @param getMethod the method to invoke
+	 */
+	public Service setComposition(String getMethod);
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceComponent.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceComponent.java
new file mode 100644
index 0000000..2d70ea7
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceComponent.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+/**
+ * Describes a service component. Service components form descriptions of services
+ * that are managed by the dependency manager. They can be used to query their state
+ * for monitoring tools. The dependency manager shell command is an example of
+ * such a tool.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ServiceComponent {
+    /** Names for the states of this component. */
+    public static final String[] STATE_NAMES = { "unregistered", "registered" };
+    /** State constant for an unregistered component. */
+    public static final int STATE_UNREGISTERED = 0;
+    /** State constant for a registered component. */
+    public static final int STATE_REGISTERED = 1;
+    /** Returns a list of dependencies associated with this service component. */
+    public ServiceComponentDependency[] getComponentDependencies();
+    /** Returns the name of this service component. */
+    public String getName();
+    /** Returns the state of this service component. */
+    public int getState();
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceComponentDependency.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceComponentDependency.java
new file mode 100644
index 0000000..53c13ac
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceComponentDependency.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+/**
+ * Describes a service component dependency. They form descriptions of dependencies
+ * that are managed by the dependency manager. They can be used to query their state
+ * for monitoring tools. The dependency manager shell command is an example of
+ * such a tool.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ServiceComponentDependency {
+    /** Names for the states of this dependency. */
+    public static final String[] STATE_NAMES = { 
+        "optional unavailable", 
+        "optional available", 
+        "required unavailable", 
+        "required available" 
+        };
+    /** State constant for an unavailable, optional dependency. */
+    public static final int STATE_UNAVAILABLE_OPTIONAL = 0;
+    /** State constant for an available, optional dependency. */
+    public static final int STATE_AVAILABLE_OPTIONAL = 1;
+    /** State constant for an unavailable, required dependency. */
+    public static final int STATE_UNAVAILABLE_REQUIRED = 2;
+    /** State constant for an available, required dependency. */
+    public static final int STATE_AVAILABLE_REQUIRED = 3;
+    /** Returns the name of this dependency. */
+    public String getName();
+    /** Returns the name of the type of this dependency. */
+    public String getType();
+    /** Returns the state of this dependency. */
+    public int getState();
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceDependency.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceDependency.java
new file mode 100644
index 0000000..195fa12
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceDependency.java
@@ -0,0 +1,720 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Service dependency that can track an OSGi service.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceDependency implements Dependency, ServiceTrackerCustomizer, ServiceComponentDependency {
+    private boolean m_isRequired;
+    private Service m_service;
+    private volatile ServiceTracker m_tracker;
+    private BundleContext m_context;
+    private boolean m_isAvailable;
+    private volatile Class m_trackedServiceName;
+    private Object m_nullObject;
+    private volatile String m_trackedServiceFilter;
+    private volatile String m_trackedServiceFilterUnmodified;
+    private volatile ServiceReference m_trackedServiceReference;
+    private volatile boolean m_isStarted;
+    private Object m_callbackInstance;
+    private String m_callbackAdded;
+    private String m_callbackChanged;
+    private String m_callbackRemoved;
+    private boolean m_autoConfig;
+    private ServiceReference m_reference;
+    private Object m_serviceInstance;
+    private final Logger m_logger;
+    private String m_autoConfigInstance;
+    private boolean m_autoConfigInvoked;
+    private Object m_defaultImplementation;
+    private Object m_defaultImplementationInstance;
+    
+    private static final Comparator COMPARATOR = new Comparator() {
+        public int getRank(ServiceReference ref) {
+            Object ranking = ref.getProperty(Constants.SERVICE_RANKING);
+            if (ranking != null && (ranking instanceof Integer)) {
+                return ((Integer) ranking).intValue();
+            }
+            return 0;
+        }
+
+        public int compare(Object a, Object b) {
+            ServiceReference ra = (ServiceReference) a, rb = (ServiceReference) b;
+            int ranka = getRank(ra);
+            int rankb = getRank(rb);
+            if (ranka < rankb) {
+                return -1;
+            }
+            else if (ranka > rankb) {
+                return 1;
+            }
+            return 0;
+        }
+    };
+    
+    /**
+     * Entry to wrap service properties behind a Map.
+     */
+    private final static class ServicePropertiesMapEntry implements Map.Entry {
+        private final String m_key;
+        private Object m_value;
+
+        public ServicePropertiesMapEntry(String key, Object value) {
+            m_key = key;
+            m_value = value;
+        }
+
+        public Object getKey() {
+            return m_key;
+        }
+
+        public Object getValue() {
+            return m_value;
+        }
+
+        public String toString() {
+            return m_key + "=" + m_value;
+        }
+
+        public Object setValue(Object value) {
+            Object oldValue = m_value;
+            m_value = value;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry)) {
+                return false;
+            }
+            Map.Entry e = (Map.Entry) o;
+            return eq(m_key, e.getKey()) && eq(m_value, e.getValue());
+        }
+
+        public int hashCode() {
+            return ((m_key == null) ? 0 : m_key.hashCode()) ^ ((m_value == null) ? 0 : m_value.hashCode());
+        }
+
+        private static final boolean eq(Object o1, Object o2) {
+            return (o1 == null ? o2 == null : o1.equals(o2));
+        }
+    }
+
+    /**
+     * Wraps service properties behind a Map.
+     */
+    private final static class ServicePropertiesMap extends AbstractMap {
+        private final ServiceReference m_ref;
+
+        public ServicePropertiesMap(ServiceReference ref) {
+            m_ref = ref;
+        }
+
+        public Object get(Object key) {
+            return m_ref.getProperty(key.toString());
+        }
+
+        public int size() {
+            return m_ref.getPropertyKeys().length;
+        }
+
+        public Set entrySet() {
+            Set set = new HashSet();
+            String[] keys = m_ref.getPropertyKeys();
+            for (int i = 0; i < keys.length; i++) {
+                set.add(new ServicePropertiesMapEntry(keys[i], m_ref.getProperty(keys[i])));
+            }
+            return set;
+        }
+    }
+        
+    /**
+     * Creates a new service dependency.
+     * 
+     * @param context the bundle context
+     * @param logger the logger
+     */
+    public ServiceDependency(BundleContext context, Logger logger) {
+        m_context = context;
+        m_logger = logger;
+        m_autoConfig = true;
+    }
+
+    public synchronized boolean isRequired() {
+        return m_isRequired;
+    }
+
+    public synchronized boolean isAvailable() {
+        return m_isAvailable;
+    }
+    
+    public synchronized boolean isAutoConfig() {
+        return m_autoConfig;
+    }
+
+    public synchronized Object getService() {
+        Object service = null;
+        if (m_isStarted) {
+            service = m_tracker.getService();
+        }
+        if (service == null) {
+            service = getDefaultImplementation();
+            if (service == null) {
+                service = getNullObject();
+            }
+        }
+        return service;
+    }
+
+    public Object lookupService() {
+        Object service = null;
+        if (m_isStarted) {
+            service = m_tracker.getService();
+        }
+        else {
+            ServiceReference[] refs = null;
+            ServiceReference ref = null;
+            if (m_trackedServiceName != null) {
+                if (m_trackedServiceFilter != null) {
+                    try {
+                        refs = m_context.getServiceReferences(m_trackedServiceName.getName(), m_trackedServiceFilter);
+                        if (refs != null) {
+                            Arrays.sort(refs, COMPARATOR);
+                            ref = refs[0];
+                        }
+                    }
+                    catch (InvalidSyntaxException e) {
+                        throw new IllegalStateException("Invalid filter definition for dependency.");
+                    }
+                }
+                else if (m_trackedServiceReference != null) {
+                    ref = m_trackedServiceReference;
+                }
+                else {
+                    ref = m_context.getServiceReference(m_trackedServiceName.getName());
+                }
+                if (ref != null) {
+                    service = m_context.getService(ref);
+                }
+            }
+            else {
+                throw new IllegalStateException("Could not lookup dependency, no service name specified.");
+            }
+        }
+        if (service == null) {
+            service = getDefaultImplementation();
+            if (service == null) {
+                service = getNullObject();
+            }
+        }
+        return service;
+    }
+
+    private Object getNullObject() {
+        if (m_nullObject == null) {
+            Class trackedServiceName;
+            synchronized (this) {
+                trackedServiceName = m_trackedServiceName;
+            }
+            try {
+                m_nullObject = Proxy.newProxyInstance(trackedServiceName.getClassLoader(), new Class[] {trackedServiceName}, new DefaultNullObject()); 
+            }
+            catch (Exception e) {
+                m_logger.log(Logger.LOG_ERROR, "Could not create null object for " + trackedServiceName + ".", e);
+            }
+        }
+        return m_nullObject;
+    }
+    
+    private Object getDefaultImplementation() {
+        if (m_defaultImplementation != null) {
+            if (m_defaultImplementation instanceof Class) {
+                try {
+                    m_defaultImplementationInstance = ((Class) m_defaultImplementation).newInstance();
+                }
+                catch (Exception e) {
+                    m_logger.log(Logger.LOG_ERROR, "Could not create default implementation instance of class " + m_defaultImplementation + ".", e);
+                }
+            }
+            else {
+                m_defaultImplementationInstance = m_defaultImplementation;
+            }
+        }
+        return m_defaultImplementationInstance;
+    }
+    
+    public synchronized Class getInterface() {
+        return m_trackedServiceName;
+    }
+
+    public void start(Service service) {
+        synchronized (this) {
+            if (m_isStarted) {
+                throw new IllegalStateException("Service dependency was already started." + m_trackedServiceName);
+            }
+            m_service = service;
+            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.");
+                    }
+                }
+                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);
+                }
+            }
+            else {
+                throw new IllegalStateException("Could not create tracker for dependency, no service name specified.");
+            }
+            m_isStarted = true;
+        }
+        m_tracker.open();
+    }
+
+    public void stop(Service service) {
+        synchronized (this) {
+            if (!m_isStarted) {
+                throw new IllegalStateException("Service dependency was not started.");
+            }
+            m_isStarted = false;
+        }
+        m_tracker.close();
+        m_tracker = null;
+    }
+
+    public Object addingService(ServiceReference ref) {
+        Object service = m_context.getService(ref);
+        // first check to make sure the service is actually an instance of our service
+        if (!m_trackedServiceName.isInstance(service)) {
+            return null;
+        }
+            
+        // we remember these for future reference, needed for required service callbacks
+        m_reference = ref;
+        m_serviceInstance = service;
+        return service;
+    }
+
+    public void addedService(ServiceReference ref, Object service) {
+        if (makeAvailable()) {
+            m_service.dependencyAvailable(this);
+            // try to invoke callback, if specified, but only for optional dependencies
+            // because callbacks for required dependencies are handled differently
+            if (!isRequired()) {
+                invokeAdded(ref, service);
+            }
+        }
+        else {
+            m_service.dependencyChanged(this);
+            invokeAdded(ref, service);
+        }
+    }
+
+    public void invokeAdded() {
+        invokeAdded(m_reference, m_serviceInstance);
+    }
+    
+    public void invokeAdded(ServiceReference reference, Object serviceInstance) {
+        Object[] callbackInstances = getCallbackInstances();
+        if ((callbackInstances != null) && (m_callbackAdded != null)) {
+            invokeCallbackMethod(callbackInstances, m_callbackAdded, reference, serviceInstance);
+        }
+    }
+
+    public void modifiedService(ServiceReference ref, Object service) {
+        m_reference = ref;
+        m_serviceInstance = service;
+        m_service.dependencyChanged(this);
+        // only invoke the changed callback if the service itself is "active"
+        if (((ServiceImpl) m_service).isRegistered()) {
+            invokeChanged(ref, service);
+        }
+    }
+
+    public void invokeChanged(ServiceReference reference, Object serviceInstance) {
+        Object[] callbackInstances = getCallbackInstances();
+        if ((callbackInstances != null) && (m_callbackChanged != null)) {
+            invokeCallbackMethod(callbackInstances, m_callbackChanged, reference, serviceInstance);
+        }
+    }
+
+    public void removedService(ServiceReference ref, Object service) {
+        if (makeUnavailable()) {
+            m_service.dependencyUnavailable(this);
+            // try to invoke callback, if specified, but only for optional dependencies
+            // because callbacks for required dependencies are handled differently
+            if (!isRequired()) {
+                invokeRemoved(ref, service);
+            }
+        }
+        else {
+            m_service.dependencyChanged(this);
+            invokeRemoved(ref, service);
+        }
+        
+        // unget what we got in addingService (see ServiceTracker 701.4.1)
+        m_context.ungetService(ref);
+    }
+
+    public void invokeRemoved() {
+        invokeRemoved(m_reference, m_serviceInstance);
+    }
+    
+    public void invokeRemoved(ServiceReference reference, Object serviceInstance) {
+        Object[] callbackInstances = getCallbackInstances();
+        if ((callbackInstances != null) && (m_callbackRemoved != null)) {
+            invokeCallbackMethod(callbackInstances, m_callbackRemoved, reference, serviceInstance);
+        }
+    }
+    
+    private synchronized boolean makeAvailable() {
+        if (!m_isAvailable) {
+            m_isAvailable = true;
+            return true;
+        }
+        return false;
+    }
+    
+    private synchronized boolean makeUnavailable() {
+        if ((m_isAvailable) && (m_tracker.getServiceReference() == null)) {
+            m_isAvailable = false;
+            return true;
+        }
+        return false;
+    }
+    
+    private synchronized Object[] getCallbackInstances() {
+        return m_callbackInstance != null ? new Object[] { m_callbackInstance } : ((ServiceImpl) m_service).getCompositionInstances();
+    }
+
+    private void invokeCallbackMethod(Object[] instances, String methodName, ServiceReference reference, Object service) {
+        for (int i = 0; i < instances.length; i++) {
+            try {
+                invokeCallbackMethod(instances[i], methodName, reference, service);
+            }
+            catch (NoSuchMethodException e) {
+                m_logger.log(Logger.LOG_DEBUG, "Method '" + methodName + "' does not exist on " + instances[i] + ". Callback skipped.");
+            }
+        }
+    }
+
+    private void invokeCallbackMethod(Object instance, String methodName, ServiceReference reference, Object service) throws NoSuchMethodException {
+        Class currentClazz = instance.getClass();
+        boolean done = false;
+        while (!done && currentClazz != null) {
+            Class trackedServiceName;
+            synchronized (this) {
+                trackedServiceName = m_trackedServiceName;
+            }
+            done = invokeMethod(instance, currentClazz, methodName,
+                new Class[][] {{ServiceReference.class, trackedServiceName}, {ServiceReference.class, Object.class}, {ServiceReference.class}, {trackedServiceName}, {Object.class}, {}, {Map.class, trackedServiceName}},
+                new Object[][] {{reference, service}, {reference, service}, {reference}, {service}, {service}, {}, {new ServicePropertiesMap(reference), service}},
+                false);
+            if (!done) {
+                currentClazz = currentClazz.getSuperclass();
+            }
+        }
+        if (!done && currentClazz == null) {
+            throw new NoSuchMethodException(methodName);
+        }
+    }
+
+    private boolean invokeMethod(Object object, Class clazz, String name, Class[][] signatures, Object[][] parameters, boolean isSuper) {
+        Method m = null;
+        for (int i = 0; i < signatures.length; i++) {
+            Class[] signature = signatures[i];
+            try {
+                m = clazz.getDeclaredMethod(name, signature);
+                if (!(isSuper && Modifier.isPrivate(m.getModifiers()))) {
+                    m.setAccessible(true);
+                    try {
+                        m.invoke(object, parameters[i]);
+                    }
+                    catch (InvocationTargetException e) {
+                        m_logger.log(Logger.LOG_ERROR, "Exception while invoking method " + m + ".", e);
+                    }
+                    // we did find and invoke the method, so we return true
+                    return true;
+                }
+            }
+            catch (NoSuchMethodException e) {
+                // ignore this and keep looking
+            }
+            catch (Exception e) {
+                // could not even try to invoke the method
+                m_logger.log(Logger.LOG_ERROR, "Exception while trying to invoke method " + m + ".", e);
+            }
+        }
+        return false;
+    }
+    
+    // ----- CREATION
+
+    /**
+     * Sets the name of the service that should be tracked. 
+     * 
+     * @param serviceName the name of the service
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setService(Class serviceName) {
+        ensureNotActive();
+        if (serviceName == null) {
+            throw new IllegalArgumentException("Service name cannot be null.");
+        }
+        m_trackedServiceName = serviceName;
+        m_trackedServiceReference = null;
+        m_trackedServiceFilter = null;
+        return this;
+    }
+    
+    /**
+     * Sets the name of the service that should be tracked. You can either specify
+     * only the name, or the name and a filter. In the latter case, the filter is used
+     * to track the service and should only return services of the type that was specified
+     * in the name. To make sure of this, the filter is actually extended internally to
+     * filter on the correct name.
+     * 
+     * @param serviceName the name of the service
+     * @param serviceFilter the filter condition
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setService(Class serviceName, String serviceFilter) {
+        ensureNotActive();
+        if (serviceName == null) {
+            throw new IllegalArgumentException("Service name cannot be null.");
+        }
+        m_trackedServiceName = serviceName;
+        if (serviceFilter != null) {
+            m_trackedServiceFilterUnmodified = serviceFilter;
+            m_trackedServiceFilter ="(&(" + Constants.OBJECTCLASS + "=" + serviceName.getName() + ")" + serviceFilter + ")";
+        }
+        else {
+            m_trackedServiceFilterUnmodified = null;
+            m_trackedServiceFilter = null;
+        }
+        m_trackedServiceReference = null;
+        return this;
+    }
+
+    /**
+     * Sets the name of the service that should be tracked. You can either specify
+     * only the name, or the name and a reference. In the latter case, the service reference
+     * is used to track the service and should only return services of the type that was 
+     * specified in the name.
+     * 
+     * @param serviceName the name of the service
+     * @param serviceReference the service reference to track
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setService(Class serviceName, ServiceReference serviceReference) {
+        ensureNotActive();
+        if (serviceName == null) {
+            throw new IllegalArgumentException("Service name cannot be null.");
+        }
+        m_trackedServiceName = serviceName;
+        m_trackedServiceReference = serviceReference;
+        m_trackedServiceFilterUnmodified = null;
+        m_trackedServiceFilter = null;
+        return this;
+    }
+    
+    /**
+     * Sets the default implementation for this service dependency. You can use this to supply
+     * your own implementation that will be used instead of a Null Object when the dependency is
+     * not available. This is also convenient if the service dependency is not an interface
+     * (which would cause the Null Object creation to fail) but a class.
+     * 
+     * @param implementation the instance to use or the class to instantiate if you want to lazily
+     *     instantiate this implementation
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setDefaultImplementation(Object implementation) {
+        ensureNotActive();
+        m_defaultImplementation = implementation;
+        return this;
+    }
+
+    /**
+     * Sets the required flag which determines if this service is required or not.
+     * 
+     * @param required the required flag
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setRequired(boolean required) {
+        ensureNotActive();
+        m_isRequired = required;
+        return this;
+    }
+
+    /**
+     * Sets auto configuration for this service. Auto configuration allows the
+     * dependency to fill in any attributes in the service implementation that
+     * are of the same type as this dependency. Default is on.
+     * 
+     * @param autoConfig the value of auto config
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setAutoConfig(boolean autoConfig) {
+        ensureNotActive();
+        m_autoConfig = autoConfig;
+        m_autoConfigInvoked = true;
+        return this;
+    }
+    
+    /**
+     * Sets auto configuration for this service. Auto configuration allows the
+     * dependency to fill in the attribute in the service implementation that
+     * has the same type and instance name.
+     * 
+     * @param instanceName the name of attribute to auto config
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setAutoConfig(String instanceName) {
+        ensureNotActive();
+        m_autoConfig = (instanceName != null);
+        m_autoConfigInstance = instanceName;
+        m_autoConfigInvoked = true;
+        return this;
+    }
+    
+    /**
+     * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
+     * dependency is added or removed. When you specify callbacks, the auto configuration 
+     * feature is automatically turned off, because we're assuming you don't need it in this 
+     * case.
+     * 
+     * @param added the method to call when a service was added
+     * @param removed the method to call when a service was removed
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setCallbacks(String added, String removed) {
+        return setCallbacks(null, added, null, removed);
+    }
+
+    /**
+     * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
+     * dependency is added, changed or removed. When you specify callbacks, the auto 
+     * configuration feature is automatically turned off, because we're assuming you don't 
+     * need it in this case.
+     * 
+     * @param added the method to call when a service was added
+     * @param changed the method to call when a service was changed
+     * @param removed the method to call when a service was removed
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setCallbacks(String added, String changed, String removed) {
+        return setCallbacks(null, added, changed, removed);
+    }
+
+    /**
+     * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
+     * dependency is added or removed. They are called on the instance you provide. When you
+     * specify callbacks, the auto configuration feature is automatically turned off, because
+     * we're assuming you don't need it in this case.
+     * 
+     * @param instance the instance to call the callbacks on
+     * @param added the method to call when a service was added
+     * @param removed the method to call when a service was removed
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setCallbacks(Object instance, String added, String removed) {
+        return setCallbacks(instance, added, null, removed);
+    }
+    
+    /**
+     * Sets the callbacks for this service. These callbacks can be used as hooks whenever a
+     * dependency is added, changed or removed. They are called on the instance you provide. When you
+     * specify callbacks, the auto configuration feature is automatically turned off, because
+     * we're assuming you don't need it in this case.
+     * 
+     * @param instance the instance to call the callbacks on
+     * @param added the method to call when a service was added
+     * @param changed the method to call when a service was changed
+     * @param removed the method to call when a service was removed
+     * @return this service dependency
+     */
+    public synchronized ServiceDependency setCallbacks(Object instance, String added, String changed, String removed) {
+        ensureNotActive();
+        // if at least one valid callback is specified, we turn off auto configuration, unless
+        // someone already explicitly invoked autoConfig
+        if ((added != null || removed != null || changed != null) && ! m_autoConfigInvoked) {
+            setAutoConfig(false);
+        }
+        m_callbackInstance = instance;
+        m_callbackAdded = added;
+        m_callbackChanged = changed;
+        m_callbackRemoved = removed;
+        return this;
+    }
+    
+    private void ensureNotActive() {
+        if (m_tracker != null) {
+            throw new IllegalStateException("Cannot modify state while active.");
+        }
+    }
+    
+    public synchronized String toString() {
+        return "ServiceDependency[" + m_trackedServiceName + " " + m_trackedServiceFilterUnmodified + "]";
+    }
+
+    public String getAutoConfigName() {
+        return m_autoConfigInstance;
+    }
+
+    public String getName() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(m_trackedServiceName.getName());
+        if (m_trackedServiceFilterUnmodified != null) {
+            sb.append(m_trackedServiceFilterUnmodified);
+        }
+        return sb.toString();
+    }
+
+    public int getState() {
+        return (isAvailable() ? 1 : 0) + (isRequired() ? 2 : 0);
+    }
+
+    public String getType() {
+        return "service";
+    }
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java
new file mode 100644
index 0000000..f5f4c90
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceImpl.java
@@ -0,0 +1,921 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Service implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceImpl implements Service, ServiceComponent {
+    private static final Class[] VOID = new Class[] {};
+	private static final ServiceRegistration NULL_REGISTRATION;
+    private static final ServiceStateListener[] SERVICE_STATE_LISTENER_TYPE = new ServiceStateListener[] {};
+
+    private final BundleContext m_context;
+    private final DependencyManager m_manager;
+
+    // configuration (static)
+    private String m_callbackInit;
+    private String m_callbackStart;
+    private String m_callbackStop;
+    private String m_callbackDestroy;
+    private Object m_serviceName;
+    private Object m_implementation;
+
+    // configuration (dynamic, but does not affect state)
+    private Dictionary m_serviceProperties;
+
+    // configuration (dynamic, and affects state)
+    private ArrayList m_dependencies = new ArrayList();
+
+    // runtime state (calculated from dependencies)
+    private State m_state;
+
+    // runtime state (changes because of state changes)
+    private Object m_serviceInstance;
+    private ServiceRegistration m_registration;
+
+    // service state listeners
+    private final List m_stateListeners = new ArrayList();
+
+    // work queue
+    private final SerialExecutor m_executor = new SerialExecutor();
+
+    // instance factory
+	private Object m_instanceFactory;
+	private String m_instanceFactoryCreateMethod;
+
+	// composition manager
+	private Object m_compositionManager;
+	private String m_compositionManagerGetMethod;
+	private Object m_compositionManagerInstance;
+	
+	// internal logging
+    private final Logger m_logger;
+    private ServiceRegistration m_serviceRegistration;
+    private Map m_autoConfig = new HashMap();
+    private Map m_autoConfigInstance = new HashMap();
+
+    public ServiceImpl(BundleContext context, DependencyManager manager, Logger logger) {
+    	m_logger = logger;
+        m_state = new State((List) m_dependencies.clone(), false);
+        m_context = context;
+        m_manager = manager;
+        m_callbackInit = "init";
+        m_callbackStart = "start";
+        m_callbackStop = "stop";
+        m_callbackDestroy = "destroy";
+        m_implementation = null;
+        m_autoConfig.put(BundleContext.class, Boolean.TRUE);
+        m_autoConfig.put(ServiceRegistration.class, Boolean.TRUE);
+        m_autoConfig.put(DependencyManager.class, Boolean.TRUE);
+    }
+
+    private void calculateStateChanges(final State oldState, final State newState) {
+    	if (oldState.isWaitingForRequired() && newState.isTrackingOptional()) {
+        	m_executor.enqueue(new Runnable() {
+				public void run() {
+					activateService(newState);
+				}});
+    	}
+    	if (oldState.isTrackingOptional() && newState.isWaitingForRequired()) {
+    		m_executor.enqueue(new Runnable() {
+				public void run() {
+					deactivateService(oldState);
+				}});
+    	}
+    	if (oldState.isInactive() && (newState.isTrackingOptional())) {
+    		m_executor.enqueue(new Runnable() {
+				public void run() {
+					activateService(newState);
+				}});
+    	}
+    	if (oldState.isInactive() && (newState.isWaitingForRequired())) {
+    		m_executor.enqueue(new Runnable() {
+				public void run() {
+					startTrackingRequired(newState);
+				}});
+    	}
+    	if ((oldState.isWaitingForRequired()) && newState.isInactive()) {
+    		m_executor.enqueue(new Runnable() {
+				public void run() {
+					stopTrackingRequired(oldState);
+				}});
+    	}
+    	if ((oldState.isTrackingOptional()) && newState.isInactive()) {
+    		m_executor.enqueue(new Runnable() {
+				public void run() {
+					deactivateService(oldState);
+					stopTrackingRequired(oldState);
+				}});
+    	}
+    	m_executor.execute();
+    }
+
+    public Service add(final Dependency dependency) {
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            m_dependencies.add(dependency);
+        }
+        if (oldState.isTrackingOptional() || (oldState.isWaitingForRequired() && dependency.isRequired())) {
+        	dependency.start(this);
+        }
+        synchronized (m_dependencies) {
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive());
+            m_state = newState;
+            calculateStateChanges(oldState, newState);
+        }
+        return this;
+    }
+
+    public Service remove(Dependency dependency) {
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            m_dependencies.remove(dependency);
+        }
+        if (oldState.isTrackingOptional() || (oldState.isWaitingForRequired() && dependency.isRequired())) {
+        	dependency.stop(this);
+        }
+        synchronized (m_dependencies) {
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive());
+            m_state = newState;
+        }
+        calculateStateChanges(oldState, newState);
+        return this;
+    }
+
+    public List getDependencies() {
+        synchronized (m_dependencies) {
+            return (List) m_dependencies.clone();
+        }
+    }
+
+    public ServiceRegistration getServiceRegistration() {
+        return m_registration;
+    }
+
+    public Object getService() {
+        return m_serviceInstance;
+    }
+
+    public void dependencyAvailable(final Dependency dependency) {
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive());
+            m_state = newState;
+        }
+        calculateStateChanges(oldState, newState);
+        if (newState.isTrackingOptional()) {
+        	m_executor.enqueue(new Runnable() {
+        		public void run() {
+        			updateInstance(dependency);
+        		}
+        	});
+        	m_executor.execute();
+        }
+    }
+
+    public void dependencyChanged(final Dependency dependency) {
+    	State state;
+        synchronized (m_dependencies) {
+        	state = m_state;
+        }
+        if (state.isTrackingOptional()) {
+        	m_executor.enqueue(new Runnable() {
+        		public void run() {
+        			updateInstance(dependency);
+        		}
+        	});
+        	m_executor.execute();
+        }
+    }
+
+    public void dependencyUnavailable(final Dependency dependency) {
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive());
+            m_state = newState;
+        }
+        calculateStateChanges(oldState, newState);
+        if (newState.isTrackingOptional()) {
+        	m_executor.enqueue(new Runnable() {
+        		public void run() {
+        			updateInstance(dependency);
+        		}
+        	});
+        	m_executor.execute();
+        }
+    }
+
+    public synchronized void start() {
+        m_serviceRegistration = m_context.registerService(ServiceComponent.class.getName(), this, null);
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            newState = new State((List) m_dependencies.clone(), true);
+            m_state = newState;
+        }
+        calculateStateChanges(oldState, newState);
+    }
+
+    public synchronized void stop() {
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            newState = new State((List) m_dependencies.clone(), false);
+            m_state = newState;
+        }
+        calculateStateChanges(oldState, newState);
+        m_serviceRegistration.unregister();
+    }
+
+    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;
+	    return this;
+	}
+
+	public synchronized Service setFactory(Object factory, String createMethod) {
+	    ensureNotActive();
+		m_instanceFactory = factory;
+		m_instanceFactoryCreateMethod = createMethod;
+		return this;
+	}
+
+	public synchronized Service setFactory(String createMethod) {
+		return setFactory(null, createMethod);
+	}
+
+	public synchronized Service setComposition(Object instance, String getMethod) {
+	    ensureNotActive();
+		m_compositionManager = instance;
+		m_compositionManagerGetMethod = getMethod;
+		return this;
+	}
+
+	public synchronized Service setComposition(String getMethod) {
+		return setComposition(null, getMethod);
+	}
+
+	public String toString() {
+	    return "ServiceImpl[" + m_serviceName + " " + m_implementation + "]";
+	}
+
+	public synchronized Dictionary getServiceProperties() {
+	    if (m_serviceProperties != null) {
+	        return (Dictionary) ((Hashtable) m_serviceProperties).clone();
+	    }
+	    return null;
+	}
+
+	public synchronized void setServiceProperties(Dictionary serviceProperties) {
+	    m_serviceProperties = serviceProperties;
+	    if (isRegistered() && (m_serviceName != null)) {
+	        m_registration.setProperties(calculateServiceProperties());
+	    }
+	}
+
+	// service state listener methods
+	public void addStateListener(ServiceStateListener listener) {
+    	synchronized (m_stateListeners) {
+		    m_stateListeners.add(listener);
+    	}
+    	// when we register as a listener and the service is already started
+    	// make sure we invoke the right callbacks so the listener knows
+    	State state;
+    	synchronized (m_dependencies) {
+    		state = m_state;
+    	}
+    	if (state.isTrackingOptional()) {
+    		listener.starting(this);
+    		listener.started(this);
+    	}
+	}
+
+	public void removeStateListener(ServiceStateListener listener) {
+    	synchronized (m_stateListeners) {
+    		m_stateListeners.remove(listener);
+    	}
+	}
+
+	void removeStateListeners() {
+    	synchronized (m_stateListeners) {
+    		m_stateListeners.clear();
+    	}
+	}
+
+	private void stateListenersStarting() {
+		ServiceStateListener[] list = getListeners();
+		for (int i = 0; i < list.length; i++) {
+		    try {
+		        list[i].starting(this);
+		    }
+		    catch (Throwable t) {
+		        m_logger.log(Logger.LOG_ERROR, "Error invoking listener starting method.", t);
+		    }
+		}
+	}
+
+	private void stateListenersStarted() {
+        ServiceStateListener[] list = getListeners();
+        for (int i = 0; i < list.length; i++) {
+            try {
+                list[i].started(this);
+            }
+            catch (Throwable t) {
+                m_logger.log(Logger.LOG_ERROR, "Error invoking listener started method.", t);
+            }
+        }
+    }
+
+    private void stateListenersStopping() {
+        ServiceStateListener[] list = getListeners();
+        for (int i = 0; i < list.length; i++) {
+            try {
+                list[i].stopping(this);
+            }
+            catch (Throwable t) {
+                m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopping method.", t);
+            }
+        }
+    }
+
+    private void stateListenersStopped() {
+        ServiceStateListener[] list = getListeners();
+        for (int i = 0; i < list.length; i++) {
+            try {
+                list[i].stopped(this);
+            }
+            catch (Throwable t) {
+                m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopped method.", t);
+            }
+        }
+    }
+
+	private ServiceStateListener[] getListeners() {
+		synchronized (m_stateListeners) {
+			return (ServiceStateListener[]) m_stateListeners.toArray(SERVICE_STATE_LISTENER_TYPE);
+		}
+	}
+
+	private void activateService(State state) {
+		String init, start;
+		synchronized (this) {
+			init = m_callbackInit;
+			start = m_callbackStart;
+		}
+        // service activation logic, first we initialize the service instance itself
+        // meaning it is created if necessary and the bundle context is set
+        initService();
+        // then we invoke the init callback so the service can further initialize
+        // itself
+        invoke(init);
+        // now is the time to configure the service, meaning all required
+        // dependencies will be set and any callbacks called
+        configureService(state);
+        // inform the state listeners we're starting
+        stateListenersStarting();
+        // invoke the start callback, since we're now ready to be used
+        invoke(start);
+        // start tracking optional services
+        startTrackingOptional(state);
+        // register the service in the framework's service registry
+        registerService();
+        // inform the state listeners we've started
+        stateListenersStarted();
+    }
+
+    private void deactivateService(State state) {
+    	String stop, destroy;
+    	synchronized (this) {
+    		stop = m_callbackStop;
+    		destroy = m_callbackDestroy;
+    	}
+        // service deactivation logic, first inform the state listeners
+        // we're stopping
+        stateListenersStopping();
+        // then, unregister the service from the framework
+        unregisterService();
+        // stop tracking optional services
+        stopTrackingOptional(state);
+        // invoke the stop callback
+        invoke(stop);
+        // inform the state listeners we've stopped
+        stateListenersStopped();
+        // invoke the destroy callback
+        invoke(destroy);
+        // destroy the service instance
+        destroyService(state);
+    }
+
+    private void invoke(String name) {
+        if (name != null) {
+            // invoke method if it exists
+            try {
+                Class clazz = m_serviceInstance.getClass();
+                while (clazz != null) {
+                	try {
+                	Method method = clazz.getDeclaredMethod(name, null);
+	                	if (method != null) {
+	                		method.setAccessible(true);
+	                		try {
+    	                		method.invoke(m_serviceInstance, null);
+	                		}
+	                		catch (InvocationTargetException e) {
+	                		    m_logger.log(Logger.LOG_ERROR, "Exception while invoking method " + method + ".", e);
+	                		}
+	                		return;
+	                	}
+                	}
+                	catch (NoSuchMethodException e) {
+                		// ignore this, we keep searching if the method does not exist
+                	}
+                	clazz = clazz.getSuperclass();
+                }
+            }
+            catch (Exception e) {
+                m_logger.log(Logger.LOG_ERROR, "Error trying to invoke method named " + name + ".", e);
+            }
+        }
+    }
+
+    private void startTrackingOptional(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (!dependency.isRequired()) {
+                dependency.start(this);
+            }
+        }
+    }
+    
+    private void stopTrackingOptional(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (!dependency.isRequired()) {
+                dependency.stop(this);
+            }
+        }
+    }
+
+    private void startTrackingRequired(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (dependency.isRequired()) {
+                dependency.start(this);
+            }
+        }
+    }
+
+    private void stopTrackingRequired(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (dependency.isRequired()) {
+                dependency.stop(this);
+            }
+        }
+    }
+
+    private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
+		Constructor constructor = clazz.getConstructor(VOID);
+		constructor.setAccessible(true);
+        return clazz.newInstance();
+    }
+
+    void initService() {
+    	if (m_serviceInstance == null) {
+	        if (m_implementation instanceof Class) {
+	            // instantiate
+	            try {
+	            	m_serviceInstance = createInstance((Class) m_implementation);
+	            }
+	            catch (Exception e) {
+	                m_logger.log(Logger.LOG_ERROR, "Could not create service instance of class " + m_implementation + ".", e);
+				}
+	        }
+	        else {
+	        	if (m_instanceFactoryCreateMethod != null) {
+	        		Object factory = null;
+		        	if (m_instanceFactory != null) {
+		        		if (m_instanceFactory instanceof Class) {
+		        			try {
+								factory = createInstance((Class) m_instanceFactory);
+							}
+		                    catch (Exception e) {
+		                        m_logger.log(Logger.LOG_ERROR, "Could not create factory instance of class " + m_instanceFactory + ".", e);
+		                    }
+		        		}
+		        		else {
+		        			factory = m_instanceFactory;
+		        		}
+		        	}
+		        	else {
+		        		// TODO review if we want to try to default to something if not specified
+		        	    // for now the JavaDoc of setFactory(method) reflects the fact that we need
+		        	    // to review it
+		        	}
+		        	if (factory == null) {
+                        m_logger.log(Logger.LOG_ERROR, "Factory cannot be null.");
+		        	}
+		        	else {
+    		        	try {
+    						Method m = factory.getClass().getDeclaredMethod(m_instanceFactoryCreateMethod, null);
+    						m_serviceInstance = m.invoke(factory, null);
+    					}
+    		        	catch (Exception e) {
+    	                    m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
+    					}
+		        	}
+	        	}
+	        	if (m_implementation == null) {
+                    m_logger.log(Logger.LOG_ERROR, "Implementation cannot be null.");
+	        	}
+	        	if (m_serviceInstance == null) {
+	        	    m_serviceInstance = m_implementation;
+	        	}
+	        }
+	        // configure the bundle context
+	        if (((Boolean) m_autoConfig.get(BundleContext.class)).booleanValue()) {
+	            configureImplementation(BundleContext.class, m_context, (String) m_autoConfigInstance.get(BundleContext.class));
+	        }
+            if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
+                configureImplementation(ServiceRegistration.class, NULL_REGISTRATION, (String) m_autoConfigInstance.get(ServiceRegistration.class));
+            }
+            if (((Boolean) m_autoConfig.get(DependencyManager.class)).booleanValue()) {
+                configureImplementation(DependencyManager.class, m_manager, (String) m_autoConfigInstance.get(DependencyManager.class));
+            }
+    	}
+    }
+
+    public void setAutoConfig(Class clazz, boolean autoConfig) {
+        m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
+    }
+    
+    public void setAutoConfig(Class clazz, String instanceName) {
+        m_autoConfig.put(clazz, Boolean.valueOf(instanceName != null));
+        m_autoConfigInstance.put(clazz, instanceName);
+    }
+    
+    private void configureService(State state) {
+        // configure all services (the optional dependencies might be configured
+        // as null objects but that's what we want at this point)
+        configureServices(state);
+    }
+
+    private void destroyService(State state) {
+        unconfigureServices(state);
+        m_serviceInstance = null;
+    }
+
+    private void registerService() {
+        if (m_serviceName != null) {
+            ServiceRegistrationImpl wrapper = new ServiceRegistrationImpl();
+            m_registration = wrapper;
+            if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
+                configureImplementation(ServiceRegistration.class, m_registration, (String) m_autoConfigInstance.get(ServiceRegistration.class));
+            }
+            
+            // service name can either be a string or an array of strings
+            ServiceRegistration registration;
+
+            // determine service properties
+            Dictionary properties = calculateServiceProperties();
+
+            // register the service
+            try {
+                if (m_serviceName instanceof String) {
+                    registration = m_context.registerService((String) m_serviceName, m_serviceInstance, properties);
+                }
+                else {
+                    registration = m_context.registerService((String[]) m_serviceName, m_serviceInstance, properties);
+                }
+                wrapper.setServiceRegistration(registration);
+            }
+            catch (IllegalArgumentException iae) {
+                m_logger.log(Logger.LOG_ERROR, "Could not register service " + m_serviceInstance, iae);
+                // set the registration to an illegal state object, which will make all invocations on this
+                // wrapper fail with an ISE (which also occurs when the SR becomes invalid)
+                wrapper.setIllegalState();
+            }
+        }
+    }
+
+	private Dictionary calculateServiceProperties() {
+		Dictionary properties = new Properties();
+		addTo(properties, m_serviceProperties);
+		for (int i = 0; i < m_dependencies.size(); i++) {
+			Dependency d = (Dependency) m_dependencies.get(i);
+			if (d instanceof ConfigurationDependency) {
+				ConfigurationDependency cd = (ConfigurationDependency) d;
+				if (cd.isPropagated()) {
+					Dictionary dict = cd.getConfiguration();
+					addTo(properties, dict);
+				}
+			}
+		}
+		if (properties.size() == 0) {
+			properties = null;
+		}
+		return properties;
+	}
+
+	private void addTo(Dictionary properties, Dictionary additional) {
+		if (properties == null) {
+			throw new IllegalArgumentException("Dictionary to add to cannot be null.");
+		}
+		if (additional != null) {
+			Enumeration e = additional.keys();
+			while (e.hasMoreElements()) {
+				Object key = e.nextElement();
+				properties.put(key, additional.get(key));
+			}
+		}
+	}
+
+    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(), sd.getAutoConfigName());
+            }
+        }
+        else if (dependency instanceof ConfigurationDependency) {
+        	ConfigurationDependency cd = (ConfigurationDependency) dependency;
+        	if (cd.isPropagated()) {
+        		// change service properties accordingly
+        		Dictionary props = calculateServiceProperties();
+        		m_registration.setProperties(props);
+        	}
+        }
+    }
+
+    /**
+     * 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
+     * @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 = getCompositionInstances();
+    	if (instances != null) {
+	    	for (int i = 0; i < instances.length; i++) {
+	    		Object serviceInstance = instances[i];
+		        Class serviceClazz = serviceInstance.getClass();
+		        while (serviceClazz != null) {
+		            Field[] fields = serviceClazz.getDeclaredFields();
+		            for (int j = 0; j < fields.length; j++) {
+		                if (fields[j].getType().equals(clazz) && (instanceName == null || fields[j].getName().equals(instanceName))) {
+		                    try {
+		                    	fields[j].setAccessible(true);
+		                        // synchronized makes sure the field is actually written to immediately
+		                        synchronized (new Object()) {
+		                            fields[j].set(serviceInstance, instance);
+		                        }
+		                    }
+		                    catch (Exception e) {
+		                        m_logger.log(Logger.LOG_ERROR, "Could not set field " + fields[j], e);
+		                        return;
+		                    }
+		                }
+		            }
+		            serviceClazz = serviceClazz.getSuperclass();
+		        }
+	    	}
+    	}
+    }
+    
+    public Object[] getCompositionInstances() {
+      Object[] instances = null;
+      if (m_compositionManagerGetMethod != null) {
+	if (m_compositionManager != null) {
+	  m_compositionManagerInstance = m_compositionManager;
+	}
+	else {
+	  m_compositionManagerInstance = m_serviceInstance;
+	}
+	if (m_compositionManagerInstance != null) {
+	  try {
+	    Method m = m_compositionManagerInstance.getClass().getDeclaredMethod(m_compositionManagerGetMethod, null);
+	    m.setAccessible(true);
+	    instances = (Object[]) m.invoke(m_compositionManagerInstance, null);
+	  }
+	  catch (Exception e) {
+	    m_logger.log(Logger.LOG_ERROR, "Could not obtain instances from the composition manager.", e);
+	    instances = new Object[] { m_serviceInstance };
+	  }
+	}
+      }
+      else {
+	instances = new Object[] { m_serviceInstance };
+      }
+      return instances;
+    }
+
+    private void configureImplementation(Class clazz, Object instance) {
+        configureImplementation(clazz, instance, null);
+    }
+
+    private void configureServices(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (dependency instanceof ServiceDependency) {
+                ServiceDependency sd = (ServiceDependency) dependency;
+                if (sd.isAutoConfig()) {
+                    if (sd.isRequired()) {
+                        configureImplementation(sd.getInterface(), sd.getService(), sd.getAutoConfigName());
+                    }
+                    else {
+                        // for optional services, we do an "ad-hoc" lookup to inject the service if it is
+                        // already available even though the tracker has not yet been started
+                        configureImplementation(sd.getInterface(), sd.lookupService(), sd.getAutoConfigName());
+                    }
+                }
+                // for required dependencies, we invoke any callbacks here
+                if (sd.isRequired()) {
+                    sd.invokeAdded();
+                }
+            }
+        }
+    }
+
+    private void unconfigureServices(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (dependency instanceof ServiceDependency) {
+                ServiceDependency sd = (ServiceDependency) dependency;
+                // for required dependencies, we invoke any callbacks here
+                if (sd.isRequired()) {
+                    sd.invokeRemoved();
+                }
+            }
+        }
+    }
+
+    private void ensureNotActive() {
+    	State state;
+    	synchronized (m_dependencies) {
+    		state = m_state;
+    	}
+    	if (!state.isInactive()) {
+            throw new IllegalStateException("Cannot modify state while active.");
+        }
+    }
+    boolean isRegistered() {
+    	State state;
+    	synchronized (m_dependencies) {
+    		state = m_state;
+    	}
+        return (state.isTrackingOptional());
+    }
+
+    // ServiceComponent interface
+    
+    static class SCDImpl implements ServiceComponentDependency {
+        private final String m_name;
+        private final int m_state;
+        private final String m_type;
+
+        public SCDImpl(String name, int state, String type) {
+            m_name = name;
+            m_state = state;
+            m_type = type;
+        }
+
+        public String getName() {
+            return m_name;
+        }
+
+        public int getState() {
+            return m_state;
+        }
+
+        public String getType() {
+            return m_type;
+        }
+    }
+    
+    public ServiceComponentDependency[] getComponentDependencies() {
+        List deps = getDependencies();
+        if (deps != null) {
+            ServiceComponentDependency[] result = new ServiceComponentDependency[deps.size()];
+            for (int i = 0; i < result.length; i++) {
+                Dependency dep = (Dependency) deps.get(i);
+                if (dep instanceof ServiceComponentDependency) {
+                    result[i] = (ServiceComponentDependency) dep;
+                }
+                else {
+                    result[i] = new SCDImpl(dep.toString(), (dep.isAvailable() ? 1 : 0) + (dep.isRequired() ? 2 : 0), dep.getClass().getName());
+                }
+            }
+            return result;
+        }
+        return null;
+    }
+
+    public String getName() {
+        if (m_serviceName instanceof String[]) {
+            StringBuffer sb = new StringBuffer();
+            String[] names = (String[]) m_serviceName;
+            for (int i = 0; i < names.length; i++) {
+                if (i > 0) {
+                    sb.append(", ");
+                }
+                sb.append(names[i]);
+            }
+            return sb.toString();
+        }
+        else if (m_serviceName instanceof String) {
+            return m_serviceName.toString();
+        }
+        else {
+            return m_implementation.toString();
+        }
+    }
+
+    public int getState() {
+        return (isRegistered() ? 1 : 0);
+    }
+    
+    static {
+        NULL_REGISTRATION = (ServiceRegistration) Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(), new Class[] {ServiceRegistration.class}, new DefaultNullObject());
+    }
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceRegistrationImpl.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceRegistrationImpl.java
new file mode 100644
index 0000000..0ff8473
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceRegistrationImpl.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.util.Dictionary;
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * A wrapper around a service registration that blocks until the
+ * service registration is available.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class ServiceRegistrationImpl implements ServiceRegistration {
+    public static final ServiceRegistrationImpl ILLEGAL_STATE = new ServiceRegistrationImpl();
+    private volatile ServiceRegistration m_registration;
+
+    public ServiceRegistrationImpl() {
+        m_registration = null;
+    }
+    
+    public ServiceReference getReference() {
+        return ensureRegistration().getReference();
+    }
+
+    public void setProperties(Dictionary dictionary) {
+        ensureRegistration().setProperties(dictionary);
+    }
+
+    public void unregister() {
+        ensureRegistration().unregister();
+    }
+
+    public boolean equals(Object obj) {
+        return ensureRegistration().equals(obj);
+    }
+
+    public int hashCode() {
+        return ensureRegistration().hashCode();
+    }
+
+    public String toString() {
+        return ensureRegistration().toString();
+    }
+    
+    private synchronized ServiceRegistration ensureRegistration() {
+        while (m_registration == null) {
+            try {
+                wait();
+            }
+            catch (InterruptedException ie) {
+                // we were interrupted so hopefully we will now have a
+                // service registration ready; if not we wait again
+            }
+        }
+        // check if we're in an illegal state and throw an exception
+        if (ILLEGAL_STATE == m_registration) {
+            throw new IllegalStateException("Service is not registered.");
+        }
+        return m_registration;
+    }
+
+    /**
+     * Sets the service registration and notifies all waiting parties.
+     */
+    void setServiceRegistration(ServiceRegistration registration) {
+        synchronized (this) {
+        	m_registration = registration;
+            notifyAll();
+        }
+    }
+
+    /**
+     * Sets this wrapper to an illegal state, which will cause all threads
+     * that are waiting for this service registration to fail.
+     */
+	void setIllegalState() {
+        setServiceRegistration(ServiceRegistrationImpl.ILLEGAL_STATE);
+	}
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceStateListener.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceStateListener.java
new file mode 100644
index 0000000..a655633
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceStateListener.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+/**
+ * This interface can be used to register a service state listener. Service
+ * state listeners are called whenever a service state changes. You get notified
+ * when the service is starting, started, stopping and stopped. Each callback
+ * includes a reference to the service in question.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ServiceStateListener {
+    /**
+     * Called when the service is starting. At this point, the required
+     * dependencies have been injected, but the service has not been registered
+     * yet.
+     * 
+     * @param service the service
+     */
+    public void starting(Service service);
+    
+    /**
+     * Called when the service is started. At this point, the service has been
+     * registered.
+     * 
+     * @param service the service
+     */
+    public void started(Service service);
+    
+    /**
+     * Called when the service is stopping. At this point, the service is still
+     * registered.
+     * 
+     * @param service the service
+     */
+    public void stopping(Service service);
+    
+    /**
+     * Called when the service is stopped. At this point, the service has been
+     * unregistered.
+     * 
+     * @param service the service
+     */
+    public void stopped(Service service);
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceTracker.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceTracker.java
new file mode 100644
index 0000000..83c4b4b
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceTracker.java
@@ -0,0 +1,1153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.LinkedList;
+
+import org.osgi.framework.AllServiceListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A modified <code>ServiceTracker</code> class simplifies using services 
+ * from the Framework's service registry. This class is used internally
+ * by the dependency manager. It is based on the OSGi R4.1 sources, which
+ * are made available under the same ASF 2.0 license.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ServiceTracker implements ServiceTrackerCustomizer {
+    /* set this to true to compile in debug messages */
+    static final boolean                DEBUG           = false;
+    /**
+     * Bundle context against which this <code>ServiceTracker</code> object is
+     * tracking.
+     */
+    protected final BundleContext       context;
+    /**
+     * Filter specifying search criteria for the services to track.
+     * 
+     * @since 1.1
+     */
+    protected final Filter              filter;
+    /**
+     * <code>ServiceTrackerCustomizer</code> object for this tracker.
+     */
+    final ServiceTrackerCustomizer      customizer;
+    /**
+     * Filter string for use when adding the ServiceListener. If this field is
+     * set, then certain optimizations can be taken since we don't have a user
+     * supplied filter.
+     */
+    final String                        listenerFilter;
+    /**
+     * Class name to be tracked. If this field is set, then we are tracking by
+     * class name.
+     */
+    private final String                trackClass;
+    /**
+     * Reference to be tracked. If this field is set, then we are tracking a
+     * single ServiceReference.
+     */
+    private final ServiceReference      trackReference;
+    /**
+     * Tracked services: <code>ServiceReference</code> object -> customized
+     * Object and <code>ServiceListener</code> object
+     */
+    private volatile Tracked            tracked;
+    /**
+     * Modification count. This field is initialized to zero by open, set to -1
+     * by close and incremented by modified.
+     * 
+     * This field is volatile since it is accessed by multiple threads.
+     */
+    private volatile int                trackingCount   = -1;
+    /**
+     * Cached ServiceReference for getServiceReference.
+     * 
+     * This field is volatile since it is accessed by multiple threads.
+     */
+    private volatile ServiceReference   cachedReference;
+    /**
+     * Cached service object for getService.
+     * 
+     * This field is volatile since it is accessed by multiple threads.
+     */
+    private volatile Object             cachedService;
+
+    /**
+     * Create a <code>ServiceTracker</code> object on the specified
+     * <code>ServiceReference</code> object.
+     * 
+     * <p>
+     * The service referenced by the specified <code>ServiceReference</code>
+     * object will be tracked by this <code>ServiceTracker</code> object.
+     * 
+     * @param context <code>BundleContext</code> object against which the
+     *        tracking is done.
+     * @param reference <code>ServiceReference</code> object for the service
+     *        to be tracked.
+     * @param customizer The customizer object to call when services are added,
+     *        modified, or removed in this <code>ServiceTracker</code> object.
+     *        If customizer is <code>null</code>, then this
+     *        <code>ServiceTracker</code> object will be used as the
+     *        <code>ServiceTrackerCustomizer</code> object and the
+     *        <code>ServiceTracker</code> object will call the
+     *        <code>ServiceTrackerCustomizer</code> methods on itself.
+     */
+    public ServiceTracker(BundleContext context, ServiceReference reference,
+            ServiceTrackerCustomizer customizer) {
+        this.context = context;
+        this.trackReference = reference;
+        this.trackClass = null;
+        this.customizer = (customizer == null) ? this : customizer;
+        this.listenerFilter = "(" + Constants.SERVICE_ID + "=" + reference.getProperty(Constants.SERVICE_ID).toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        try {
+            this.filter = context.createFilter(listenerFilter);
+        }
+        catch (InvalidSyntaxException e) { // we could only get this exception
+            // if the ServiceReference was
+            // invalid
+            throw new IllegalArgumentException(
+                    "unexpected InvalidSyntaxException: " + e.getMessage()); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Create a <code>ServiceTracker</code> object on the specified class
+     * name.
+     * 
+     * <p>
+     * Services registered under the specified class name will be tracked by
+     * this <code>ServiceTracker</code> object.
+     * 
+     * @param context <code>BundleContext</code> object against which the
+     *        tracking is done.
+     * @param clazz Class name of the services to be tracked.
+     * @param customizer The customizer object to call when services are added,
+     *        modified, or removed in this <code>ServiceTracker</code> object.
+     *        If customizer is <code>null</code>, then this
+     *        <code>ServiceTracker</code> object will be used as the
+     *        <code>ServiceTrackerCustomizer</code> object and the
+     *        <code>ServiceTracker</code> object will call the
+     *        <code>ServiceTrackerCustomizer</code> methods on itself.
+     */
+    public ServiceTracker(BundleContext context, String clazz,
+            ServiceTrackerCustomizer customizer) {
+        this.context = context;
+        this.trackReference = null;
+        this.trackClass = clazz;
+        this.customizer = (customizer == null) ? this : customizer;
+        this.listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+        try {
+            this.filter = context.createFilter(listenerFilter);
+        }
+        catch (InvalidSyntaxException e) { // we could only get this exception
+            // if the clazz argument was
+            // malformed
+            throw new IllegalArgumentException(
+                    "unexpected InvalidSyntaxException: " + e.getMessage()); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Create a <code>ServiceTracker</code> object on the specified
+     * <code>Filter</code> object.
+     * 
+     * <p>
+     * Services which match the specified <code>Filter</code> object will be
+     * tracked by this <code>ServiceTracker</code> object.
+     * 
+     * @param context <code>BundleContext</code> object against which the
+     *        tracking is done.
+     * @param filter <code>Filter</code> object to select the services to be
+     *        tracked.
+     * @param customizer The customizer object to call when services are added,
+     *        modified, or removed in this <code>ServiceTracker</code> object.
+     *        If customizer is null, then this <code>ServiceTracker</code>
+     *        object will be used as the <code>ServiceTrackerCustomizer</code>
+     *        object and the <code>ServiceTracker</code> object will call the
+     *        <code>ServiceTrackerCustomizer</code> methods on itself.
+     * @since 1.1
+     */
+    public ServiceTracker(BundleContext context, Filter filter,
+            ServiceTrackerCustomizer customizer) {
+        this.context = context;
+        this.trackReference = null;
+        this.trackClass = null;
+        this.listenerFilter = null;
+        this.filter = filter;
+        this.customizer = (customizer == null) ? this : customizer;
+        if ((context == null) || (filter == null)) { // we throw a NPE here
+            // to
+            // be consistent with the
+            // other constructors
+            throw new NullPointerException();
+        }
+    }
+
+    /**
+     * Open this <code>ServiceTracker</code> object and begin tracking
+     * services.
+     * 
+     * <p>
+     * This method calls <code>open(false)</code>.
+     * 
+     * @throws java.lang.IllegalStateException if the <code>BundleContext</code>
+     *         object with which this <code>ServiceTracker</code> object was
+     *         created is no longer valid.
+     * @see #open(boolean)
+     */
+    public void open() {
+        open(false);
+    }
+
+    /**
+     * Open this <code>ServiceTracker</code> object and begin tracking
+     * services.
+     * 
+     * <p>
+     * Services which match the search criteria specified when this
+     * <code>ServiceTracker</code> object was created are now tracked by this
+     * <code>ServiceTracker</code> object.
+     * 
+     * @param trackAllServices If <code>true</code>, then this
+     *        <code>ServiceTracker</code> will track all matching services
+     *        regardless of class loader accessibility. If <code>false</code>,
+     *        then this <code>ServiceTracker</code> will only track matching
+     *        services which are class loader accessibile to the bundle whose
+     *        <code>BundleContext</code> is used by this
+     *        <code>ServiceTracker</code>.
+     * @throws java.lang.IllegalStateException if the <code>BundleContext</code>
+     *         object with which this <code>ServiceTracker</code> object was
+     *         created is no longer valid.
+     * @since 1.3
+     */
+    public synchronized void open(boolean trackAllServices) {
+        if (tracked != null) {
+            return;
+        }
+        if (DEBUG) {
+            System.out.println("ServiceTracker.open: " + filter); //$NON-NLS-1$
+        }
+        tracked = trackAllServices ? new AllTracked() : new Tracked();
+        trackingCount = 0;
+        synchronized (tracked) {
+            try {
+                context.addServiceListener(tracked, listenerFilter);
+                ServiceReference[] references;
+                if (listenerFilter == null) { // user supplied filter
+                    references = getInitialReferences(trackAllServices, null,
+                            filter.toString());
+                }
+                else { // constructor supplied filter
+                    if (trackClass == null) {
+                        references = new ServiceReference[] {trackReference};
+                    }
+                    else {
+                        references = getInitialReferences(trackAllServices,
+                                trackClass, null);
+                    }
+                }
+
+                tracked.setInitialServices(references); // set tracked with
+                // the initial
+                // references
+            }
+            catch (InvalidSyntaxException e) {
+                throw new RuntimeException(
+                        "unexpected InvalidSyntaxException: " + e.getMessage()); //$NON-NLS-1$
+            }
+        }
+        /* Call tracked outside of synchronized region */
+        tracked.trackInitialServices(); // process the initial references
+    }
+
+    /**
+     * Returns the list of initial <code>ServiceReference</code> objects that
+     * will be tracked by this <code>ServiceTracker</code> object.
+     * 
+     * @param trackAllServices If true, use getAllServiceReferences.
+     * @param trackClass the class name with which the service was registered,
+     *        or null for all services.
+     * @param filterString the filter criteria or null for all services.
+     * @return the list of initial <code>ServiceReference</code> objects.
+     * @throws InvalidSyntaxException if the filter uses an invalid syntax.
+     */
+    private ServiceReference[] getInitialReferences(boolean trackAllServices,
+            String trackClass, String filterString)
+            throws InvalidSyntaxException {
+        if (trackAllServices) {
+            return context.getAllServiceReferences(trackClass, filterString);
+        }
+        else {
+            return context.getServiceReferences(trackClass, filterString);
+        }
+    }
+
+    /**
+     * Close this <code>ServiceTracker</code> object.
+     * 
+     * <p>
+     * This method should be called when this <code>ServiceTracker</code>
+     * object should end the tracking of services.
+     */
+    public synchronized void close() {
+        if (tracked == null) {
+            return;
+        }
+        if (DEBUG) {
+            System.out.println("ServiceTracker.close: " + filter); //$NON-NLS-1$
+        }
+        tracked.close();
+        ServiceReference[] references = getServiceReferences();
+        Tracked outgoing = tracked;
+        tracked = null;
+        try {
+            context.removeServiceListener(outgoing);
+        }
+        catch (IllegalStateException e) {
+            /* In case the context was stopped. */
+        }
+        if (references != null) {
+            for (int i = 0; i < references.length; i++) {
+                outgoing.untrack(references[i]);
+            }
+        }
+        trackingCount = -1;
+        if (DEBUG) {
+            if ((cachedReference == null) && (cachedService == null)) {
+                System.out
+                        .println("ServiceTracker.close[cached cleared]: " + filter); //$NON-NLS-1$
+            }
+        }
+    }
+
+    /**
+     * Default implementation of the
+     * <code>ServiceTrackerCustomizer.addingService</code> method.
+     * 
+     * <p>
+     * This method is only called when this <code>ServiceTracker</code> object
+     * has been constructed with a <code>null ServiceTrackerCustomizer</code>
+     * argument.
+     * 
+     * The default implementation returns the result of calling
+     * <code>getService</code>, on the <code>BundleContext</code> object
+     * with which this <code>ServiceTracker</code> object was created, passing
+     * the specified <code>ServiceReference</code> object.
+     * <p>
+     * This method can be overridden in a subclass to customize the service
+     * object to be tracked for the service being added. In that case, take care
+     * not to rely on the default implementation of removedService that will
+     * unget the service.
+     * 
+     * @param reference Reference to service being added to this
+     *        <code>ServiceTracker</code> object.
+     * @return The service object to be tracked for the service added to this
+     *         <code>ServiceTracker</code> object.
+     * @see ServiceTrackerCustomizer
+     */
+    public Object addingService(ServiceReference reference) {
+        return context.getService(reference);
+    }
+
+    /**
+     * Default implementation of the
+     * <code>ServiceTrackerCustomizer.modifiedService</code> method.
+     * 
+     * <p>
+     * This method is only called when this <code>ServiceTracker</code> object
+     * has been constructed with a <code>null ServiceTrackerCustomizer</code>
+     * argument.
+     * 
+     * The default implementation does nothing.
+     * 
+     * @param reference Reference to modified service.
+     * @param service The service object for the modified service.
+     * @see ServiceTrackerCustomizer
+     */
+    public void modifiedService(ServiceReference reference, Object service) {
+    }
+
+    /**
+     * Default implementation of the
+     * <code>ServiceTrackerCustomizer.removedService</code> method.
+     * 
+     * <p>
+     * This method is only called when this <code>ServiceTracker</code> object
+     * has been constructed with a <code>null ServiceTrackerCustomizer</code>
+     * argument.
+     * 
+     * The default implementation calls <code>ungetService</code>, on the
+     * <code>BundleContext</code> object with which this
+     * <code>ServiceTracker</code> object was created, passing the specified
+     * <code>ServiceReference</code> object.
+     * <p>
+     * This method can be overridden in a subclass. If the default
+     * implementation of <code>addingService</code> method was used, this
+     * method must unget the service.
+     * 
+     * @param reference Reference to removed service.
+     * @param service The service object for the removed service.
+     * @see ServiceTrackerCustomizer
+     */
+    public void removedService(ServiceReference reference, Object service) {
+        context.ungetService(reference);
+    }
+
+    /**
+     * Wait for at least one service to be tracked by this
+     * <code>ServiceTracker</code> object.
+     * <p>
+     * It is strongly recommended that <code>waitForService</code> is not used
+     * during the calling of the <code>BundleActivator</code> methods.
+     * <code>BundleActivator</code> methods are expected to complete in a
+     * short period of time.
+     * 
+     * @param timeout time interval in milliseconds to wait. If zero, the method
+     *        will wait indefinately.
+     * @return Returns the result of <code>getService()</code>.
+     * @throws InterruptedException If another thread has interrupted the
+     *         current thread.
+     * @throws IllegalArgumentException If the value of timeout is negative.
+     */
+    public Object waitForService(long timeout) throws InterruptedException {
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout value is negative"); //$NON-NLS-1$
+        }
+        Object object = getService();
+        while (object == null) {
+            Tracked tracked = this.tracked; /*
+                                             * use local var since we are not
+                                             * synchronized
+                                             */
+            if (tracked == null) { /* if ServiceTracker is not open */
+                return null;
+            }
+            synchronized (tracked) {
+                if (tracked.size() == 0) {
+                    tracked.wait(timeout);
+                }
+            }
+            object = getService();
+            if (timeout > 0) {
+                return object;
+            }
+        }
+        return object;
+    }
+
+    /**
+     * Return an array of <code>ServiceReference</code> objects for all
+     * services being tracked by this <code>ServiceTracker</code> object.
+     * 
+     * @return Array of <code>ServiceReference</code> objects or
+     *         <code>null</code> if no service are being tracked.
+     */
+    public ServiceReference[] getServiceReferences() {
+        Tracked tracked = this.tracked; /*
+                                         * use local var since we are not
+                                         * synchronized
+                                         */
+        if (tracked == null) { /* if ServiceTracker is not open */
+            return null;
+        }
+        synchronized (tracked) {
+            int length = tracked.size();
+            if (length == 0) {
+                return null;
+            }
+            ServiceReference[] references = new ServiceReference[length];
+            Enumeration keys = tracked.keys();
+            for (int i = 0; i < length; i++) {
+                references[i] = (ServiceReference) keys.nextElement();
+            }
+            return references;
+        }
+    }
+
+    /**
+     * Returns a <code>ServiceReference</code> object for one of the services
+     * being tracked by this <code>ServiceTracker</code> object.
+     * 
+     * <p>
+     * If multiple services are being tracked, the service with the highest
+     * ranking (as specified in its <code>service.ranking</code> property) is
+     * returned.
+     * 
+     * <p>
+     * If there is a tie in ranking, the service with the lowest service ID (as
+     * specified in its <code>service.id</code> property); that is, the
+     * service that was registered first is returned.
+     * <p>
+     * This is the same algorithm used by
+     * <code>BundleContext.getServiceReference</code>.
+     * 
+     * @return <code>ServiceReference</code> object or <code>null</code> if
+     *         no service is being tracked.
+     * @since 1.1
+     */
+    public ServiceReference getServiceReference() {
+        ServiceReference reference = cachedReference;
+        if (reference != null) {
+            if (DEBUG) {
+                System.out
+                        .println("ServiceTracker.getServiceReference[cached]: " + filter); //$NON-NLS-1$
+            }
+            return reference;
+        }
+        if (DEBUG) {
+            System.out.println("ServiceTracker.getServiceReference: " + filter); //$NON-NLS-1$
+        }
+        ServiceReference[] references = getServiceReferences();
+        int length = (references == null) ? 0 : references.length;
+        if (length == 0) /* if no service is being tracked */
+        {
+            return null;
+        }
+        int index = 0;
+        if (length > 1) /* if more than one service, select highest ranking */
+        {
+            int rankings[] = new int[length];
+            int count = 0;
+            int maxRanking = Integer.MIN_VALUE;
+            for (int i = 0; i < length; i++) {
+                Object property = references[i]
+                        .getProperty(Constants.SERVICE_RANKING);
+                int ranking = (property instanceof Integer) ? ((Integer) property)
+                        .intValue()
+                        : 0;
+                rankings[i] = ranking;
+                if (ranking > maxRanking) {
+                    index = i;
+                    maxRanking = ranking;
+                    count = 1;
+                }
+                else {
+                    if (ranking == maxRanking) {
+                        count++;
+                    }
+                }
+            }
+            if (count > 1) /* if still more than one service, select lowest id */
+            {
+                long minId = Long.MAX_VALUE;
+                for (int i = 0; i < length; i++) {
+                    if (rankings[i] == maxRanking) {
+                        long id = ((Long) (references[i]
+                                .getProperty(Constants.SERVICE_ID)))
+                                .longValue();
+                        if (id < minId) {
+                            index = i;
+                            minId = id;
+                        }
+                    }
+                }
+            }
+        }
+        return cachedReference = references[index];
+    }
+
+    /**
+     * Returns the service object for the specified
+     * <code>ServiceReference</code> object if the referenced service is being
+     * tracked by this <code>ServiceTracker</code> object.
+     * 
+     * @param reference Reference to the desired service.
+     * @return Service object or <code>null</code> if the service referenced
+     *         by the specified <code>ServiceReference</code> object is not
+     *         being tracked.
+     */
+    public Object getService(ServiceReference reference) {
+        Tracked tracked = this.tracked; /*
+                                         * use local var since we are not
+                                         * synchronized
+                                         */
+        if (tracked == null) { /* if ServiceTracker is not open */
+            return null;
+        }
+        synchronized (tracked) {
+            return tracked.get(reference);
+        }
+    }
+
+    /**
+     * Return an array of service objects for all services being tracked by this
+     * <code>ServiceTracker</code> object.
+     * 
+     * @return Array of service objects or <code>null</code> if no service are
+     *         being tracked.
+     */
+    public Object[] getServices() {
+        Tracked tracked = this.tracked; /*
+                                         * use local var since we are not
+                                         * synchronized
+                                         */
+        if (tracked == null) { /* if ServiceTracker is not open */
+            return null;
+        }
+        synchronized (tracked) {
+            ServiceReference[] references = getServiceReferences();
+            int length = (references == null) ? 0 : references.length;
+            if (length == 0) {
+                return null;
+            }
+            Object[] objects = new Object[length];
+            for (int i = 0; i < length; i++) {
+                objects[i] = getService(references[i]);
+            }
+            return objects;
+        }
+    }
+
+    /**
+     * Returns a service object for one of the services being tracked by this
+     * <code>ServiceTracker</code> object.
+     * 
+     * <p>
+     * If any services are being tracked, this method returns the result of
+     * calling <code>getService(getServiceReference())</code>.
+     * 
+     * @return Service object or <code>null</code> if no service is being
+     *         tracked.
+     */
+    public Object getService() {
+        Object service = cachedService;
+        if (service != null) {
+            if (DEBUG) {
+                System.out
+                        .println("ServiceTracker.getService[cached]: " + filter); //$NON-NLS-1$
+            }
+            return service;
+        }
+        if (DEBUG) {
+            System.out.println("ServiceTracker.getService: " + filter); //$NON-NLS-1$
+        }
+        ServiceReference reference = getServiceReference();
+        if (reference == null) {
+            return null;
+        }
+        return cachedService = getService(reference);
+    }
+
+    /**
+     * Remove a service from this <code>ServiceTracker</code> object.
+     * 
+     * The specified service will be removed from this
+     * <code>ServiceTracker</code> object. If the specified service was being
+     * tracked then the <code>ServiceTrackerCustomizer.removedService</code>
+     * method will be called for that service.
+     * 
+     * @param reference Reference to the service to be removed.
+     */
+    public void remove(ServiceReference reference) {
+        Tracked tracked = this.tracked; /*
+                                         * use local var since we are not
+                                         * synchronized
+                                         */
+        if (tracked == null) { /* if ServiceTracker is not open */
+            return;
+        }
+        tracked.untrack(reference);
+    }
+
+    /**
+     * Return the number of services being tracked by this
+     * <code>ServiceTracker</code> object.
+     * 
+     * @return Number of services being tracked.
+     */
+    public int size() {
+        Tracked tracked = this.tracked; /*
+                                         * use local var since we are not
+                                         * synchronized
+                                         */
+        if (tracked == null) { /* if ServiceTracker is not open */
+            return 0;
+        }
+        return tracked.size();
+    }
+
+    /**
+     * Returns the tracking count for this <code>ServiceTracker</code> object.
+     * 
+     * The tracking count is initialized to 0 when this
+     * <code>ServiceTracker</code> object is opened. Every time a service is
+     * added, modified or removed from this <code>ServiceTracker</code> object
+     * the tracking count is incremented.
+     * 
+     * <p>
+     * The tracking count can be used to determine if this
+     * <code>ServiceTracker</code> object has added, modified or removed a
+     * service by comparing a tracking count value previously collected with the
+     * current tracking count value. If the value has not changed, then no
+     * service has been added, modified or removed from this
+     * <code>ServiceTracker</code> object since the previous tracking count
+     * was collected.
+     * 
+     * @since 1.2
+     * @return The tracking count for this <code>ServiceTracker</code> object
+     *         or -1 if this <code>ServiceTracker</code> object is not open.
+     */
+    public int getTrackingCount() {
+        return trackingCount;
+    }
+
+    /**
+     * Called by the Tracked object whenever the set of tracked services is
+     * modified. Increments the tracking count and clears the cache.
+     * 
+     * @GuardedBy tracked
+     */
+    /*
+     * This method must not be synchronized since it is called by Tracked while
+     * Tracked is synchronized. We don't want synchronization interactions
+     * between the ServiceListener thread and the user thread.
+     */
+    void modified() {
+        trackingCount++; /* increment modification count */
+        cachedReference = null; /* clear cached value */
+        cachedService = null; /* clear cached value */
+        if (DEBUG) {
+            System.out.println("ServiceTracker.modified: " + filter); //$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Inner class to track services. If a <code>ServiceTracker</code> object
+     * is reused (closed then reopened), then a new Tracked object is used. This
+     * class is a hashtable mapping <code>ServiceReference</code> object ->
+     * customized Object. This class is the <code>ServiceListener</code>
+     * object for the tracker. This class is used to synchronize access to the
+     * tracked services. This is not a public class. It is only for use by the
+     * implementation of the <code>ServiceTracker</code> class.
+     * 
+     * @ThreadSafe
+     */
+    class Tracked extends Hashtable implements ServiceListener {
+        static final long           serialVersionUID    = -7420065199791006079L;
+        /**
+         * List of ServiceReferences in the process of being added. This is used
+         * to deal with nesting of ServiceEvents. Since ServiceEvents are
+         * synchronously delivered, ServiceEvents can be nested. For example,
+         * when processing the adding of a service and the customizer causes the
+         * service to be unregistered, notification to the nested call to
+         * untrack that the service was unregistered can be made to the track
+         * method.
+         * 
+         * Since the ArrayList implementation is not synchronized, all access to
+         * this list must be protected by the same synchronized object for
+         * thread-safety.
+         * 
+         * @GuardedBy this
+         */
+        private final ArrayList     adding;
+
+        /**
+         * true if the tracked object is closed.
+         * 
+         * This field is volatile because it is set by one thread and read by
+         * another.
+         */
+        private volatile boolean    closed;
+
+        /**
+         * Initial list of ServiceReferences for the tracker. This is used to
+         * correctly process the initial services which could become
+         * unregistered before they are tracked. This is necessary since the
+         * initial set of tracked services are not "announced" by ServiceEvents
+         * and therefore the ServiceEvent for unregistration could be delivered
+         * before we track the service.
+         * 
+         * A service must not be in both the initial and adding lists at the
+         * same time. A service must be moved from the initial list to the
+         * adding list "atomically" before we begin tracking it.
+         * 
+         * Since the LinkedList implementation is not synchronized, all access
+         * to this list must be protected by the same synchronized object for
+         * thread-safety.
+         * 
+         * @GuardedBy this
+         */
+        private final LinkedList    initial;
+
+        /**
+         * Tracked constructor.
+         */
+        protected Tracked() {
+            super();
+            closed = false;
+            adding = new ArrayList(6);
+            initial = new LinkedList();
+        }
+
+        /**
+         * Set initial list of services into tracker before ServiceEvents begin
+         * to be received.
+         * 
+         * This method must be called from ServiceTracker.open while
+         * synchronized on this object in the same synchronized block as the
+         * addServiceListener call.
+         * 
+         * @param references The initial list of services to be tracked.
+         * @GuardedBy this
+         */
+        protected void setInitialServices(ServiceReference[] references) {
+            if (references == null) {
+                return;
+            }
+            int size = references.length;
+            for (int i = 0; i < size; i++) {
+                if (DEBUG) {
+                    System.out
+                            .println("ServiceTracker.Tracked.setInitialServices: " + references[i]); //$NON-NLS-1$
+                }
+                initial.add(references[i]);
+            }
+        }
+
+        /**
+         * Track the initial list of services. This is called after
+         * ServiceEvents can begin to be received.
+         * 
+         * This method must be called from ServiceTracker.open while not
+         * synchronized on this object after the addServiceListener call.
+         * 
+         */
+        protected void trackInitialServices() {
+            while (true) {
+                ServiceReference reference;
+                synchronized (this) {
+                    if (initial.size() == 0) {
+                        /*
+                         * if there are no more inital services
+                         */
+                        return; /* we are done */
+                    }
+                    /*
+                     * move the first service from the initial list to the
+                     * adding list within this synchronized block.
+                     */
+                    reference = (ServiceReference) initial.removeFirst();
+                    if (this.get(reference) != null) {
+                        /* if we are already tracking this service */
+                        if (DEBUG) {
+                            System.out
+                                    .println("ServiceTracker.Tracked.trackInitialServices[already tracked]: " + reference); //$NON-NLS-1$
+                        }
+                        continue; /* skip this service */
+                    }
+                    if (adding.contains(reference)) {
+                        /*
+                         * if this service is already in the process of being
+                         * added.
+                         */
+                        if (DEBUG) {
+                            System.out
+                                    .println("ServiceTracker.Tracked.trackInitialServices[already adding]: " + reference); //$NON-NLS-1$
+                        }
+                        continue; /* skip this service */
+                    }
+                    adding.add(reference);
+                }
+                if (DEBUG) {
+                    System.out
+                            .println("ServiceTracker.Tracked.trackInitialServices: " + reference); //$NON-NLS-1$
+                }
+                trackAdding(reference); /*
+                                         * Begin tracking it. We call
+                                         * trackAdding since we have already put
+                                         * the reference in the adding list.
+                                         */
+            }
+        }
+
+        /**
+         * Called by the owning <code>ServiceTracker</code> object when it is
+         * closed.
+         */
+        protected void close() {
+            closed = true;
+        }
+
+        /**
+         * <code>ServiceListener</code> method for the
+         * <code>ServiceTracker</code> class. This method must NOT be
+         * synchronized to avoid deadlock potential.
+         * 
+         * @param event <code>ServiceEvent</code> object from the framework.
+         */
+        public void serviceChanged(ServiceEvent event) {
+            /*
+             * Check if we had a delayed call (which could happen when we
+             * close).
+             */
+            if (closed) {
+                return;
+            }
+            ServiceReference reference = event.getServiceReference();
+            if (DEBUG) {
+                System.out
+                        .println("ServiceTracker.Tracked.serviceChanged[" + event.getType() + "]: " + reference); //$NON-NLS-1$ //$NON-NLS-2$
+            }
+
+            switch (event.getType()) {
+                case ServiceEvent.REGISTERED :
+                case ServiceEvent.MODIFIED :
+                    if (listenerFilter != null) { // constructor supplied
+                        // filter
+                        track(reference);
+                        /*
+                         * If the customizer throws an unchecked exception, it
+                         * is safe to let it propagate
+                         */
+                    }
+                    else { // user supplied filter
+                        if (filter.match(reference)) {
+                            track(reference);
+                            /*
+                             * If the customizer throws an unchecked exception,
+                             * it is safe to let it propagate
+                             */
+                        }
+                        else {
+                            untrack(reference);
+                            /*
+                             * If the customizer throws an unchecked exception,
+                             * it is safe to let it propagate
+                             */
+                        }
+                    }
+                    break;
+                case ServiceEvent.UNREGISTERING :
+                    untrack(reference);
+                    /*
+                     * If the customizer throws an unchecked exception, it is
+                     * safe to let it propagate
+                     */
+                    break;
+            }
+        }
+
+        /**
+         * Begin to track the referenced service.
+         * 
+         * @param reference Reference to a service to be tracked.
+         */
+        private void track(ServiceReference reference) {
+            Object object;
+            synchronized (this) {
+                object = this.get(reference);
+            }
+            if (object != null) /* we are already tracking the service */
+            {
+                if (DEBUG) {
+                    System.out
+                            .println("ServiceTracker.Tracked.track[modified]: " + reference); //$NON-NLS-1$
+                }
+                synchronized (this) {
+                    modified(); /* increment modification count */
+                }
+                /* Call customizer outside of synchronized region */
+                customizer.modifiedService(reference, object);
+                /*
+                 * If the customizer throws an unchecked exception, it is safe
+                 * to let it propagate
+                 */
+                return;
+            }
+            synchronized (this) {
+                if (adding.contains(reference)) { /*
+                                                     * if this service is
+                                                     * already in the process of
+                                                     * being added.
+                                                     */
+                    if (DEBUG) {
+                        System.out
+                                .println("ServiceTracker.Tracked.track[already adding]: " + reference); //$NON-NLS-1$
+                    }
+                    return;
+                }
+                adding.add(reference); /* mark this service is being added */
+            }
+
+            trackAdding(reference); /*
+                                     * call trackAdding now that we have put the
+                                     * reference in the adding list
+                                     */
+        }
+
+        /**
+         * Common logic to add a service to the tracker used by track and
+         * trackInitialServices. The specified reference must have been placed
+         * in the adding list before calling this method.
+         * 
+         * @param reference Reference to a service to be tracked.
+         */
+        private void trackAdding(ServiceReference reference) {
+            if (DEBUG) {
+                System.out
+                        .println("ServiceTracker.Tracked.trackAdding: " + reference); //$NON-NLS-1$
+            }
+            Object object = null;
+            boolean becameUntracked = false;
+            /* Call customizer outside of synchronized region */
+            try {
+                object = customizer.addingService(reference);
+                /*
+                 * If the customizer throws an unchecked exception, it will
+                 * propagate after the finally
+                 */
+            }
+            finally {
+                boolean needToCallback = false;
+                synchronized (this) {
+                    if (adding.remove(reference)) { /*
+                                                     * if the service was not
+                                                     * untracked during the
+                                                     * customizer callback
+                                                     */
+                        if (object != null) {
+                            this.put(reference, object);
+                            modified(); /* increment modification count */
+                            notifyAll(); /*
+                                             * notify any waiters in
+                                             * waitForService
+                                             */
+                            // marrs: extra callback added, will be invoked after 
+                            // the synchronized block
+                            needToCallback = true;
+                        }
+                    }
+                    else {
+                        becameUntracked = true;
+                    }
+                }
+                if (needToCallback) {
+                    customizer.addedService(reference, object);
+                }
+            }
+            /*
+             * The service became untracked during the customizer callback.
+             */
+            if (becameUntracked) {
+                if (DEBUG) {
+                    System.out
+                            .println("ServiceTracker.Tracked.trackAdding[removed]: " + reference); //$NON-NLS-1$
+                }
+                /* Call customizer outside of synchronized region */
+                customizer.removedService(reference, object);
+                /*
+                 * If the customizer throws an unchecked exception, it is safe
+                 * to let it propagate
+                 */
+            }
+        }
+
+        /**
+         * Discontinue tracking the referenced service.
+         * 
+         * @param reference Reference to the tracked service.
+         */
+        protected void untrack(ServiceReference reference) {
+            Object object;
+            synchronized (this) {
+                if (initial.remove(reference)) { /*
+                                                     * if this service is
+                                                     * already in the list of
+                                                     * initial references to
+                                                     * process
+                                                     */
+                    if (DEBUG) {
+                        System.out
+                                .println("ServiceTracker.Tracked.untrack[removed from initial]: " + reference); //$NON-NLS-1$
+                    }
+                    return; /*
+                             * we have removed it from the list and it will not
+                             * be processed
+                             */
+                }
+
+                if (adding.remove(reference)) { /*
+                                                 * if the service is in the
+                                                 * process of being added
+                                                 */
+                    if (DEBUG) {
+                        System.out
+                                .println("ServiceTracker.Tracked.untrack[being added]: " + reference); //$NON-NLS-1$
+                    }
+                    return; /*
+                             * in case the service is untracked while in the
+                             * process of adding
+                             */
+                }
+                object = this.remove(reference); /*
+                                                     * must remove from tracker
+                                                     * before calling customizer
+                                                     * callback
+                                                     */
+                if (object == null) { /* are we actually tracking the service */
+                    return;
+                }
+                modified(); /* increment modification count */
+            }
+            if (DEBUG) {
+                System.out
+                        .println("ServiceTracker.Tracked.untrack[removed]: " + reference); //$NON-NLS-1$
+            }
+            /* Call customizer outside of synchronized region */
+            customizer.removedService(reference, object);
+            /*
+             * If the customizer throws an unchecked exception, it is safe to
+             * let it propagate
+             */
+        }
+    }
+
+    /**
+     * Subclass of Tracked which implements the AllServiceListener interface.
+     * This class is used by the ServiceTracker if open is called with true.
+     * 
+     * @since 1.3
+     * @ThreadSafe
+     */
+    class AllTracked extends Tracked implements AllServiceListener {
+        static final long   serialVersionUID    = 4050764875305137716L;
+
+        /**
+         * AllTracked constructor.
+         */
+        protected AllTracked() {
+            super();
+        }
+    }
+
+    public void addedService(ServiceReference ref, Object service) {
+        // do nothing
+    }
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceTrackerCustomizer.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceTrackerCustomizer.java
new file mode 100644
index 0000000..44f7590
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/ServiceTrackerCustomizer.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A modified version of a normal service tracker customizer. This one has an
+ * extra callback "addedservice" that is invoked after the service has been added
+ * to the tracker (and therefore is accessible through the tracker API).
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface ServiceTrackerCustomizer {
+    public Object addingService(ServiceReference ref);
+    public void addedService(ServiceReference ref, Object service);
+    public void modifiedService(ServiceReference ref, Object service);
+    public void removedService(ServiceReference ref, Object service);
+}
diff --git a/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/State.java b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/State.java
new file mode 100644
index 0000000..bd960b6
--- /dev/null
+++ b/dependencymanager.temp/src/main/java/org/apache/felix/dependencymanager/State.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dependencymanager;
+
+import java.util.List;
+
+/**
+ * Encapsulates the current state of the dependencies of a service. A state is
+ * basically an immutable value object.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class State {
+    private static final String[] STATES = { "?", "inactive", "waiting for required", "tracking optional" };
+    private static final int INACTIVE = 1;
+    private static final int WAITING_FOR_REQUIRED = 2;
+    private static final int TRACKING_OPTIONAL = 3;
+	private final List m_deps;
+	private final int m_state;
+    private String m_stringValue;
+	
+	/**
+	 * Creates a new state instance.
+	 * 
+	 * @param deps the dependencies that determine the state
+	 * @param isActive <code>true</code> if the service is active (started)
+	 */
+	public State(List deps, boolean isActive) {
+		m_deps = deps;
+		// only bother calculating dependencies if we're active
+    	if (isActive) {
+    		boolean allRequiredAvailable = true;
+    		for (int i = 0; i < deps.size(); i++) {
+    			Dependency dep = (Dependency) deps.get(i);
+    			if (dep.isRequired()) {
+    				if (!dep.isAvailable()) {
+    					allRequiredAvailable = false;
+    				}
+    			}
+    		}
+	    	if (allRequiredAvailable) {
+	    		m_state = TRACKING_OPTIONAL;
+	    	}
+	    	else {
+	    		m_state = WAITING_FOR_REQUIRED;
+	    	}
+    	}
+    	else {
+    		m_state = INACTIVE;
+    	}
+	}
+	
+	public boolean isInactive() {
+		return m_state == INACTIVE;
+	}
+	
+	public boolean isWaitingForRequired() {
+		return m_state == WAITING_FOR_REQUIRED;
+	}
+	
+	public boolean isTrackingOptional() {
+		return m_state == TRACKING_OPTIONAL;
+	}
+	
+	public List getDependencies() {
+		return m_deps;
+	}
+	
+	public synchronized String toString() {
+	    if (m_stringValue == null) {
+	        // we only need to determine this once, but we do it lazily
+	        StringBuffer buf = new StringBuffer();
+    		buf.append("State[" + STATES[m_state] + "|");
+    		List deps = m_deps;
+        	for (int i = 0; i < deps.size(); i++) {
+        		Dependency dep = (Dependency) deps.get(i);
+        		buf.append("(" + dep + (dep.isRequired() ? " R" : " O") + (dep.isAvailable() ? " +" : " -") + ")");
+        	}
+        	m_stringValue = buf.toString();
+	    }
+        return m_stringValue;
+	}
+}
diff --git a/dependencymanager.temp/src/test/java/org/apache/felix/dependencymanager/test/ComponentLifeCycleTest.java b/dependencymanager.temp/src/test/java/org/apache/felix/dependencymanager/test/ComponentLifeCycleTest.java
new file mode 100644
index 0000000..f836184
--- /dev/null
+++ b/dependencymanager.temp/src/test/java/org/apache/felix/dependencymanager/test/ComponentLifeCycleTest.java
@@ -0,0 +1,98 @@
+package org.apache.felix.dependencymanager.test;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.apache.felix.dependencymanager.Logger;
+import org.apache.felix.dependencymanager.Service;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
+
+@RunWith( JUnit4TestRunner.class )
+public class ComponentLifeCycleTest {
+    @Configuration
+    public static Option[] configuration() {
+        return options(
+            provision(
+                mavenBundle().groupId("org.apache.felix").artifactId("org.osgi.compendium").versionAsInProject(),
+                mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.dependencymanager").versionAsInProject()
+            )
+        );
+    }    
+    
+    @Test
+    public void testComponentLifeCycleCallbacks(BundleContext context) {
+        DependencyManager m = new DependencyManager(context, new Logger(context));
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a simple service component
+        Service s = m.createService().setImplementation(new ComponentInstance(e));
+        // add it, and since it has no dependencies, it should be activated immediately
+        m.add(s);
+        // remove it so it gets destroyed
+        m.remove(s);
+        // ensure we executed all steps inside the component instance
+        e.step(6);
+    }
+    
+    @Test
+    public void testCustomComponentLifeCycleCallbacks(BundleContext context) {
+        DependencyManager m = new DependencyManager(context, new Logger(context));
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a simple service component
+        Service s = m.createService().setImplementation(new CustomComponentInstance(e)).setCallbacks("a", "b", "c", "d");
+        // add it, and since it has no dependencies, it should be activated immediately
+        m.add(s);
+        // remove it so it gets destroyed
+        m.remove(s);
+        // ensure we executed all steps inside the component instance
+        e.step(6);
+    }
+}
+
+class ComponentInstance {
+    private final Ensure m_ensure;
+    public ComponentInstance(Ensure e) {
+        m_ensure = e;
+        m_ensure.step(1);
+    }
+    public void init() {
+        m_ensure.step(2);
+    }
+    public void start() {
+        m_ensure.step(3);
+    }
+    public void stop() {
+        m_ensure.step(4);
+    }
+    public void destroy() {
+        m_ensure.step(5);
+    }
+}
+
+class CustomComponentInstance {
+    private final Ensure m_ensure;
+    public CustomComponentInstance(Ensure e) {
+        m_ensure = e;
+        m_ensure.step(1);
+    }
+    public void a() {
+        m_ensure.step(2);
+    }
+    public void b() {
+        m_ensure.step(3);
+    }
+    public void c() {
+        m_ensure.step(4);
+    }
+    public void d() {
+        m_ensure.step(5);
+    }
+}
diff --git a/dependencymanager.temp/src/test/java/org/apache/felix/dependencymanager/test/Ensure.java b/dependencymanager.temp/src/test/java/org/apache/felix/dependencymanager/test/Ensure.java
new file mode 100644
index 0000000..c27e246
--- /dev/null
+++ b/dependencymanager.temp/src/test/java/org/apache/felix/dependencymanager/test/Ensure.java
@@ -0,0 +1,11 @@
+package org.apache.felix.dependencymanager.test;
+
+import junit.framework.Assert;
+
+public class Ensure {
+    int step = 1;
+    public synchronized void step(int nr) {
+        Assert.assertEquals(nr, step);
+        step++;
+    }
+}
diff --git a/dependencymanager.temp/src/test/java/org/apache/felix/dependencymanager/test/ServiceDependencyTest.java b/dependencymanager.temp/src/test/java/org/apache/felix/dependencymanager/test/ServiceDependencyTest.java
new file mode 100644
index 0000000..ddd5af6
--- /dev/null
+++ b/dependencymanager.temp/src/test/java/org/apache/felix/dependencymanager/test/ServiceDependencyTest.java
@@ -0,0 +1,76 @@
+package org.apache.felix.dependencymanager.test;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+
+import org.apache.felix.dependencymanager.DependencyManager;
+import org.apache.felix.dependencymanager.Logger;
+import org.apache.felix.dependencymanager.Service;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
+
+@RunWith( JUnit4TestRunner.class )
+public class ServiceDependencyTest {
+    @Configuration
+    public static Option[] configuration() {
+        return options(
+            provision(
+                mavenBundle().groupId("org.apache.felix").artifactId("org.osgi.compendium").versionAsInProject(),
+                mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.dependencymanager").versionAsInProject()
+            )
+        );
+    }    
+
+    @Test
+    public void testServiceRegistrationAndConsumption(BundleContext context) {
+        DependencyManager m = new DependencyManager(context, new Logger(context));
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a service provider and consumer
+        Service sp = m.createService().setImplementation(new ServiceProvider(e)).setInterface(ServiceInterface.class.getName(), null);
+        Service sc = m.createService().setImplementation(new ServiceConsumer(e)).add(m.createServiceDependency().setService(ServiceInterface.class).setRequired(true));
+        m.add(sp);
+        m.add(sc);
+        m.remove(sp);
+        m.remove(sc);
+        // ensure we executed all steps inside the component instance
+        e.step(4);
+    }
+}
+
+interface ServiceInterface {
+    public void invoke();
+}
+
+class ServiceProvider implements ServiceInterface {
+    private final Ensure m_ensure;
+    public ServiceProvider(Ensure e) {
+        m_ensure = e;
+    }
+    public void invoke() {
+        m_ensure.step(2);
+    }
+}
+
+class ServiceConsumer {
+    private volatile ServiceInterface m_service;
+    private final Ensure m_ensure;
+
+    public ServiceConsumer(Ensure e) {
+        m_ensure = e;
+    }
+    
+    public void start() {
+        m_ensure.step(1);
+        m_service.invoke();
+    }
+    
+    public void stop() {
+        m_ensure.step(3);
+    }
+}