FELIX-1201 Applied the patch. Reformatted the code and docs a bit.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@822842 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ConfigurationDependency.java b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ConfigurationDependency.java
index 0c24e25..c5d0971 100644
--- a/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ConfigurationDependency.java
+++ b/dependencymanager/src/main/java/org/apache/felix/dependencymanager/ConfigurationDependency.java
@@ -17,7 +17,8 @@
  * 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;
 
@@ -31,19 +32,19 @@
  * 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
+ * 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:
- * <li>
- * <ul>Make sure it throws a <code>ConfigurationException</code> when you get a
+ * <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.</ul>
- * <ul>This method will be called before all required dependencies are available.
- * Make sure you do not depend on these to parse your settings.</ul>
- * </li>
+ * 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>
  */
@@ -54,11 +55,12 @@
 	private volatile Service m_service;
 	private Dictionary m_settings;
 	private boolean m_propagate;
-    private final Logger m_logger;
+	private final Logger m_logger;
+    private String m_callback;
 	
 	public ConfigurationDependency(BundleContext context, Logger logger) {
 		m_context = context;
-        m_logger = logger;
+		m_logger = logger;
 	}
 	
 	public synchronized boolean isAvailable() {
@@ -98,38 +100,68 @@
 		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();
-		if (service != null) {
-			if (service instanceof ManagedService) {
-				ManagedService ms = (ManagedService) service;
-				ms.updated(settings);
 				
-				// 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
-			}
-			else {
-				m_logger.log(Logger.LOG_ERROR, "Service " + m_service + " with configuration dependency " + this + " does not implement ManagedService.");
-				return;
-			}
-		}
-		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
 		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 });
+		
+			  	// 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);
 		}
@@ -162,10 +194,10 @@
 		return this;
 	}
 	
-    private void ensureNotActive() {
-        if (m_service != null) {
-            throw new IllegalStateException("Cannot modify state while active.");
-        }
+	private void ensureNotActive() {
+	  	if (m_service != null) {
+	  	  throw new IllegalStateException("Cannot modify state while active.");
+	  	}
     }
     
     public String toString() {