You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ui...@apache.org on 2012/02/24 11:47:51 UTC

svn commit: r1293173 [4/8] - in /felix/sandbox/uiterlix/dependencymanager/core: ./ .externalToolBuilders/ .settings/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/fel...

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,288 @@
+/*
+ * 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.dm.impl;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ComponentStateListener;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.InvocationUtil;
+import org.apache.felix.dm.PropertyMetaData;
+import org.apache.felix.dm.impl.metatype.MetaTypeProviderImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.metatype.MetaTypeProvider;
+import org.osgi.service.metatype.ObjectClassDefinition;
+
+/**
+ * Factory configuration adapter service implementation. This class extends the FilterService in order to catch
+ * some Service methods for configuring actual adapter service implementation.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FactoryConfigurationAdapterServiceImpl extends FilterService {
+    public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate) {
+        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+        Hashtable props = new Hashtable();
+        props.put(Constants.SERVICE_PID, factoryPid);
+        m_component
+            .setInterface(ManagedServiceFactory.class.getName(), props)
+            .setImplementation(new AdapterImpl(factoryPid, update, propagate));
+    }
+    
+    public FactoryConfigurationAdapterServiceImpl(DependencyManager dm, String factoryPid, String update, boolean propagate,
+        BundleContext bctx, Logger logger, String heading, String description, String localization, PropertyMetaData[] properyMetaData) {
+        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+        Hashtable props = new Hashtable();
+        props.put(Constants.SERVICE_PID, factoryPid);
+        m_component
+            .setInterface(ManagedServiceFactory.class.getName(), props)
+            .setImplementation(new MetaTypeAdapterImpl(factoryPid, update, propagate,
+                bctx, logger, heading, description,
+                localization, properyMetaData));
+    }
+    
+    /**
+     * Creates, updates, or removes a service, when a ConfigAdmin factory configuration is created/updated or deleted.
+     */
+    public class AdapterImpl extends AbstractDecorator implements ManagedServiceFactory {        
+        // Our Managed Service Factory PID
+        protected String m_factoryPid;
+        
+        // The adapter "update" method used to provide the configuration
+        protected String m_update;
+
+        // Tells if the CM config must be propagated along with the adapter service properties
+        protected boolean m_propagate;
+
+        /**
+         * Creates a new CM factory configuration adapter.
+         * 
+         * @param factoryPid
+         * @param updateMethod
+         * @param adapterInterface
+         * @param adapterImplementation
+         * @param adapterProperties
+         * @param propagate
+         */
+        public AdapterImpl(String factoryPid, String updateMethod, boolean propagate) {
+            m_factoryPid = factoryPid;
+            m_update = updateMethod;
+            m_propagate = propagate;
+        }
+
+        /**
+         * Returns the managed service factory name.
+         */
+        public String getName() {
+            return m_factoryPid;
+        }
+      
+        /**
+         * Method called from our superclass, when we need to create a service.
+         */
+        public Component createService(Object[] properties) {
+            Dictionary settings = (Dictionary) properties[0];     
+            Component newService = m_manager.createComponent();        
+            Object impl = null;
+            
+            try {
+                if (m_serviceImpl != null) {
+                    impl = (m_serviceImpl instanceof Class) ? ((Class) m_serviceImpl).newInstance() : m_serviceImpl;
+                }
+                else {
+                    impl = instantiateFromFactory(m_factory, m_factoryCreateMethod);
+                }
+                InvocationUtil.invokeCallbackMethod(impl, m_update, 
+                    new Class[][] {{ Dictionary.class }, {}}, 
+                    new Object[][] {{ settings }, {}});
+            }
+            
+            catch (Throwable t) {
+               handleException(t);
+            }
+
+            // Merge adapter service properties, with CM settings 
+            Dictionary serviceProperties = getServiceProperties(settings);
+            newService.setInterface(m_serviceInterfaces, serviceProperties);
+            newService.setImplementation(impl);
+            newService.setComposition(m_compositionInstance, m_compositionMethod); // if not set, no effect
+            newService.setCallbacks(m_callbackObject, m_init, m_start, m_stop, m_destroy); // if not set, no effect
+            configureAutoConfigState(newService, m_component);
+            
+            List dependencies = m_component.getDependencies();
+            for (int i = 0; i < dependencies.size(); i++) {
+                newService.add(((Dependency) dependencies.get(i)).createCopy());
+            }
+            
+            for (int i = 0; i < m_stateListeners.size(); i ++) {
+                newService.addStateListener((ComponentStateListener) m_stateListeners.get(i));
+            }
+            
+            return newService;
+        }
+
+        /**
+         * Method called from our superclass, when we need to update a Service, because 
+         * the configuration has changed.
+         */
+        public void updateService(Object[] properties) {
+            Dictionary cmSettings = (Dictionary) properties[0];
+            Component service = (Component) properties[1];
+            Object impl = service.getService();
+           
+            try {
+                InvocationUtil.invokeCallbackMethod(impl, m_update, 
+                    new Class[][] {{ Dictionary.class }, {}}, 
+                    new Object[][] {{ cmSettings }, {}});
+                if (m_serviceInterfaces != null && m_propagate == true) {
+                    Dictionary serviceProperties = getServiceProperties(cmSettings);
+                    service.setServiceProperties(serviceProperties);
+                }
+            }
+            
+            catch (Throwable t) {
+                handleException(t);
+            }
+        }   
+
+        /**
+         * Merge CM factory configuration setting with the adapter service properties. The private CM factory configuration 
+         * settings are ignored. A CM factory configuration property is private if its name starts with a dot (".").
+         * 
+         * @param adapterProperties
+         * @param settings
+         * @return
+         */
+        private Dictionary getServiceProperties(Dictionary settings) {
+            Dictionary props = new Hashtable();
+            
+            // Add adapter Service Properties
+            if (m_serviceProperties != null) {
+                Enumeration keys = m_serviceProperties.keys();
+                while (keys.hasMoreElements()) {
+                    Object key = keys.nextElement();
+                    Object val = m_serviceProperties.get(key);
+                    props.put(key, val);
+                }
+            }
+
+            if (m_propagate) {
+                // Add CM setting into adapter service properties.
+                // (CM setting will override existing adapter service properties).
+                Enumeration keys = settings.keys();
+                while (keys.hasMoreElements()) {
+                    Object key = keys.nextElement();
+                    if (! key.toString().startsWith(".")) {
+                        // public properties are propagated
+                        Object val = settings.get(key);
+                        props.put(key, val);
+                    }
+                }
+            }
+
+            
+            return props;
+        }
+    
+        private Object instantiateFromFactory(Object mFactory, String mFactoryCreateMethod) {
+            Object factory = null;
+            if (m_factory instanceof Class) {
+                try {
+                    factory = createInstance((Class) m_factory);
+                }
+                catch (Throwable t) {
+                    handleException(t);
+                }
+            }
+            else {
+                factory = m_factory;
+            }
+
+            try {
+                return InvocationUtil.invokeMethod(factory, factory.getClass(), m_factoryCreateMethod, new Class[][] { {} }, new Object[][] { {} }, false);
+            }
+            catch (Throwable t) {
+                handleException(t);
+                return null;
+            }
+        }
+
+        private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException {
+            Constructor constructor = clazz.getConstructor(new Class[] {});
+            constructor.setAccessible(true);
+            return clazz.newInstance();
+        }
+    
+        private void handleException(Throwable t) {
+            if (t instanceof InvocationTargetException) {
+                // Our super class will check if the target exception is itself a ConfigurationException.
+                // In this case, it will simply re-thrown.
+                throw new RuntimeException(((InvocationTargetException) t).getTargetException());
+            }
+            else if (t instanceof RuntimeException) {
+                throw (RuntimeException) t;
+            }
+            else {
+                throw new RuntimeException(t);
+            }
+        }
+    }
+
+    
+    /**
+     * Extends AdapterImpl for MetaType support.
+     */
+    class MetaTypeAdapterImpl extends AdapterImpl implements MetaTypeProvider {
+        // Our MetaType Provider for describing our properties metadata
+        private MetaTypeProviderImpl m_metaType;
+        
+        public MetaTypeAdapterImpl(String factoryPid, String updateMethod, boolean propagate,
+                                   BundleContext bctx, Logger logger, String heading, 
+                                   String description, String localization,
+                                   PropertyMetaData[] properyMetaData) {
+            super(factoryPid, updateMethod, propagate);
+            m_metaType = new MetaTypeProviderImpl(m_factoryPid, bctx, logger, null, this);
+            m_metaType.setName(heading);
+            m_metaType.setDescription(description);
+            if (localization != null) {
+                m_metaType.setLocalization(localization);
+            }
+            for (int i = 0; i < properyMetaData.length; i++) {
+                m_metaType.add(properyMetaData[i]);
+            }
+        }
+        
+        public String[] getLocales() {
+            return m_metaType.getLocales();
+        }
+
+        public ObjectClassDefinition getObjectClassDefinition(String id, String locale) {
+            return m_metaType.getObjectClassDefinition(id, locale);
+        }
+    }    
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,276 @@
+/*
+ * 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.dm.impl;
+
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ComponentDeclaration;
+import org.apache.felix.dm.ComponentDependencyDeclaration;
+import org.apache.felix.dm.ComponentStateListener;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * This class allows to filter a Component interface. All Aspect/Adapters extend this class
+ * in order to add functionality to the default Component implementation.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FilterService implements Component, ComponentDeclaration {
+    protected ComponentImpl m_component;
+    protected List m_stateListeners = new ArrayList();
+    protected String m_init = "init";
+    protected String m_start = "start";
+    protected String m_stop = "stop";
+    protected String m_destroy = "destroy";
+    protected Object m_callbackObject;
+    protected Object m_compositionInstance;
+    protected String m_compositionMethod;
+    protected String[] m_serviceInterfaces;
+    protected Object m_serviceImpl;
+    protected Object m_factory;
+    protected String m_factoryCreateMethod;
+    protected Dictionary m_serviceProperties;
+
+    public FilterService(Component service) {
+        m_component = (ComponentImpl) service;
+    }
+
+    public Component add(Dependency dependency) {
+        m_component.add(dependency);
+        // Add the dependency (if optional) to all already instantiated services.
+        // If the dependency is required, our internal service will be stopped/restarted, so in this case
+        // we have nothing to do.
+        if (! dependency.isRequired()) {
+            AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+            if (ad != null)
+            {
+                ad.addDependency(dependency);
+            }
+        }
+        return this;
+    }
+
+    public Component add(List dependencies) {
+        m_component.add(dependencies);
+        // Add the dependencies to all already instantiated services.
+        // If one dependency from the list is required, we have nothing to do, since our internal
+        // service will be stopped/restarted.
+        Iterator it = dependencies.iterator();
+        while (it.hasNext()) {
+            if (((Dependency) it.next()).isRequired()) {
+                return this;
+            }
+        }
+        // Ok, the list contains no required dependencies: add optionals dependencies in already instantiated
+        // services.
+        AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+        if (ad != null) {
+            ad.addDependencies(dependencies);
+        }
+        return this;
+    }
+
+    public void addStateListener(ComponentStateListener listener) {
+        synchronized (this) {
+            m_stateListeners.add(listener);
+        }
+        // Add the listener to all already instantiated services.
+        AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+        if (ad != null) {
+            ad.addStateListener(listener);
+        }
+    }
+
+    public List getDependencies() {
+        return m_component.getDependencies();
+    }
+
+    public Object getService() {
+        return m_component.getService();
+    }
+
+    public synchronized Dictionary getServiceProperties() {
+        return m_serviceProperties;
+    }
+
+    public ServiceRegistration getServiceRegistration() {
+        return m_component.getServiceRegistration();
+    }
+
+    public Component remove(Dependency dependency) {
+        m_component.remove(dependency);
+        // Remove the dependency (if optional) from all already instantiated services.
+        // If the dependency is required, our internal service will be stopped, so in this case
+        // we have nothing to do.
+        if (!dependency.isRequired())
+        {
+            AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+            if (ad != null)
+            {
+                ad.removeDependency(dependency);
+            }
+        }
+        return this;
+    }
+
+    public void removeStateListener(ComponentStateListener listener) {
+        synchronized (this) {
+            m_stateListeners.remove(listener);
+        }
+        // Remove the listener from all already instantiated services.
+        AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+        if (ad != null) {
+            ad.removeStateListener(listener);
+        }
+    }
+
+    public synchronized Component setCallbacks(Object instance, String init, String start, String stop, String destroy) {
+        m_component.ensureNotActive();
+        m_callbackObject = instance;
+        m_init = init;
+        m_start = start;
+        m_stop = stop;
+        m_destroy = destroy;
+        return this;
+    }
+
+    public Component setCallbacks(String init, String start, String stop, String destroy) {
+        setCallbacks(null, init, start, stop, destroy);
+        return this;
+    }
+
+    public synchronized Component setComposition(Object instance, String getMethod) {
+        m_component.ensureNotActive();
+        m_compositionInstance = instance;
+        m_compositionMethod = getMethod;
+        return this;
+    }
+
+    public synchronized Component setComposition(String getMethod) {
+        m_component.ensureNotActive();
+        m_compositionMethod = getMethod;
+        return this;
+    }
+
+    public synchronized Component setFactory(Object factory, String createMethod) {
+        m_component.ensureNotActive();
+        m_factory = factory;
+        m_factoryCreateMethod = createMethod;
+        return this;
+    }
+
+    public Component setFactory(String createMethod) {
+        return setFactory(null, createMethod);
+    }
+
+    public synchronized Component setImplementation(Object implementation) {
+        m_component.ensureNotActive();
+        m_serviceImpl = implementation;
+        return this;
+    }
+
+    public Component setInterface(String serviceName, Dictionary properties) {
+        return setInterface(new String[] { serviceName }, properties);
+    }
+
+    public synchronized Component setInterface(String[] serviceInterfaces, Dictionary properties) {
+        m_component.ensureNotActive();
+        if (serviceInterfaces != null) {
+            m_serviceInterfaces = new String[serviceInterfaces.length];
+            System.arraycopy(serviceInterfaces, 0, m_serviceInterfaces, 0, serviceInterfaces.length);
+            m_serviceProperties = properties;
+        }
+        return this;
+    }
+
+    public Component setServiceProperties(Dictionary serviceProperties) {
+        synchronized (this) {
+            m_serviceProperties = serviceProperties;
+        }
+        // Set the properties to all already instantiated services.
+        if (serviceProperties != null) {
+            AbstractDecorator ad = (AbstractDecorator) m_component.getService();
+            if (ad != null) {
+                ad.setServiceProperties(serviceProperties);
+            }
+        }
+        return this;
+    }
+
+    public void start() {
+        m_component.start();
+    }
+
+    public void stop() {
+        m_component.stop();
+    }
+    
+    public void invokeCallbackMethod(Object[] instances, String methodName, Class[][] signatures, Object[][] parameters) {
+        m_component.invokeCallbackMethod(instances, methodName, signatures, parameters);
+    }
+    
+    public Object[] getCompositionInstances() {
+        return m_component.getCompositionInstances();
+    }
+    
+    public DependencyManager getDependencyManager() {
+        return m_component.getDependencyManager();
+    }
+
+    public Component setAutoConfig(Class clazz, boolean autoConfig) {
+        m_component.setAutoConfig(clazz, autoConfig);
+        return this;
+    }
+
+    public Component setAutoConfig(Class clazz, String instanceName) {
+        m_component.setAutoConfig(clazz, instanceName);
+        return this;
+    }
+    
+    public boolean getAutoConfig(Class clazz) {
+        return m_component.getAutoConfig(clazz);
+    }
+    
+    public String getAutoConfigInstance(Class clazz) {
+        return m_component.getAutoConfigInstance(clazz);
+    }
+
+    public ComponentDependencyDeclaration[] getComponentDependencies() {
+        return m_component.getComponentDependencies();
+    }
+
+    public String getName() {
+        return m_component.getName();
+    }
+
+    public int getState() {
+        return m_component.getState();
+    }
+
+    public BundleContext getBundleContext() {
+        return m_component.getBundleContext();
+    };
+}
\ No newline at end of file

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,228 @@
+/*
+ * 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.dm.impl;
+
+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, which is also why it does not
+ * actually implement <code>LogService</code>. 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() {
+        try {
+            // add a service listener for log services, carefully avoiding any code dependency on it
+            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

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ResourceAdapterServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,134 @@
+/*
+ * 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.dm.impl;
+
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ComponentStateListener;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.ResourceDependency;
+
+/**
+ * Resource adapter service implementation. This class extends the FilterService in order to catch
+ * some Service methods for configuring actual resource adapter service implementation.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ResourceAdapterServiceImpl extends FilterService {
+    private Object m_callbackInstance = null;
+    private String m_callbackChanged = "changed";
+    private String m_callbackAdded = "setResource";
+    
+    /**
+     * Creates a new Resource Adapter Service implementation.
+     * @param dm the dependency manager used to create our internal adapter service
+     */
+    public ResourceAdapterServiceImpl(DependencyManager dm, String resourceFilter, boolean propagate, Object callbackInstance, String callbackSet, String callbackChanged) {
+        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+        m_callbackInstance = callbackInstance;
+        m_callbackAdded = callbackSet;
+        m_callbackChanged = callbackChanged;
+        m_component.setImplementation(new ResourceAdapterImpl(propagate))
+            .add(dm.createResourceDependency()
+                 .setFilter(resourceFilter)
+                 .setAutoConfig(false)
+                 .setCallbacks("added", "removed"));
+    }
+    
+    public ResourceAdapterServiceImpl(DependencyManager dm, String resourceFilter, Object propagateCallbackInstance, String propagateCallbackMethod, Object callbackInstance, String callbackSet, String callbackChanged) {
+        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+        m_callbackInstance = callbackInstance;
+        m_callbackAdded = callbackSet;
+        m_callbackChanged = callbackChanged;
+        m_component.setImplementation(new ResourceAdapterImpl(propagateCallbackInstance, propagateCallbackMethod))
+            .add(dm.createResourceDependency()
+                 .setFilter(resourceFilter)
+                 .setAutoConfig(false)
+                 .setCallbacks("added", "removed"));
+    }   
+
+    public class ResourceAdapterImpl extends AbstractDecorator {
+        private final boolean m_propagate;
+        private final Object m_propagateCallbackInstance;
+        private final String m_propagateCallbackMethod;
+
+        public ResourceAdapterImpl(boolean propagate) {
+            this(propagate, null, null);
+        }
+
+        public ResourceAdapterImpl(Object propagateCallbackInstance, String propagateCallbackMethod) {
+            this(true, propagateCallbackInstance, propagateCallbackMethod);
+        }
+        
+        private ResourceAdapterImpl(boolean propagate, Object propagateCallbackInstance, String propagateCallbackMethod) {
+            m_propagate = propagate;
+            m_propagateCallbackInstance = propagateCallbackInstance;
+            m_propagateCallbackMethod = propagateCallbackMethod;
+        }
+
+        public Component createService(Object[] properties) {
+            URL resource = (URL) properties[0]; 
+            Properties props = new Properties();
+            if (m_serviceProperties != null) {
+                Enumeration e = m_serviceProperties.keys();
+                while (e.hasMoreElements()) {
+                    Object key = e.nextElement();
+                    props.put(key, m_serviceProperties.get(key));
+                }
+            }
+            List dependencies = m_component.getDependencies();
+            // the first dependency is always the dependency on the resource, which
+            // will be replaced with a more specific dependency below
+            dependencies.remove(0);
+            ResourceDependency resourceDependency = m_manager.createResourceDependency()
+                 .setResource(resource)
+                 .setCallbacks(m_callbackInstance, m_callbackAdded, m_callbackChanged, null)
+                 .setAutoConfig(m_callbackAdded == null)
+                 .setRequired(true);
+            if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+                resourceDependency.setPropagate(m_propagateCallbackInstance, m_propagateCallbackMethod);
+            } else {
+                resourceDependency.setPropagate(m_propagate);
+            }
+            Component service = m_manager.createComponent()
+                .setInterface(m_serviceInterfaces, props)
+                .setImplementation(m_serviceImpl)
+                .setFactory(m_factory, m_factoryCreateMethod) // if not set, no effect
+                .setComposition(m_compositionInstance, m_compositionMethod) // if not set, no effect
+                .setCallbacks(m_callbackObject, m_init, m_start, m_stop, m_destroy) // if not set, no effect
+                .add(resourceDependency);
+            
+            configureAutoConfigState(service, m_component);
+
+            for (int i = 0; i < dependencies.size(); i++) {
+                service.add(((Dependency) dependencies.get(i)).createCopy());
+            }
+
+            for (int i = 0; i < m_stateListeners.size(); i ++) {
+                service.addStateListener((ComponentStateListener) m_stateListeners.get(i));
+            }
+            return service;
+        }
+    }
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/SerialExecutor.java Fri Feb 24 10:47:49 2012
@@ -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.dm.impl;
+
+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();
+        }
+    }
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceRegistrationImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceRegistrationImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceRegistrationImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ServiceRegistrationImpl.java Fri Feb 24 10:47:49 2012
@@ -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.dm.impl;
+
+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);
+	}
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/State.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/State.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/State.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/State.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,133 @@
+/*
+ * 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.dm.impl;
+
+import java.util.List;
+
+import org.apache.felix.dm.Dependency;
+
+/**
+ * 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", "bound", "waiting for required (instantiated)" };
+    private static final int INACTIVE = 1;
+    private static final int WAITING_FOR_REQUIRED = 2;
+    private static final int TRACKING_OPTIONAL = 3;
+    private static final int BOUND = 4;
+    private static final int WAITING_FOR_REQUIRED_INSTANTIATED = 5;
+    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, boolean isInstantiated, boolean isBound /* unused? */) {
+        m_deps = deps;
+        // only bother calculating dependencies if we're active
+        if (isActive) {
+            boolean allRequiredAvailable = true;
+            boolean keepInstanceAround = isInstantiated;
+            for (int i = 0; i < deps.size(); i++) {
+                Dependency dep = (Dependency) deps.get(i);
+                if (dep.isRequired()) {
+                    if (!dep.isAvailable()) {
+                        allRequiredAvailable = false;
+                        if (!dep.isInstanceBound()) {
+                            keepInstanceAround = false;
+                        }
+                    }
+                }
+            }
+            if (allRequiredAvailable) {
+                if (isInstantiated) {
+                    m_state = BOUND;
+                }
+                else {
+                    m_state = TRACKING_OPTIONAL;
+                }
+            }
+            else {
+                if (keepInstanceAround) {
+                    m_state = WAITING_FOR_REQUIRED_INSTANTIATED;
+                }
+                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 boolean isBound() {
+        return m_state == BOUND;
+    }
+    
+    public boolean isAllRequiredAvailable() {
+        return isTrackingOptional() || isBound();
+    }
+    
+    public boolean isWaitingForRequiredInstantiated() {
+        return m_state == WAITING_FOR_REQUIRED_INSTANTIATED;
+    }
+    
+    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++) {
+                if (i == 0) {
+                    buf.append("|");
+                }
+                Dependency dep = (Dependency) deps.get(i);
+                buf.append("(" + (dep.isRequired() ? "Req " : "   ") + (dep.isAvailable() ? "Avl " : "    ") + (dep.isInstanceBound() ? "InB " : "    ") + (dep.isPropagated() ? "Prp " : "    ") + dep + ")");
+            }
+            buf.append("]");
+            m_stringValue = buf.toString();
+        }
+        return m_stringValue;
+    }
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/BundleDependencyImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,501 @@
+/*
+ * 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.dm.impl.dependencies;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import org.apache.felix.dm.BundleDependency;
+import org.apache.felix.dm.ComponentDependencyDeclaration;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyService;
+import org.apache.felix.dm.InvocationUtil;
+import org.apache.felix.dm.impl.DefaultNullObject;
+import org.apache.felix.dm.impl.Logger;
+import org.apache.felix.dm.tracker.BundleTracker;
+import org.apache.felix.dm.tracker.BundleTrackerCustomizer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.log.LogService;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BundleDependencyImpl extends DependencyBase implements BundleDependency, BundleTrackerCustomizer, ComponentDependencyDeclaration {
+	private final BundleContext m_context;
+	private BundleTracker m_tracker;
+	private int m_stateMask = Bundle.INSTALLED | Bundle.RESOLVED | Bundle.ACTIVE;
+	private List m_services = new ArrayList();
+	private boolean m_isAvailable;
+    private Object m_callbackInstance;
+    private String m_callbackAdded;
+    private String m_callbackChanged;
+    private String m_callbackRemoved;
+    private boolean m_autoConfig;
+	private Bundle m_bundleInstance;
+	private Filter m_filter;
+	private long m_bundleId = -1;
+	private String m_autoConfigInstance;
+    private Object m_nullObject;
+    private boolean m_autoConfigInvoked;
+    private boolean m_propagate;
+    private Object m_propagateCallbackInstance;
+    private String m_propagateCallbackMethod;
+
+    public BundleDependencyImpl(BundleContext context, Logger logger) {
+        super(logger);
+		m_context = context;
+		m_autoConfig = true;
+	}
+    
+    public BundleDependencyImpl(BundleDependencyImpl prototype) {
+        super(prototype);
+        m_context = prototype.m_context;
+        m_autoConfig = prototype.m_autoConfig;
+        m_stateMask = prototype.m_stateMask;
+        m_nullObject = prototype.m_nullObject;
+        m_bundleInstance = prototype.m_bundleInstance;
+        m_filter = prototype.m_filter;
+        m_bundleId = prototype.m_bundleId;
+        m_propagate = prototype.m_propagate;
+        m_callbackInstance = prototype.m_callbackInstance;
+        m_callbackAdded = prototype.m_callbackAdded;
+        m_callbackChanged = prototype.m_callbackChanged;
+        m_callbackRemoved = prototype.m_callbackRemoved;
+        m_autoConfigInstance = prototype.m_autoConfigInstance;
+    }
+    
+    public Dependency createCopy() {
+        return new BundleDependencyImpl(this);
+    }
+
+    public BundleDependency setInstanceBound(boolean isInstanceBound) {
+        setIsInstanceBound(isInstanceBound);
+        return this;
+    }
+    
+	public synchronized boolean isAvailable() {
+        return m_isAvailable;
+    }
+
+    public void start(DependencyService service) {
+        boolean needsStarting = false;
+		synchronized (this) {
+		    m_services.add(service);
+		    if (!m_isStarted) {
+    			m_tracker = new BundleTracker(m_context, m_stateMask, this);
+    			m_isStarted = true;
+    			needsStarting = true;
+		    }
+		}
+		if (needsStarting) {
+		    m_tracker.open();
+		}
+	}
+
+	public void stop(DependencyService service) {
+	    boolean needsStopping = false;
+        synchronized (this) {
+            if (m_services.size() == 1 && m_services.contains(service)) {
+                m_isStarted = false;
+                needsStopping = true;
+            }
+        }
+        if (needsStopping) {
+            m_tracker.close();
+            m_tracker = null;
+            m_services.remove(service);
+        }            
+	}
+
+	public String getName() {
+        StringBuilder sb = new StringBuilder();
+        if ((m_stateMask & Bundle.ACTIVE) != 0) {
+            sb.append("active ");
+        }
+        if ((m_stateMask & Bundle.INSTALLED) != 0) {
+            sb.append("installed ");
+        }
+        if ((m_stateMask & Bundle.RESOLVED) != 0) {
+            sb.append("resolved ");
+        }
+        if (m_filter != null) {
+            sb.append(m_filter.toString());
+        }
+        if (m_bundleId != -1) {
+            sb.append("bundle.id=" + m_bundleId);
+        }
+        return sb.toString();
+	}
+
+	public String getType() {
+		return "bundle";
+	}
+
+	public Object addingBundle(Bundle bundle, BundleEvent event) {
+		// if we don't like a bundle, we could reject it here by returning null
+		long bundleId = bundle.getBundleId();
+        if (m_bundleId >= 0 && m_bundleId != bundleId) {
+			return null;
+		}
+		Filter filter = m_filter;
+		if (filter != null) {
+			Dictionary headers = bundle.getHeaders();
+			if (!m_filter.match(headers)) {
+				return null;
+			}
+		}
+        return bundle;
+	}
+	
+	public void addedBundle(Bundle bundle, BundleEvent event, Object object) {
+	    boolean makeAvailable = makeAvailable();
+	    Object[] services = m_services.toArray();
+	    for (int i = 0; i < services.length; i++) {
+	        DependencyService ds = (DependencyService) services[i];
+	        if (makeAvailable) {
+	            ds.dependencyAvailable(this);
+	            if (!isRequired()) {
+	                invokeAdded(ds, bundle);
+	            }
+	        }
+	        else {
+	            ds.dependencyChanged(this);
+	            invokeAdded(ds, bundle);
+	        }
+	    }
+	}
+
+	public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {
+		Object[] services = m_services.toArray();
+        for (int i = 0; i < services.length; i++) {
+            DependencyService ds = (DependencyService) services[i];
+            ds.dependencyChanged(this);
+            if (ds.isRegistered()) {
+                invokeChanged(ds, bundle);
+            }
+        }
+	}
+
+	public void removedBundle(Bundle bundle, BundleEvent event, Object object) {
+		boolean makeUnavailable = makeUnavailable();
+        Object[] services = m_services.toArray();
+        for (int i = 0; i < services.length; i++) {
+            DependencyService ds = (DependencyService) services[i];
+            if (makeUnavailable) {
+                ds.dependencyUnavailable(this);
+                if (!isRequired()) {
+                    invokeRemoved(ds, bundle);
+                }
+            }
+            else {
+                ds.dependencyChanged(this);
+                invokeRemoved(ds, bundle);
+            }
+        }
+	}
+	
+    private synchronized boolean makeAvailable() {
+        if (!isAvailable()) {
+            m_isAvailable = true;
+            return true;
+        }
+        return false;
+    }
+    
+    private synchronized boolean makeUnavailable() {
+        if ((isAvailable()) && (m_tracker.getTrackingCount() == 0)) {
+            m_isAvailable = false;
+            return true;
+        }
+        return false;
+    }
+    
+    public void invokeAdded(DependencyService dependencyService, Bundle service) {
+        invoke(dependencyService, service, m_callbackAdded);
+    }
+
+    public void invokeChanged(DependencyService dependencyService, Bundle service) {
+        invoke(dependencyService, service, m_callbackChanged);
+    }
+    
+    public void invokeRemoved(DependencyService dependencyService, Bundle service) {
+        invoke(dependencyService, service, m_callbackRemoved);
+    }
+    
+    public void invoke(DependencyService dependencyService, Bundle service, String name) {
+        if (name != null) {
+            dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name,
+              new Class[][] {{Bundle.class}, {Object.class}, {}},
+              new Object[][] {{service}, {service}, {}}
+            );
+        }
+    }
+
+    private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
+        if (m_callbackInstance == null) {
+            return dependencyService.getCompositionInstances();
+        }
+        else {
+            return new Object[] { m_callbackInstance };
+        }
+    }
+    
+    /**
+     * 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 BundleDependency 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 BundleDependency 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 BundleDependency 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 BundleDependency setCallbacks(Object instance, String added, String changed, String removed) {
+        ensureNotActive();
+        // if at least one valid callback is specified, we turn off auto configuration
+        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 BundleDependency setAutoConfig(boolean autoConfig) {
+        ensureNotActive();
+        m_autoConfig = autoConfig;
+        m_autoConfigInvoked = true;
+        return this;
+    }
+
+    public synchronized BundleDependency setAutoConfig(String instanceName) {
+        ensureNotActive();
+        m_autoConfig = (instanceName != null);
+        m_autoConfigInstance = instanceName;
+        m_autoConfigInvoked = true;
+        return this;
+    }
+    
+    public synchronized BundleDependency setRequired(boolean required) {
+        ensureNotActive();
+        setIsRequired(required);
+        return this;
+    }
+    
+	public BundleDependency setBundle(Bundle bundle) {
+		m_bundleId = bundle.getBundleId();
+		return this;
+	}
+
+	public BundleDependency setFilter(String filter) throws IllegalArgumentException {
+		if (filter != null) {
+			try {
+				m_filter = m_context.createFilter(filter);
+			} 
+			catch (InvalidSyntaxException e) {
+				throw new IllegalArgumentException(e.getMessage());
+			}
+		}
+		return this;
+	}
+	
+	public BundleDependency setStateMask(int mask) {
+		m_stateMask = mask;
+		return this;
+	}
+	
+    public synchronized boolean isAutoConfig() {
+        return m_autoConfig;
+    }
+
+    public Bundle getBundle() {
+    	Bundle[] bundles = m_tracker.getBundles();
+    	if (bundles != null && bundles.length > 0) {
+    		return bundles[0];
+    	}
+    	return null;
+    }
+
+    public Object getAutoConfigInstance() {
+        return lookupBundle();
+    }
+
+    public Bundle lookupBundle() {
+        Bundle service = null;
+        if (m_isStarted) {
+            service = getBundle();
+        }
+        else {
+            Bundle[] bundles = m_context.getBundles();
+            for (int i = 0; i < bundles.length; i++) {
+                if ((bundles[i].getState() & m_stateMask) > 0) {
+                    Filter filter = m_filter;
+                    if (filter == null) {
+                        service = bundles[i];
+                        break;
+                    }
+                    else if (filter.match(bundles[i].getHeaders())) {
+                        service = bundles[i];
+                        break;
+                    }
+                }
+            }
+        }
+        if (service == null && isAutoConfig()) {
+            // TODO does it make sense to add support for custom bundle impls?
+//            service = getDefaultImplementation();
+            if (service == null) {
+                service = getNullObject();
+            }
+        }
+        return service;
+    }
+
+    private Bundle getNullObject() {
+        if (m_nullObject == null) {
+            try {
+                m_nullObject = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { Bundle.class }, new DefaultNullObject()); 
+            }
+            catch (Exception e) {
+                m_logger.log(Logger.LOG_ERROR, "Could not create null object for Bundle.", e);
+            }
+        }
+        return (Bundle) m_nullObject;
+    }
+    
+    public String getAutoConfigName() {
+        return m_autoConfigInstance;
+    }
+
+    public Class getAutoConfigType() {
+        return Bundle.class;
+    }
+
+    public void invokeAdded(DependencyService service) {
+        // we remember these for future reference, needed for required service callbacks
+        m_bundleInstance = lookupBundle();
+        invokeAdded(service, m_bundleInstance);
+    }
+
+    public void invokeRemoved(DependencyService service) {
+        invokeRemoved(service, m_bundleInstance);
+        m_bundleInstance = null;
+    }
+    
+    public BundleDependency setPropagate(boolean propagate) {
+        ensureNotActive();
+        m_propagate = propagate;
+        return this;
+    }
+    
+    public BundleDependency setPropagate(Object instance, String method) {
+        setPropagate(instance != null && method != null);
+        m_propagateCallbackInstance = instance;
+        m_propagateCallbackMethod = method;
+        return this;
+    }
+    
+    public Dictionary getProperties() {
+        Bundle bundle = lookupBundle();
+        if (bundle != null) {
+            if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+                try {
+                    return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ Bundle.class }}, new Object[][] {{ bundle }});
+                }
+                catch (InvocationTargetException e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
+                }
+                catch (Exception e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
+                }
+                throw new IllegalStateException("Could not invoke callback");
+            }
+            else {
+                return bundle.getHeaders();
+            }
+        }
+        else {
+            throw new IllegalStateException("cannot find bundle");
+        }
+    }
+
+    public boolean isPropagated() {
+        return m_propagate;
+    }
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/dependencies/ConfigurationDependencyImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,401 @@
+/*
+ * 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.dm.impl.dependencies;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.felix.dm.ComponentDependencyDeclaration;
+import org.apache.felix.dm.ConfigurationDependency;
+import org.apache.felix.dm.Dependency;
+import org.apache.felix.dm.DependencyActivation;
+import org.apache.felix.dm.DependencyService;
+import org.apache.felix.dm.InvocationUtil;
+import org.apache.felix.dm.PropertyMetaData;
+import org.apache.felix.dm.impl.Logger;
+import org.apache.felix.dm.impl.metatype.MetaTypeProviderImpl;
+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;
+import org.osgi.service.log.LogService;
+
+/**
+ * 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 ConfigurationDependencyImpl extends DependencyBase implements ConfigurationDependency, ManagedService, ComponentDependencyDeclaration, DependencyActivation {
+	private BundleContext m_context;
+	private String m_pid;
+	private ServiceRegistration m_registration;
+    protected List m_services = new ArrayList();
+	private Dictionary m_settings;
+    private String m_callback;
+	private final Set m_updateInvokedCache = new HashSet();
+    private MetaTypeProviderImpl m_metaType;
+    private boolean m_propagate;
+    private Object m_propagateCallbackInstance;
+    private String m_propagateCallbackMethod;
+	
+	public ConfigurationDependencyImpl(BundleContext context, Logger logger) {
+	    super(logger);
+		m_context = context;
+	}
+	
+	public ConfigurationDependencyImpl(ConfigurationDependencyImpl prototype) {
+	    super(prototype);
+	    m_context = prototype.m_context;
+	    m_pid = prototype.m_pid;
+	    m_propagate = prototype.m_propagate;
+	    m_callback = prototype.m_callback;
+	}
+	
+	public Dependency createCopy() {
+	    return new ConfigurationDependencyImpl(this);
+	}
+	
+	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 ConfigurationDependency setInstanceBound(boolean isInstanceBound) {
+        setIsInstanceBound(isInstanceBound);
+        return this;
+    }
+
+	
+	public Dictionary getConfiguration() {
+		return m_settings;
+	}
+	
+	public void start(DependencyService service) {
+	    boolean needsStarting = false;
+	    synchronized (this) {
+	        m_services.add(service);
+	        if (!m_isStarted) {
+	            m_isStarted = true;
+                needsStarting = true;
+	        }
+	    }
+	    if (needsStarting) {
+	        Properties props = new Properties();
+	        props.put(Constants.SERVICE_PID, m_pid);
+	        ManagedService ms = this;
+	        if (m_metaType != null) {
+	            ms = m_metaType;
+	        }
+	        m_registration = m_context.registerService(ManagedService.class.getName(), ms, props);
+	    }
+	}
+
+	public void stop(DependencyService service) {
+        boolean needsStopping = false;
+        synchronized (this) {
+            if (m_services.size() == 1 && m_services.contains(service)) {
+                m_isStarted = false;
+                needsStopping = true;
+            }
+        }
+        if (needsStopping) {
+            m_registration.unregister();
+            m_registration = null;
+            m_services.remove(service);
+        }
+	}
+
+    public ConfigurationDependency setCallback(String callback) {
+		m_callback = callback;
+		return this;
+	}
+
+	public void updated(Dictionary settings) throws ConfigurationException {
+	    synchronized (m_updateInvokedCache) {
+	        m_updateInvokedCache.clear();
+	    }
+	    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;
+	    }
+
+	    Object[] services = m_services.toArray();
+        for (int i = 0; i < services.length; i++) {
+            DependencyService ds = (DependencyService) services[i];
+            // if non-null settings come in, we have to instantiate the service and
+            // apply these settings
+            ds.initService();
+            Object service = ds.getService();
+
+            if (service != null) {
+                invokeUpdate(ds, service, settings);
+            }
+            else {
+                m_logger.log(Logger.LOG_ERROR, "Service " + ds + " with configuration dependency " + this + " could not be instantiated.");
+                return;
+            }
+        }
+
+		synchronized (this) {
+			m_settings = settings;
+		}
+		
+        for (int i = 0; i < services.length; i++) {
+            DependencyService ds = (DependencyService) services[i];
+            // If these settings did not cause a configuration exception, we determine if they have 
+            // caused the dependency state to change
+            if ((oldSettings == null) && (settings != null)) {
+                ds.dependencyAvailable(this);
+            }
+            if ((oldSettings != null) && (settings == null)) {
+                ds.dependencyUnavailable(this);
+            }
+            if ((oldSettings != null) && (settings != null)) {
+                ds.dependencyChanged(this);
+            }
+        }
+	}
+
+    public void invokeUpdate(DependencyService ds, Object service, Dictionary settings) throws ConfigurationException {
+        boolean wasAdded;
+        synchronized (m_updateInvokedCache) {
+            wasAdded = m_updateInvokedCache.add(ds);
+        }
+        if (wasAdded) {
+            String callback = (m_callback == null) ? "updated" : m_callback;
+            try {
+                // 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.
+                InvocationUtil.invokeCallbackMethod(service, callback, new Class[][] {{ Dictionary.class }}, 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 " + ds + " with " + this.toString() + " could not be updated", e.getTargetException());
+                }
+            }
+            catch (NoSuchMethodException e) {
+                // if the method does not exist, ignore it
+            }
+            catch (Throwable t) {
+                // wrap any other exception as a ConfigurationException.
+                throw new ConfigurationException(null, "Service " + ds + " with " + this.toString() + " could not be updated", t);
+            }
+        }
+    }
+
+	/**
+	 * 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_services != null && m_services.size() > 0) {
+	  	  throw new IllegalStateException("Cannot modify state while active.");
+	  	}
+    }
+    
+    public String toString() {
+    	return "ConfigurationDependency[" + m_pid + "]";
+    }
+
+    public String getName() {
+        return m_pid;
+    }
+
+    public String getType() {
+        return "configuration";
+    }
+
+    public Object getAutoConfigInstance() {
+        return getConfiguration();
+    }
+
+    public String getAutoConfigName() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Class getAutoConfigType() {
+        return Dictionary.class;
+    }
+
+    public void invokeAdded(DependencyService service) {
+        try {
+            invokeUpdate(service, service.getService(), getConfiguration());
+        }
+        catch (ConfigurationException e) {
+            // if this happens, it's definitely an inconsistency, since we
+            // asked the instance the same question before (if this is a
+            // valid configuration) and then it was
+            e.printStackTrace();
+        }
+    }
+
+    public void invokeRemoved(DependencyService service) {
+        synchronized (m_updateInvokedCache) {
+            m_updateInvokedCache.remove(service);
+        }
+    }
+
+    public boolean isAutoConfig() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public ConfigurationDependency setPropagate(Object instance, String method) {
+        setPropagate(instance != null && method != null);
+        m_propagateCallbackInstance = instance;
+        m_propagateCallbackMethod = method;
+        return this;
+    }
+    
+    public Dictionary getProperties() {
+        Dictionary config = getConfiguration();
+        if (config != null) {
+            if (m_propagateCallbackInstance != null && m_propagateCallbackMethod != null) {
+                try {
+                    return (Dictionary) InvocationUtil.invokeCallbackMethod(m_propagateCallbackInstance, m_propagateCallbackMethod, new Class[][] {{ Dictionary.class }, {}}, new Object[][] {{ config }, {}});
+                }
+                catch (InvocationTargetException e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while invoking callback method", e.getCause());
+                }
+                catch (Exception e) {
+                    m_logger.log(LogService.LOG_WARNING, "Exception while trying to invoke callback method", e);
+                }
+                throw new IllegalStateException("Could not invoke callback");
+            }
+            else {
+                return config;
+            }
+        }
+        else {
+            throw new IllegalStateException("cannot find configuration");
+        }
+    }
+    
+    public BundleContext getBundleContext() {
+        return m_context;
+    }
+    
+    public Logger getLogger() {
+        return m_logger;
+    }
+    
+    public ConfigurationDependency add(PropertyMetaData properties)
+    {
+        createMetaTypeImpl();
+        m_metaType.add(properties);
+       return this;
+    }
+
+    public ConfigurationDependency setDescription(String description)
+    {
+        createMetaTypeImpl();
+        m_metaType.setDescription(description);
+       return this;
+    }
+
+    public ConfigurationDependency setHeading(String heading)
+    {
+        createMetaTypeImpl();
+        m_metaType.setName(heading);
+       return this;
+    }
+    
+    public ConfigurationDependency setLocalization(String path)
+    {
+        createMetaTypeImpl();
+        m_metaType.setLocalization(path);
+        return this;
+    }
+    
+    private synchronized void createMetaTypeImpl() {
+        if (m_metaType == null) {
+            m_metaType = new MetaTypeProviderImpl(getName(), getBundleContext(), getLogger(), this, null);
+        }
+    }
+}