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 [3/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/AbstractDecorator.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AbstractDecorator.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,275 @@
+/*
+ * 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.Dictionary;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+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.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class AbstractDecorator  {
+    protected volatile DependencyManager m_manager;
+    private final Map m_services = new HashMap();
+    
+    public abstract Component createService(Object[] properties);
+    
+    /**
+     * Catches our DependencyManager handle from our component init method.
+     */
+    public void init(Component c) {
+        m_manager = c.getDependencyManager();
+    }
+    
+    /**
+     * Extra method, which may be used by sub-classes, when adaptee has changed.
+     * For now, it's only used by the FactoryConfigurationAdapterImpl class, 
+     * but it might also make sense to use this for Resource Adapters ...
+     */
+    public void updateService(Object[] properties) {
+        throw new NoSuchMethodError("Method updateService not implemented");
+    }
+    
+    /**
+     * Set some service properties to all already instantiated services.
+     */
+    public void setServiceProperties(Dictionary serviceProperties) {
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
+        }
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).setServiceProperties(serviceProperties);
+        }
+    }
+    
+    /**
+     * Remove a StateListener from all already instantiated services.
+     */
+    public void addStateListener(ComponentStateListener listener) {
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
+        }
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).addStateListener(listener);
+        }
+    }
+
+    /**
+     * Remove a StateListener from all already instantiated services.
+     */
+    public void removeStateListener(ComponentStateListener listener) {
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
+        }
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).removeStateListener(listener);
+        }
+    }
+    
+    /**
+     * Add a Dependency to all already instantiated services.
+     */
+    public void addDependency(Dependency d) {
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
+        }
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).add(d);
+        }
+    }
+    
+    /**
+     * Add a Dependency to all already instantiated services.
+     */
+    public void addDependencies(List dependencies) {
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
+        }
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).add(dependencies);
+        }
+    }
+
+    /**
+     * Remove a Dependency from all instantiated services.
+     */
+    public void removeDependency(Dependency d) {
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
+        }
+        for (int i = 0; i < components.length; i++) {
+            ((Component) components[i]).remove(d);
+        }
+    }
+    
+    // callbacks for FactoryConfigurationAdapterImpl
+    public void updated(String pid, Dictionary properties) throws ConfigurationException {
+        try {
+            Component service;
+            synchronized (m_services) {
+                service = (Component) m_services.get(pid);
+            }
+            if (service == null) { 
+                service = createService(new Object[] { properties });
+                synchronized (m_services) {
+                    m_services.put(pid, service);
+                }
+                m_manager.add(service);
+            }
+            else {
+                updateService(new Object[] { properties, service });
+            }
+        }
+        catch (Throwable t) {
+            if (t instanceof ConfigurationException) {
+                throw (ConfigurationException) t;
+            }
+            else if (t.getCause() instanceof ConfigurationException) {
+                throw (ConfigurationException) t.getCause();
+            }
+            else {
+                throw new ConfigurationException(null, "Could not create service for ManagedServiceFactory Pid " + pid, t);
+            }
+        }
+    }
+
+    public void deleted(String pid) {
+        Component service = null;
+        synchronized (m_services) {
+            service = (Component) m_services.remove(pid);
+        }
+        if (service != null) {
+            m_manager.remove(service);
+        }
+    }
+
+    // callbacks for resources
+    public void added(URL resource) {
+        Component newService = createService(new Object[] { resource });
+        synchronized (m_services) {
+            m_services.put(resource, newService);
+        }
+        m_manager.add(newService);
+    }
+
+    public void removed(URL resource) {
+        Component newService;
+        synchronized (m_services) {
+            newService = (Component) m_services.remove(resource);
+        }
+        if (newService == null) {
+            throw new IllegalStateException("Service should not be null here.");
+        }
+        m_manager.remove(newService);
+    }
+    
+    // callbacks for services
+    public void added(ServiceReference ref, Object service) {
+        Component newService = createService(new Object[] { ref, service });
+        synchronized (m_services) {
+            m_services.put(ref, newService);
+        }
+        m_manager.add(newService);
+    }
+    
+    public void removed(ServiceReference ref, Object service) {
+        Component newService;
+        synchronized (m_services) {
+            newService = (Component) m_services.remove(ref);
+        }
+        if (newService == null) {
+            throw new IllegalStateException("Service should not be null here.");
+        }
+        m_manager.remove(newService);
+    }
+    
+    public void swapped(ServiceReference oldRef, Object oldService, ServiceReference newRef, Object newService) {
+        synchronized (m_services) {
+        	Component service = (Component) m_services.remove(oldRef);
+        	m_services.put(newRef, service);
+        }
+    }
+    
+    // callbacks for bundles
+    public void added(Bundle bundle) {
+        Component newService = createService(new Object[] { bundle });
+        synchronized (m_services) {
+            m_services.put(bundle, newService);
+        }
+        m_manager.add(newService);
+    }
+    
+    public void removed(Bundle bundle) {
+        Component newService;
+        synchronized (m_services) {
+            newService = (Component) m_services.remove(bundle);
+        }
+        if (newService == null) {
+            throw new IllegalStateException("Service should not be null here.");
+        }
+        m_manager.remove(newService);
+    }
+      
+    public void stop() { 
+        Object[] components;
+        synchronized (m_services) {
+            components = m_services.values().toArray();
+            m_services.clear();
+        }
+        for (int i = 0; i < components.length; i++) {
+            m_manager.remove((Component) components[i]);
+        }
+    }    
+    
+    public void configureAutoConfigState(Component target, Component source) {
+        configureAutoConfigState(target, source, BundleContext.class);
+        configureAutoConfigState(target, source, ServiceRegistration.class);
+        configureAutoConfigState(target, source, DependencyManager.class);
+        configureAutoConfigState(target, source, Component.class);
+    }
+
+    private void configureAutoConfigState(Component target, Component source, Class clazz) {
+        String name = source.getAutoConfigInstance(clazz);
+        if (name != null) {
+            target.setAutoConfig(clazz, name);
+        }
+        else {
+            target.setAutoConfig(clazz, source.getAutoConfig(clazz));
+        }
+    }
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AdapterServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,143 @@
+/*
+ * 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.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.ServiceDependency;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * 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 AdapterServiceImpl extends FilterService {
+    /**
+     * Creates a new Adapter Service implementation.
+     * 
+     * @param dm the dependency manager used to create our internal adapter service
+     * @param adapteeInterface the service interface to apply the adapter to
+     * @param adapteeFilter the filter condition to use with the service interface
+     * @param add
+     * @param change
+     * @param remove
+     */
+    public AdapterServiceImpl(DependencyManager dm, Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove, String swap) {
+        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+        m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, add, change, remove, swap))
+                 .add(dm.createServiceDependency()
+                      .setService(adapteeInterface, adapteeFilter)
+                      .setAutoConfig(false)
+                      .setCallbacks("added", null, "removed", "swapped"));
+    }	
+	
+    public AdapterServiceImpl(DependencyManager dm, Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove) {
+        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+        m_component.setImplementation(new AdapterImpl(adapteeInterface, adapteeFilter, autoConfig, add, change, remove, null))
+                 .add(dm.createServiceDependency()
+                      .setService(adapteeInterface, adapteeFilter)
+                      .setAutoConfig(false)
+                      .setCallbacks("added", null, "removed", "swapped"));
+    }
+    
+    public class AdapterImpl extends AbstractDecorator {
+        private final Class m_adapteeInterface;
+        private final String m_adapteeFilter;
+        private final String m_add;
+        private final String m_change;
+        private final String m_remove;
+        private final String m_swap;
+        private final String m_autoConfig;
+        
+        public AdapterImpl(Class adapteeInterface, String adapteeFilter, String autoConfig, String add, String change, String remove, String swap) {
+            m_adapteeInterface = adapteeInterface;
+            m_adapteeFilter = adapteeFilter;
+            m_autoConfig = autoConfig;
+            m_add = add;
+            m_change = change;
+            m_swap = swap;
+            m_remove = remove;
+        }
+        
+        public Component createService(Object[] properties) {
+            ServiceReference ref = (ServiceReference) properties[0]; 
+            Properties props = new Properties();
+            String[] keys = ref.getPropertyKeys();
+            for (int i = 0; i < keys.length; i++) {
+                String key = keys[i];
+                if (key.equals(Constants.SERVICE_ID) || key.equals(Constants.SERVICE_RANKING) || key.equals(DependencyManager.ASPECT) || key.equals(Constants.OBJECTCLASS)) {
+                    // do not copy these
+                }
+                else {
+                    props.put(key, ref.getProperty(key));
+                }
+            }
+            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();
+            dependencies.remove(0);
+            ServiceDependency dependency = m_manager.createServiceDependency()
+            	 // create a dependency on both the service id we're adapting and possible aspects for this given service id
+            	 .setService(m_adapteeInterface, "(|(" + Constants.SERVICE_ID + "=" + ref.getProperty(Constants.SERVICE_ID) 
+            			 	+ ")(" + DependencyManager.ASPECT + "=" + ref.getProperty(Constants.SERVICE_ID) + "))")
+                 .setRequired(true);
+            if (m_autoConfig != null) {
+                dependency.setAutoConfig(m_autoConfig);
+            }
+            if (m_add != null || m_change != null || m_remove != null || m_swap != null) {
+                dependency.setCallbacks(m_add, m_change, m_remove, m_swap);
+            }
+            
+            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(dependency);
+            
+            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;
+        }
+        public String toString() {
+            return "Adapter for " + m_adapteeInterface + ((m_adapteeFilter != null) ? " with filter " + m_adapteeFilter : "");
+        }
+    }
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/AspectServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,166 @@
+/*
+ * 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.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.ServiceDependency;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Aspect Service implementation. This class extends the FilterService in order to catch
+ * some Service methods for configuring actual aspect service implementation.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AspectServiceImpl extends FilterService {
+    public AspectServiceImpl(DependencyManager dm, Class aspectInterface, String aspectFilter, int ranking, String autoConfig, String add, String change, String remove)
+    { 
+        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+        m_component.setImplementation(new AspectImpl(aspectInterface, aspectFilter, ranking, autoConfig, add, change, remove))
+             .add(dm.createServiceDependency()
+                  .setService(aspectInterface, createDependencyFilterForAspect(aspectFilter))
+                  .setAutoConfig(false)
+                  .setCallbacks("added", "removed"));
+    }
+
+    private String createDependencyFilterForAspect(String filter) {
+        // we only want to match services which are not themselves aspects
+        if (filter == null || filter.length() == 0) {
+            return "(!(" + DependencyManager.ASPECT + "=*))";
+        }
+        else {
+            return "(&(!(" + DependencyManager.ASPECT + "=*))" + filter + ")";
+        }        
+    }
+    
+    /**
+     * This class is the Aspect Implementation. It will create the actual Aspect Service, and
+     * will use the Aspect Service parameters provided by our enclosing class.
+     */
+    class AspectImpl extends AbstractDecorator {
+        private final Class m_aspectInterface; // the service decorated by this aspect
+        private final String m_aspectFilter; // the service filter decorated by this aspect
+        private final int m_ranking; // the aspect ranking
+        private final String m_autoConfig; // the aspect impl field name where to inject decorated service
+        private final String m_add;
+        private final String m_change;
+        private final String m_remove;
+      
+        public AspectImpl(Class aspectInterface, String aspectFilter, int ranking, String autoConfig, String add, String change, String remove) {
+            m_aspectInterface = aspectInterface;
+            m_aspectFilter = aspectFilter;
+            m_ranking = ranking;
+            m_autoConfig = autoConfig;
+            m_add = add;
+            m_change = change;
+            m_remove = remove;
+        }
+        
+        public Component createService(Object[] params) {
+            List dependencies = m_component.getDependencies();
+            // remove our internal dependency
+            dependencies.remove(0);
+            // replace it with one that points to the specific service that just was passed in
+            Properties serviceProperties = getServiceProperties(params);
+            String[] serviceInterfaces = getServiceInterfaces();
+            ServiceReference ref = (ServiceReference) params[0];
+            ServiceDependency dependency = m_manager.createServiceDependency().setService(m_aspectInterface, createAspectFilter(ref)).setRequired(true);
+            if (m_autoConfig != null) {
+                dependency.setAutoConfig(m_autoConfig);
+            }
+            if (m_add != null || m_change != null || m_remove != null) {
+                dependency.setCallbacks(m_add, m_change, m_remove);
+            }
+            Component service = m_manager.createComponent()
+                .setInterface(serviceInterfaces, serviceProperties)
+                .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(dependency);
+            
+            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;                
+        }
+        
+        private Properties getServiceProperties(Object[] params) {
+            ServiceReference ref = (ServiceReference) params[0]; 
+            Properties props = new Properties();
+            String[] keys = ref.getPropertyKeys();
+            for (int i = 0; i < keys.length; i++) {
+                String key = keys[i];
+                if (key.equals(Constants.SERVICE_ID) || key.equals(Constants.SERVICE_RANKING) || key.equals(DependencyManager.ASPECT) || key.equals(Constants.OBJECTCLASS)) {
+                    // do not copy these
+                }
+                else {
+                    props.put(key, ref.getProperty(key));
+                }
+            }
+            if (m_serviceProperties != null) {
+                Enumeration e = m_serviceProperties.keys();
+                while (e.hasMoreElements()) {
+                    Object key = e.nextElement();
+                    props.put(key, m_serviceProperties.get(key));
+                }
+            }
+            // finally add our aspect property
+            props.put(DependencyManager.ASPECT, ref.getProperty(Constants.SERVICE_ID));
+            // and the ranking
+            props.put(Constants.SERVICE_RANKING, Integer.valueOf(m_ranking));
+            return props;
+        }
+        
+        private String[] getServiceInterfaces() {
+            List serviceNames = new ArrayList();
+            // Of course, we provide the aspect interface.
+            serviceNames.add(m_aspectInterface.getName());
+            // But also append additional aspect implementation interfaces.
+            if (m_serviceInterfaces != null) {
+                for (int i = 0; i < m_serviceInterfaces.length; i ++) {
+                    if (!m_serviceInterfaces[i].equals(m_aspectInterface.getName())) {
+                        serviceNames.add(m_serviceInterfaces[i]);
+                    }
+                }
+            }
+            return (String[]) serviceNames.toArray(new String[serviceNames.size()]);
+        }
+
+        private String createAspectFilter(ServiceReference ref) {
+            Long sid = (Long) ref.getProperty(Constants.SERVICE_ID);
+            return "(&(|(!(" + Constants.SERVICE_RANKING + "=*))(" + Constants.SERVICE_RANKING + "<=" + (m_ranking - 1) + "))(|(" + Constants.SERVICE_ID + "=" + sid + ")(" + DependencyManager.ASPECT + "=" + sid + ")))";
+        }
+    }
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterServiceImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterServiceImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/BundleAdapterServiceImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,102 @@
+/*
+ * 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.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.osgi.framework.Bundle;
+
+/**
+ * Bundle 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 BundleAdapterServiceImpl extends FilterService
+{
+    /**
+     * Creates a new Bundle Adapter Service implementation.
+     */
+    public BundleAdapterServiceImpl(DependencyManager dm, int bundleStateMask, String bundleFilter, boolean propagate)
+    {
+        super(dm.createComponent()); // This service will be filtered by our super class, allowing us to take control.
+        m_component.setImplementation(new BundleAdapterImpl(bundleStateMask, bundleFilter, propagate))
+                 .add(dm.createBundleDependency()
+                      .setFilter(bundleFilter)
+                      .setStateMask(bundleStateMask)
+                      .setCallbacks("added", "removed"));
+    }
+
+    public class BundleAdapterImpl extends AbstractDecorator {
+        private final boolean m_propagate;
+        private final int m_bundleStateMask;
+        private final String m_bundleFilter;
+
+        public BundleAdapterImpl(int bundleStateMask, String bundleFilter, boolean propagate) {
+            m_bundleStateMask = bundleStateMask;
+            m_bundleFilter = bundleFilter;
+            m_propagate = propagate;
+        }
+        
+        public Component createService(Object[] properties) {
+            Bundle bundle = (Bundle) 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 bundle, which
+            // will be replaced with a more specific dependency below
+            dependencies.remove(0);
+            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(m_manager.createBundleDependency()
+                    .setBundle(bundle)
+                    .setStateMask(m_bundleStateMask)
+                    .setPropagate(m_propagate)
+                    .setCallbacks(null, "changed", null)
+                    .setAutoConfig(true)
+                    .setRequired(true));
+
+            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));
+            }
+            configureAutoConfigState(service, m_component);
+            return service;
+        }
+    }
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,1165 @@
+/*
+ * 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.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.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.DependencyActivation;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.DependencyService;
+import org.apache.felix.dm.InvocationUtil;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * Component implementation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ComponentImpl implements Component, DependencyService, ComponentDeclaration, Comparable {
+    private static final Class[] VOID = new Class[] {};
+	private static final ServiceRegistration NULL_REGISTRATION;
+    private static final ComponentStateListener[] SERVICE_STATE_LISTENER_TYPE = new ComponentStateListener[] {};
+    private static long HIGHEST_ID = 0;
+
+    private final Object SYNC = new Object();
+    private final BundleContext m_context;
+    private final DependencyManager m_manager;
+    private final long m_id;
+
+    // configuration (static)
+    private String m_callbackInit;
+    private String m_callbackStart;
+    private String m_callbackStop;
+    private String m_callbackDestroy;
+    private Object m_serviceName;
+    private Object m_implementation;
+    private Object m_callbackInstance;
+
+    // configuration (dynamic, but does not affect state)
+    private Dictionary m_serviceProperties;
+
+    // configuration (dynamic, and affects state)
+    private ArrayList m_dependencies = new ArrayList();
+
+    // runtime state (calculated from dependencies)
+    private State m_state;
+
+    // runtime state (changes because of state changes)
+    private Object m_serviceInstance;
+    private volatile ServiceRegistration m_registration;
+    private boolean m_isBound;
+    private boolean m_isInstantiated;
+
+    // service state listeners
+    private final List m_stateListeners = new ArrayList();
+
+    // work queue
+    private final SerialExecutor m_executor = new SerialExecutor();
+
+    // instance factory
+	private Object m_instanceFactory;
+	private String m_instanceFactoryCreateMethod;
+
+	// composition manager
+	private Object m_compositionManager;
+	private String m_compositionManagerGetMethod;
+	private Object m_compositionManagerInstance;
+	
+	// internal logging
+    private final Logger m_logger;
+    
+    private Map m_autoConfig = new HashMap();
+    private Map m_autoConfigInstance = new HashMap();
+    
+    private boolean m_isStarted = false;
+
+    public ComponentImpl(BundleContext context, DependencyManager manager, Logger logger) {
+        synchronized (VOID) {
+            m_id = HIGHEST_ID++;
+        }
+    	m_logger = logger;
+        m_state = new State((List) m_dependencies.clone(), false, false, false);
+        m_context = context;
+        m_manager = manager;
+        m_callbackInit = "init";
+        m_callbackStart = "start";
+        m_callbackStop = "stop";
+        m_callbackDestroy = "destroy";
+        m_implementation = null;
+        m_autoConfig.put(BundleContext.class, Boolean.TRUE);
+        m_autoConfig.put(ServiceRegistration.class, Boolean.TRUE);
+        m_autoConfig.put(DependencyManager.class, Boolean.TRUE);
+        m_autoConfig.put(Component.class, Boolean.TRUE);
+    }
+
+    private void calculateStateChanges() {
+        // see if any of the things we did caused a further change of state
+        State oldState, newState;
+        synchronized (m_dependencies) {
+            oldState = m_state;
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+            m_state = newState;
+        }
+        calculateStateChanges(oldState, newState);
+    }
+    
+    private void calculateStateChanges(final State oldState, final State newState) {
+        if (oldState.isInactive() && (newState.isTrackingOptional())) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    activateService(newState);
+                }});
+        }
+        if (oldState.isInactive() && (newState.isWaitingForRequired())) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    startTrackingRequired(newState);
+                }});
+        }
+        if (oldState.isWaitingForRequired() && newState.isTrackingOptional()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    activateService(newState);
+                }});
+        }
+        if ((oldState.isWaitingForRequired()) && newState.isInactive()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    stopTrackingRequired(oldState);
+                }});
+        }
+        if (oldState.isTrackingOptional() && newState.isWaitingForRequiredInstantiated()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    // TODO as far as I can see there is nothing left to do here
+                    // unbindService(newState);
+                }});
+        }
+        if (oldState.isTrackingOptional() && newState.isWaitingForRequired()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    deactivateService(oldState);
+                }});
+        }
+        if (oldState.isTrackingOptional() && newState.isBound()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    bindService(newState);
+                }});
+        }
+        if (oldState.isTrackingOptional() && newState.isInactive()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    deactivateService(oldState);
+                    stopTrackingRequired(oldState);
+                }});
+        }
+        if (oldState.isWaitingForRequiredInstantiated() && newState.isWaitingForRequired()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    deactivateService(oldState);
+                }});
+        }
+        if (oldState.isWaitingForRequiredInstantiated() && newState.isInactive()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    deactivateService(oldState);
+                    stopTrackingRequired(oldState);
+                }});
+        }
+        if (oldState.isWaitingForRequiredInstantiated() && newState.isBound()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    bindService(newState);
+                }});
+        }
+        if (oldState.isBound() && newState.isWaitingForRequiredInstantiated()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    unbindService(oldState);
+                }});
+        }
+        if (oldState.isBound() && newState.isWaitingForRequired()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    unbindService(oldState);
+                    deactivateService(oldState);
+                }});
+        }
+        if (oldState.isBound() && newState.isInactive()) {
+            m_executor.enqueue(new Runnable() {
+                public void run() {
+                    unbindService(oldState);
+                    deactivateService(oldState);
+                    stopTrackingRequired(oldState);
+                }});
+        }
+        m_executor.execute();
+    }
+    
+    // TODO fix code duplication between add(Dependency) and add(List)
+    public Component add(final Dependency dependency) {
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            m_dependencies.add(dependency);
+        }
+        
+        // if we're inactive, don't do anything, otherwise we might want to start
+        // the dependency
+        if (!oldState.isInactive()) {
+            // if the dependency is required, it should be started regardless of the state
+            // we're in
+            if (dependency.isRequired()) {
+                ((DependencyActivation) dependency).start(this);
+            }
+            else {
+                // if the dependency is optional, it should only be started if we're in
+                // bound state
+                if (oldState.isBound()) {
+                    ((DependencyActivation) dependency).start(this);
+                }
+            }
+        }
+
+        synchronized (m_dependencies) {
+            oldState = m_state;
+            // starting the dependency above might have triggered another state change, so
+            // we have to fetch the current state again
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+            m_state = newState;
+        }
+        calculateStateChanges(oldState, newState);
+        return this;
+    }
+    
+    public Component add(List dependencies) {
+        State oldState, newState;
+        synchronized (m_dependencies) {
+            oldState = m_state;
+            for (int i = 0; i < dependencies.size(); i++) {
+                m_dependencies.add(dependencies.get(i));
+            }
+        }
+        
+        // if we're inactive, don't do anything, otherwise we might want to start
+        // the dependencies
+        if (!oldState.isInactive()) {
+            for (int i = 0; i < dependencies.size(); i++) {
+                Dependency dependency = (Dependency) dependencies.get(i);
+                // if the dependency is required, it should be started regardless of the state
+                // we're in
+                if (dependency.isRequired()) {
+                    ((DependencyActivation) dependency).start(this);
+                }
+                else {
+                    // if the dependency is optional, it should only be started if we're in
+                    // bound state
+                    if (oldState.isBound()) {
+                        ((DependencyActivation) dependency).start(this);
+                    }
+                }
+            }
+        }
+
+        synchronized (m_dependencies) {
+            oldState = m_state;
+            // starting the dependency above might have triggered another state change, so
+            // we have to fetch the current state again
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+            m_state = newState;
+        }
+        calculateStateChanges(oldState, newState);
+        return this;
+    }
+
+    public Component remove(Dependency dependency) {
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            m_dependencies.remove(dependency);
+        }
+        if (oldState.isAllRequiredAvailable() || ((oldState.isWaitingForRequired() || oldState.isWaitingForRequiredInstantiated()) && dependency.isRequired())) {
+        	((DependencyActivation) dependency).stop(this);
+        }
+        synchronized (m_dependencies) {
+            // starting the dependency above might have triggered another state change, so
+            // we have to fetch the current state again
+            oldState = m_state;
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+            m_state = newState;
+        }
+        calculateStateChanges(oldState, newState);
+        return this;
+    }
+
+    public List getDependencies() {
+        synchronized (m_dependencies) {
+            return (List) m_dependencies.clone();
+        }
+    }
+
+    public ServiceRegistration getServiceRegistration() {
+        return m_registration;
+    }
+
+    public Object getService() {
+        return m_serviceInstance;
+    }
+    
+    public Component getServiceInterface() {
+        return this;
+    }
+
+    public void dependencyAvailable(final Dependency dependency) {
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+            m_state = newState;
+        }
+        if (newState.isAllRequiredAvailable() || newState.isWaitingForRequiredInstantiated()) {
+        	updateInstance(dependency);
+        }
+        calculateStateChanges(oldState, newState);
+    }
+
+    public void dependencyChanged(final Dependency dependency) {
+    	State state;
+        synchronized (m_dependencies) {
+        	state = m_state;
+        }
+        if (state.isAllRequiredAvailable()) {
+        	updateInstance(dependency);
+        }
+    }
+
+    public void dependencyUnavailable(final Dependency dependency) {
+    	State oldState, newState;
+        synchronized (m_dependencies) {
+        	oldState = m_state;
+            newState = new State((List) m_dependencies.clone(), !oldState.isInactive(), m_isInstantiated, m_isBound);
+            m_state = newState;
+        }
+        if (newState.isAllRequiredAvailable()) {
+        	updateInstance(dependency);
+        }
+        calculateStateChanges(oldState, newState);
+    }
+
+    public synchronized void start() {
+    	if (!m_isStarted) {
+    	    m_isStarted = true;
+	        State oldState, newState;
+	        synchronized (m_dependencies) {
+	            oldState = m_state;
+	            newState = new State((List) m_dependencies.clone(), true, m_isInstantiated, m_isBound);
+	            m_state = newState;
+	        }
+	        calculateStateChanges(oldState, newState);
+    	}
+    }
+
+    public synchronized void stop() {
+        if (m_isStarted) {
+            m_isStarted = false;
+	        State oldState, newState;
+	        synchronized (m_dependencies) {
+	            oldState = m_state;
+	            newState = new State((List) m_dependencies.clone(), false, m_isInstantiated, m_isBound);
+	            m_state = newState;
+	        }
+	        calculateStateChanges(oldState, newState);
+    	}
+    }
+
+    public synchronized Component setInterface(String serviceName, Dictionary properties) {
+	    ensureNotActive();
+	    m_serviceName = serviceName;
+	    m_serviceProperties = properties;
+	    return this;
+	}
+
+	public synchronized Component setInterface(String[] serviceName, Dictionary properties) {
+	    ensureNotActive();
+	    m_serviceName = serviceName;
+	    m_serviceProperties = properties;
+	    return this;
+	}
+
+	public synchronized Component setCallbacks(String init, String start, String stop, String destroy) {
+	    ensureNotActive();
+	    m_callbackInit = init;
+	    m_callbackStart = start;
+	    m_callbackStop = stop;
+	    m_callbackDestroy = destroy;
+	    return this;
+	}
+	
+    public synchronized Component setCallbacks(Object instance, String init, String start, String stop, String destroy) {
+        ensureNotActive();
+        m_callbackInstance = instance;
+        m_callbackInit = init;
+        m_callbackStart = start;
+        m_callbackStop = stop;
+        m_callbackDestroy = destroy;
+        return this;
+    }
+	
+	public synchronized Component setImplementation(Object implementation) {
+	    ensureNotActive();
+	    m_implementation = implementation;
+	    return this;
+	}
+
+	public synchronized Component setFactory(Object factory, String createMethod) {
+	    ensureNotActive();
+		m_instanceFactory = factory;
+		m_instanceFactoryCreateMethod = createMethod;
+		return this;
+	}
+
+	public synchronized Component setFactory(String createMethod) {
+		return setFactory(null, createMethod);
+	}
+
+	public synchronized Component setComposition(Object instance, String getMethod) {
+	    ensureNotActive();
+		m_compositionManager = instance;
+		m_compositionManagerGetMethod = getMethod;
+		return this;
+	}
+
+	public synchronized Component setComposition(String getMethod) {
+		return setComposition(null, getMethod);
+	}
+
+	public String toString() {
+	    return this.getClass().getSimpleName() + "[" + m_serviceName + " " + m_implementation + "]";
+	}
+
+	public synchronized Dictionary getServiceProperties() {
+	    if (m_serviceProperties != null) {
+	        return (Dictionary) ((Hashtable) m_serviceProperties).clone();
+	    }
+	    return null;
+	}
+
+	public synchronized Component setServiceProperties(Dictionary serviceProperties) {
+	    m_serviceProperties = serviceProperties;
+	    if ((m_registration != null) && (m_serviceName != null)) {
+	        m_registration.setProperties(calculateServiceProperties());
+	    }
+	    return this;
+	}
+
+	// service state listener methods
+	public void addStateListener(ComponentStateListener listener) {
+    	synchronized (m_stateListeners) {
+		    m_stateListeners.add(listener);
+    	}
+    	// when we register as a listener and the service is already started
+    	// make sure we invoke the right callbacks so the listener knows
+    	State state;
+    	synchronized (m_dependencies) {
+    		state = m_state;
+    	}
+    	if (state.isBound()) {
+    		listener.starting(this);
+    		listener.started(this);
+    	}
+	}
+
+	public void removeStateListener(ComponentStateListener listener) {
+    	synchronized (m_stateListeners) {
+    		m_stateListeners.remove(listener);
+    	}
+	}
+
+	public void removeStateListeners() {
+    	synchronized (m_stateListeners) {
+    		m_stateListeners.clear();
+    	}
+	}
+
+	private void stateListenersStarting() {
+		ComponentStateListener[] list = getListeners();
+		for (int i = 0; i < list.length; i++) {
+		    try {
+		        list[i].starting(this);
+		    }
+		    catch (Throwable t) {
+		        m_logger.log(Logger.LOG_ERROR, "Error invoking listener starting method.", t);
+		    }
+		}
+	}
+
+	private void stateListenersStarted() {
+        ComponentStateListener[] list = getListeners();
+        for (int i = 0; i < list.length; i++) {
+            try {
+                list[i].started(this);
+            }
+            catch (Throwable t) {
+                m_logger.log(Logger.LOG_ERROR, "Error invoking listener started method.", t);
+            }
+        }
+    }
+
+    private void stateListenersStopping() {
+        ComponentStateListener[] list = getListeners();
+        for (int i = 0; i < list.length; i++) {
+            try {
+                list[i].stopping(this);
+            }
+            catch (Throwable t) {
+                m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopping method.", t);
+            }
+        }
+    }
+
+    private void stateListenersStopped() {
+        ComponentStateListener[] list = getListeners();
+        for (int i = 0; i < list.length; i++) {
+            try {
+                list[i].stopped(this);
+            }
+            catch (Throwable t) {
+                m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopped method.", t);
+            }
+        }
+    }
+
+	private ComponentStateListener[] getListeners() {
+		synchronized (m_stateListeners) {
+			return (ComponentStateListener[]) m_stateListeners.toArray(SERVICE_STATE_LISTENER_TYPE);
+		}
+	}
+
+    private void activateService(State state) {
+        String init;
+        synchronized (this) {
+            init = m_callbackInit;
+        }
+        // service activation logic, first we initialize the service instance itself
+        // meaning it is created if necessary and the bundle context is set
+        initService();
+        // now is the time to configure the service, meaning all required
+        // dependencies will be set and any callbacks called
+        configureService(state);
+        // flag that our instance has been created
+        m_isInstantiated = true;
+        // then we invoke the init callback so the service can further initialize
+        // itself
+        invoke(init);
+        // see if any of this caused further state changes
+        calculateStateChanges();
+    }
+
+    private void bindService(State state) {
+        String start;
+        synchronized (this) {
+            start = m_callbackStart;
+        }
+        
+        // configure service with extra-dependencies which might have been added from init() method.
+        configureServiceWithExtraDependencies(state);
+        // inform the state listeners we're starting
+        stateListenersStarting();
+        // invoke the start callback, since we're now ready to be used
+        invoke(start);
+        // start tracking optional services
+        startTrackingOptional(state);
+        // register the service in the framework's service registry
+        registerService();
+        // inform the state listeners we've started
+        stateListenersStarted();
+    }
+    
+    private void configureServiceWithExtraDependencies(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (dependency.isAutoConfig() && dependency.isInstanceBound()) {
+                configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
+            }
+        }
+    }
+
+    private void unbindService(State state) {
+        String stop;
+        synchronized (this) {
+            stop = m_callbackStop;
+        }
+        // service deactivation logic, first inform the state listeners
+        // we're stopping
+        stateListenersStopping();
+        // then, unregister the service from the framework
+        unregisterService();
+        // stop tracking optional services
+        stopTrackingOptional(state);
+        // invoke the stop callback
+        invoke(stop);
+        // inform the state listeners we've stopped
+        stateListenersStopped();
+    }
+
+    private void deactivateService(State state) {
+        String destroy;
+        synchronized (this) {
+            destroy = m_callbackDestroy;
+        }
+        // flag that our instance was destroyed
+        m_isInstantiated = false;
+        // invoke the destroy callback
+        invoke(destroy);
+        // destroy the service instance
+        destroyService(state);
+    }
+    
+    private void invoke(String name) {
+        if (name != null) {
+            // if a callback instance was specified, look for the method there, if not,
+            // ask the service for its composition instances
+            Object[] instances = m_callbackInstance != null ? new Object[] { m_callbackInstance } : getCompositionInstances();
+            invokeCallbackMethod(instances, name, 
+                new Class[][] {{ Component.class }, {}}, 
+                new Object[][] {{ this }, {}});
+        }
+    }
+    
+    public void invokeCallbackMethod(Object[] instances, String methodName, Class[][] signatures, Object[][] parameters) {
+        for (int i = 0; i < instances.length; i++) {
+            try {
+                InvocationUtil.invokeCallbackMethod(instances[i], methodName, signatures, parameters);
+            }
+            catch (NoSuchMethodException e) {
+                // if the method does not exist, ignore it
+            }
+            catch (InvocationTargetException e) {
+                // the method itself threw an exception, log that
+                m_logger.log(Logger.LOG_WARNING, "Invocation of '" + methodName + "' failed.", e.getCause());
+            }
+            catch (Exception e) {
+                m_logger.log(Logger.LOG_WARNING, "Could not invoke '" + methodName + "'.", e);
+            }
+        }
+    }
+
+    private void startTrackingOptional(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (!dependency.isRequired()) {
+                ((DependencyActivation) dependency).start(this);
+            }
+        }
+    }
+    
+    private void stopTrackingOptional(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (!dependency.isRequired()) {
+                ((DependencyActivation) dependency).stop(this);
+            }
+        }
+    }
+
+    private void startTrackingRequired(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (dependency.isRequired()) {
+                ((DependencyActivation) dependency).start(this);
+            }
+        }
+    }
+
+    private void stopTrackingRequired(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (dependency.isRequired()) {
+                ((DependencyActivation) dependency).stop(this);
+            }
+        }
+    }
+
+    private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+		Constructor constructor = clazz.getConstructor(VOID);
+		constructor.setAccessible(true);
+        return constructor.newInstance(null);
+    }
+
+    public void initService() {
+    	if (m_serviceInstance == null) {
+	        if (m_implementation instanceof Class) {
+	            // instantiate
+	            try {
+	            	m_serviceInstance = createInstance((Class) m_implementation);
+	            }
+	            catch (Exception e) {
+	                m_logger.log(Logger.LOG_ERROR, "Could not create service instance of class " + m_implementation + ".", e);
+				}
+	        }
+	        else {
+	        	if (m_instanceFactoryCreateMethod != null) {
+	        		Object factory = null;
+		        	if (m_instanceFactory != null) {
+		        		if (m_instanceFactory instanceof Class) {
+		        			try {
+								factory = createInstance((Class) m_instanceFactory);
+							}
+		                    catch (Exception e) {
+		                        m_logger.log(Logger.LOG_ERROR, "Could not create factory instance of class " + m_instanceFactory + ".", e);
+		                    }
+		        		}
+		        		else {
+		        			factory = m_instanceFactory;
+		        		}
+		        	}
+		        	else {
+		        		// TODO review if we want to try to default to something if not specified
+		        	    // for now the JavaDoc of setFactory(method) reflects the fact that we need
+		        	    // to review it
+		        	}
+		        	if (factory == null) {
+                        m_logger.log(Logger.LOG_ERROR, "Factory cannot be null.");
+		        	}
+		        	else {
+    		        	try {
+    						m_serviceInstance = InvocationUtil.invokeMethod(factory, factory.getClass(), m_instanceFactoryCreateMethod, new Class[][] {{}}, new Object[][] {{}}, false);
+    					}
+    		        	catch (Exception e) {
+    	                    m_logger.log(Logger.LOG_ERROR, "Could not create service instance using factory " + factory + " method " + m_instanceFactoryCreateMethod + ".", e);
+    					}
+		        	}
+	        	}
+	        	if (m_serviceInstance == null) {
+	        	    if (m_implementation == null) {
+	        	        m_logger.log(Logger.LOG_ERROR, "Implementation cannot be null.");
+	        	    }
+	        	    m_serviceInstance = m_implementation;
+	        	}
+	        }
+	        // configure the bundle context
+	        if (((Boolean) m_autoConfig.get(BundleContext.class)).booleanValue()) {
+	            configureImplementation(BundleContext.class, m_context, (String) m_autoConfigInstance.get(BundleContext.class));
+	        }
+            if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
+                configureImplementation(ServiceRegistration.class, NULL_REGISTRATION, (String) m_autoConfigInstance.get(ServiceRegistration.class));
+            }
+            if (((Boolean) m_autoConfig.get(DependencyManager.class)).booleanValue()) {
+                configureImplementation(DependencyManager.class, m_manager, (String) m_autoConfigInstance.get(DependencyManager.class));
+            }
+            if (((Boolean) m_autoConfig.get(Component.class)).booleanValue()) {
+                configureImplementation(Component.class, this, (String) m_autoConfigInstance.get(Component.class));
+            }
+    	}
+    }
+
+    public synchronized Component setAutoConfig(Class clazz, boolean autoConfig) {
+        m_autoConfig.put(clazz, Boolean.valueOf(autoConfig));
+        return this;
+    }
+    
+    public synchronized Component setAutoConfig(Class clazz, String instanceName) {
+        m_autoConfig.put(clazz, Boolean.valueOf(instanceName != null));
+        m_autoConfigInstance.put(clazz, instanceName);
+        return this;
+    }
+    
+    public boolean getAutoConfig(Class clazz) {
+        Boolean result = (Boolean) m_autoConfig.get(clazz);
+        return (result != null && result.booleanValue());
+    }
+    
+    public String getAutoConfigInstance(Class clazz) {
+        return (String) m_autoConfigInstance.get(clazz);
+    }
+    
+    private void configureService(State state) {
+        // configure all services (the optional dependencies might be configured
+        // as null objects but that's what we want at this point)
+        configureServices(state);
+    }
+
+    private void destroyService(State state) {
+        unconfigureServices(state);
+        m_serviceInstance = null;
+    }
+
+    private void registerService() {
+        if (m_serviceName != null) {
+            ServiceRegistrationImpl wrapper = new ServiceRegistrationImpl();
+            m_registration = wrapper;
+            if (((Boolean) m_autoConfig.get(ServiceRegistration.class)).booleanValue()) {
+                configureImplementation(ServiceRegistration.class, m_registration, (String) m_autoConfigInstance.get(ServiceRegistration.class));
+            }
+            
+            // service name can either be a string or an array of strings
+            ServiceRegistration registration;
+
+            // determine service properties
+            Dictionary properties = calculateServiceProperties();
+
+            // register the service
+            try {
+                if (m_serviceName instanceof String) {
+                    registration = m_context.registerService((String) m_serviceName, m_serviceInstance, properties);
+                }
+                else {
+                    registration = m_context.registerService((String[]) m_serviceName, m_serviceInstance, properties);
+                }
+                wrapper.setServiceRegistration(registration);
+            }
+            catch (IllegalArgumentException iae) {
+                m_logger.log(Logger.LOG_ERROR, "Could not register service " + m_serviceInstance, iae);
+                // set the registration to an illegal state object, which will make all invocations on this
+                // wrapper fail with an ISE (which also occurs when the SR becomes invalid)
+                wrapper.setIllegalState();
+            }
+        }
+        m_isBound = true;
+    }
+
+	private Dictionary calculateServiceProperties() {
+		Dictionary properties = new Properties();
+		addTo(properties, m_serviceProperties);
+		for (int i = 0; i < m_dependencies.size(); i++) {
+			Dependency d = (Dependency) m_dependencies.get(i);
+			if (d.isPropagated() && d.isAvailable()) {
+				Dictionary dict = d.getProperties();
+				addTo(properties, dict);
+			}
+		}
+		if (properties.size() == 0) {
+			properties = null;
+		}
+		return properties;
+	}
+
+	private void addTo(Dictionary properties, Dictionary additional) {
+		if (properties == null) {
+			throw new IllegalArgumentException("Dictionary to add to cannot be null.");
+		}
+		if (additional != null) {
+			Enumeration e = additional.keys();
+			while (e.hasMoreElements()) {
+				Object key = e.nextElement();
+				properties.put(key, additional.get(key));
+			}
+		}
+	}
+
+    private void unregisterService() {
+        m_isBound = false;
+        if (m_serviceName != null) {
+            m_registration.unregister();
+            configureImplementation(ServiceRegistration.class, NULL_REGISTRATION);
+            m_registration = null;
+        }
+    }
+
+    private void updateInstance(Dependency dependency) {
+        if (dependency.isAutoConfig()) {
+            configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
+            if (dependency.isPropagated() && m_registration != null) {
+                m_registration.setProperties(calculateServiceProperties());
+            }
+        }
+    }
+
+    /**
+     * Configure a field in the service implementation. The service implementation
+     * is searched for fields that have the same type as the class that was specified
+     * and for each of these fields, the specified instance is filled in.
+     *
+     * @param clazz the class to search for
+     * @param instance the instance to fill in
+     * @param instanceName the name of the instance to fill in, or <code>null</code> if not used
+     */
+    private void configureImplementation(Class clazz, Object instance, String instanceName) {
+    	Object[] instances = getCompositionInstances();
+    	if (instances != null) {
+	    	for (int i = 0; i < instances.length; i++) {
+	    		Object serviceInstance = instances[i];
+		        Class serviceClazz = serviceInstance.getClass();
+		        if (Proxy.isProxyClass(serviceClazz)) {
+		            serviceInstance = Proxy.getInvocationHandler(serviceInstance);
+		            serviceClazz = serviceInstance.getClass();
+		        }
+		        while (serviceClazz != null) {
+		            Field[] fields = serviceClazz.getDeclaredFields();
+		            for (int j = 0; j < fields.length; j++) {
+		                Field field = fields[j];
+                        Class type = field.getType();
+                        if ((instanceName == null && type.equals(clazz)) 
+		                    || (instanceName != null && field.getName().equals(instanceName) && type.isAssignableFrom(clazz))) {
+		                    try {
+		                    	field.setAccessible(true);
+		                        // synchronized makes sure the field is actually written to immediately
+		                        synchronized (SYNC) {
+		                            field.set(serviceInstance, instance);
+		                        }
+		                    }
+		                    catch (Exception e) {
+		                        m_logger.log(Logger.LOG_ERROR, "Could not set field " + field, e);
+		                        return;
+		                    }
+		                }
+		            }
+		            serviceClazz = serviceClazz.getSuperclass();
+		        }
+	    	}
+    	}
+    }
+    
+    public Object[] getCompositionInstances() {
+        Object[] instances = null;
+        if (m_compositionManagerGetMethod != null) {
+            if (m_compositionManager != null) {
+                m_compositionManagerInstance = m_compositionManager;
+            }
+            else {
+                m_compositionManagerInstance = m_serviceInstance;
+            }
+            if (m_compositionManagerInstance != null) {
+                try {
+                    instances = (Object[]) InvocationUtil.invokeMethod(m_compositionManagerInstance, m_compositionManagerInstance.getClass(), m_compositionManagerGetMethod, new Class[][] {{}}, new Object[][] {{}}, false);
+                }
+                catch (Exception e) {
+                    m_logger.log(Logger.LOG_ERROR, "Could not obtain instances from the composition manager.", e);
+                    instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
+                }
+            }
+        }
+        else {
+            instances = m_serviceInstance == null ? new Object[] {} : new Object[] { m_serviceInstance };
+        }
+        return instances;
+    }
+
+    private void configureImplementation(Class clazz, Object instance) {
+        configureImplementation(clazz, instance, null);
+    }
+
+    private void configureServices(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (dependency.isAutoConfig()) {
+                configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
+            }
+            if (dependency.isRequired()) {
+                dependency.invokeAdded(this);
+            }
+        }
+    }
+
+    private void unconfigureServices(State state) {
+        Iterator i = state.getDependencies().iterator();
+        while (i.hasNext()) {
+            Dependency dependency = (Dependency) i.next();
+            if (dependency.isRequired()) {
+                dependency.invokeRemoved(this);
+            }
+        }
+    }
+
+    protected void ensureNotActive() {
+    	State state;
+    	synchronized (m_dependencies) {
+    		state = m_state;
+    	}
+    	if (!state.isInactive()) {
+            throw new IllegalStateException("Cannot modify state while active.");
+        }
+    }
+    
+    public boolean isRegistered() {
+    	State state;
+    	synchronized (m_dependencies) {
+    		state = m_state;
+    	}
+        return (state.isAllRequiredAvailable());
+    }
+    
+    public boolean isInstantiated() {
+        State state;
+        synchronized (m_dependencies) {
+            state = m_state;
+        }
+        return (state.isTrackingOptional() || state.isBound() || state.isWaitingForRequiredInstantiated());
+    }
+    
+    // ServiceComponent interface
+    
+    static class SCDImpl implements ComponentDependencyDeclaration {
+        private final String m_name;
+        private final int m_state;
+        private final String m_type;
+
+        public SCDImpl(String name, int state, String type) {
+            m_name = name;
+            m_state = state;
+            m_type = type;
+        }
+
+        public String getName() {
+            return m_name;
+        }
+
+        public int getState() {
+            return m_state;
+        }
+
+        public String getType() {
+            return m_type;
+        }
+    }
+    
+    public ComponentDependencyDeclaration[] getComponentDependencies() {
+        List deps = getDependencies();
+        if (deps != null) {
+            ComponentDependencyDeclaration[] result = new ComponentDependencyDeclaration[deps.size()];
+            for (int i = 0; i < result.length; i++) {
+                Dependency dep = (Dependency) deps.get(i);
+                if (dep instanceof ComponentDependencyDeclaration) {
+                    result[i] = (ComponentDependencyDeclaration) dep;
+                }
+                else {
+                    result[i] = new SCDImpl(dep.toString(), (dep.isAvailable() ? 1 : 0) + (dep.isRequired() ? 2 : 0), dep.getClass().getName());
+                }
+            }
+            return result;
+        }
+        return null;
+    }
+
+    public String getName() {
+        Object serviceName = m_serviceName;
+        if (serviceName instanceof String[]) {
+            StringBuffer sb = new StringBuffer();
+            String[] names = (String[]) serviceName;
+            for (int i = 0; i < names.length; i++) {
+                if (i > 0) {
+                    sb.append(", ");
+                }
+                sb.append(names[i]);
+            }
+            sb.append('(');
+            sb.append(propertiesToString());
+            sb.append(')');
+            return sb.toString();
+        }
+        else if (serviceName instanceof String) {
+            return serviceName.toString() + "(" + propertiesToString() + ")";
+        }
+        else {
+            Object implementation = m_implementation;
+            if (implementation != null) {
+                return implementation.toString();
+            }
+            else {
+                return super.toString();
+            }
+        }
+    }
+    
+    private String propertiesToString() {
+        StringBuffer result = new StringBuffer();
+        Dictionary properties = calculateServiceProperties();
+        if (properties != null) {
+            Enumeration enumeration = properties.keys();
+            while (enumeration.hasMoreElements()) {
+                Object key = enumeration.nextElement();
+                if (result.length() > 0) {
+                    result.append(',');
+                }
+                result.append(key.toString());
+                result.append('=');
+                Object value = properties.get(key);
+                if (value instanceof String[]) {
+                    String[] values = (String[]) value;
+                    result.append('{');
+                    for (int i = 0; i < values.length; i++) {
+                        if (i > 0) {
+                            result.append(',');
+                        }
+                        result.append(values[i].toString());
+                    }
+                    result.append('}');
+                }
+                else {
+                    result.append(value.toString());
+                }
+            }
+        }
+        return result.toString();
+    }
+
+    public int getState() {
+        return (isRegistered() ? 1 : 0);
+    }
+    
+    public DependencyManager getDependencyManager() {
+        return m_manager;
+    }
+    
+    static {
+        NULL_REGISTRATION = (ServiceRegistration) Proxy.newProxyInstance(ComponentImpl.class.getClassLoader(), new Class[] {ServiceRegistration.class}, new DefaultNullObject());
+    }
+
+    public BundleContext getBundleContext() {
+        return m_context;
+    }
+
+    public int compareTo(Object object) {
+        if (object instanceof ComponentImpl) {
+            ComponentImpl other = (ComponentImpl) object;
+            long id1 = this.getBundleContext().getBundle().getBundleId();
+            long id2 = ((ComponentImpl) other).getBundleContext().getBundle().getBundleId();
+            if (id1 == id2) {
+                return (int)(this.m_id - other.m_id);
+            }
+            return (int)(id1 - id2);
+        }
+        return -1;
+    }
+}

Added: felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java
URL: http://svn.apache.org/viewvc/felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java?rev=1293173&view=auto
==============================================================================
--- felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java (added)
+++ felix/sandbox/uiterlix/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java Fri Feb 24 10:47:49 2012
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.impl;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+
+/**
+ * Default null object implementation. Uses a dynamic proxy. Null objects are used
+ * as placeholders for services that are not available.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public final class DefaultNullObject implements InvocationHandler {
+    private static final Boolean DEFAULT_BOOLEAN = Boolean.FALSE;
+    private static final Byte DEFAULT_BYTE = new Byte((byte) 0);
+    private static final Short DEFAULT_SHORT = new Short((short) 0);
+    private static final Integer DEFAULT_INT = new Integer(0);
+    private static final Long DEFAULT_LONG = new Long(0);
+    private static final Float DEFAULT_FLOAT = new Float(0.0f);
+    private static final Double DEFAULT_DOUBLE = new Double(0.0);
+    
+    /**
+     * Invokes a method on this null object. The method will return a default
+     * value without doing anything.
+     */
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        Class returnType = method.getReturnType();
+        if (returnType.equals(Boolean.class) || returnType.equals(Boolean.TYPE)) {
+            return DEFAULT_BOOLEAN;
+        }
+        else if (returnType.equals(Byte.class) || returnType.equals(Byte.TYPE)) {
+            return DEFAULT_BYTE;
+        } 
+        else if (returnType.equals(Short.class) || returnType.equals(Short.TYPE)) {
+            return DEFAULT_SHORT;
+        } 
+        else if (returnType.equals(Integer.class) || returnType.equals(Integer.TYPE)) {
+            return DEFAULT_INT;
+        } 
+        else if (returnType.equals(Long.class) || returnType.equals(Long.TYPE)) {
+            return DEFAULT_LONG;
+        } 
+        else if (returnType.equals(Float.class) || returnType.equals(Float.TYPE)) {
+            return DEFAULT_FLOAT;
+        } 
+        else if (returnType.equals(Double.class) || returnType.equals(Double.TYPE)) {
+            return DEFAULT_DOUBLE;
+        } 
+        else {
+            return null;
+        }
+    }
+}
\ No newline at end of file