felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pde...@apache.org
Subject svn commit: r1564995 [4/17] - in /felix/sandbox/pderop/dependencymanager: ./ core/ core/.externalToolBuilders/ core/.settings/ core/src/ core/src/main/ core/src/main/java/ core/src/main/java/org/ core/src/main/java/org/apache/ core/src/main/java/org/ap...
Date Wed, 05 Feb 2014 23:22:36 GMT
Added: felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/ComponentImpl.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,1338 @@
+/*
+ * 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.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Arrays;
+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.ConfigurationDependency;
+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;
+import org.osgi.service.log.LogService;
+
+/**
+ * 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 volatile Object m_serviceName;
+    private volatile Object m_implementation;
+    private volatile Object m_callbackInstance;
+
+    // configuration (dynamic, but does not affect state)
+    private volatile Dictionary m_serviceProperties;
+
+    // configuration (dynamic, and affects state)
+    private final ArrayList m_dependencies = new ArrayList();
+
+    // runtime state (calculated from dependencies)
+    private State m_state;
+
+    // runtime state (changes because of state changes)
+    private volatile Object m_serviceInstance;
+    private volatile ServiceRegistration m_registration;
+    private volatile boolean m_isBound;
+    private volatile boolean m_isInstantiated;
+
+    // declarations used for service state listeners management
+    private final List m_stateListeners = new ArrayList();
+    private int m_componentState = STOPPED;
+    private final static int STARTING = 0;
+    private final static int STARTED = 1;
+    private final static int STOPPING = 2;
+    private final static int STOPPED = 3;
+
+    // work queue
+    private final SerialExecutor m_executor;
+
+    // instance factory
+	private volatile Object m_instanceFactory;
+	private volatile String m_instanceFactoryCreateMethod;
+
+	// composition manager
+	private volatile Object m_compositionManager;
+	private volatile String m_compositionManagerGetMethod;
+	private volatile Object m_compositionManagerInstance;
+	
+	// internal logging
+    private final Logger m_logger;
+    
+    private final Map m_autoConfig = new HashMap();
+    private final 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);
+        m_executor = new SerialExecutor(logger);
+    }
+
+    public SerialExecutor getExecutor() {
+        return m_executor;
+    }
+    
+    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);
+    }
+    
+    /**
+     * calculate state changes.
+     * @param oldState
+     * @param newState
+     * @param inline true means that actions are executed immediately if we are currently executed from within the component's executor.
+     *                  false means that actions are just enqueued.
+     */
+    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 autoConfig(final Dependency dependency) {
+        State state;
+        synchronized (m_dependencies) {
+            state = m_state;
+        }
+        if (state.isAllRequiredAvailable() && dependency.isAutoConfig()) {
+            configureImplementation(dependency.getAutoConfigType(), dependency.getAutoConfigInstance(), dependency.getAutoConfigName());
+        }
+    }
+
+    public void propagate(final Dependency dependency) {
+        State state;
+        synchronized (m_dependencies) {
+            state = m_state;
+        }
+        if (state.isAllRequiredAvailable() && dependency.isPropagated() && m_registration != null) {
+            m_registration.setProperties(calculateServiceProperties());
+        }
+    }
+
+    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 void start() {
+        boolean needsStarting = false;
+        synchronized (this) {
+            if (!m_isStarted) {
+                m_isStarted = true;
+                needsStarting = true;
+            }
+        }
+        if (needsStarting) {
+	        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 void stop() {
+        boolean needsStopping = false;
+        synchronized (this) {
+            if (m_isStarted) {
+                m_isStarted = false;
+                needsStopping = true;
+            }
+        }
+        if (needsStopping) {
+	        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 Component setServiceProperties(Dictionary serviceProperties) {
+	    boolean needsProperties = false;
+	    Dictionary properties = null;
+	    synchronized (this) {
+	        m_serviceProperties = serviceProperties;
+	        if ((m_registration != null) && (m_serviceName != null)) {
+	            properties = calculateServiceProperties();
+	            needsProperties = true;
+	        }
+	    }
+	    if (needsProperties) {
+	        m_registration.setProperties(properties);
+	    }
+	    return this;
+	}
+
+	// service state listener methods
+	public void addStateListener(final ComponentStateListener listener) {
+	    // direct inline execution if we are currently being executed by the executor
+        m_executor.executeNow(new Runnable() { 
+            public void run() {
+                switch (m_componentState) {
+                    case STARTING:
+                        starting(listener);
+                        break;
+                    case STARTED:
+                        starting(listener);
+                        started(listener);
+                        break;
+                    case STOPPING:
+                        starting(listener);
+                        started(listener);
+                        stopping(listener);
+                        break;
+                    case STOPPED:
+                        break;
+                        
+                    default:
+                }
+                synchronized(m_stateListeners) {
+                    m_stateListeners.add(listener);
+                }
+            }
+        }); 
+    }
+
+	public void removeStateListener(final ComponentStateListener listener) {
+	    // direct inline execution if we are currently being executed by the executor
+	    m_executor.executeNow(new Runnable() { 
+            public void run() {
+                switch (m_componentState) {
+                    case STARTING:
+                        started(listener);
+                        break;
+                    case STOPPING:
+                        stopped(listener);
+                        break;
+                    default:
+                }
+                synchronized(m_stateListeners) {
+                    m_stateListeners.remove(listener);
+                }
+            }
+        });
+	}
+
+	public void removeStateListeners() {
+	    ComponentStateListener[] listeners;
+        synchronized (m_stateListeners) {
+            listeners = (ComponentStateListener[]) m_stateListeners.toArray(new ComponentStateListener[0]);
+        }
+        for (int i = 0; i < listeners.length; i ++) {
+            removeStateListener(listeners[i]);
+        }
+	}
+
+	private void stateListenersStarting() {
+        ComponentStateListener[] listeners = getListeners();
+        for (int i = 0; i < listeners.length; i ++) {
+            starting(listeners[i]);
+        }
+        m_componentState = STARTING;
+	}
+
+	private void stateListenersStarted() {
+        ComponentStateListener[] listeners = getListeners();
+        for (int i = 0; i < listeners.length; i ++) {
+            started(listeners[i]);
+        }
+        m_componentState = STARTED;
+    }
+
+    private void stateListenersStopping() {
+        ComponentStateListener[] listeners = getListeners();
+        for (int i = 0; i < listeners.length; i ++) {
+            stopping(listeners[i]);
+        }
+        m_componentState = STOPPING;
+    }
+
+    private void stateListenersStopped() {
+        ComponentStateListener[] listeners = getListeners();
+        for (int i = 0; i < listeners.length; i ++) {
+            stopped(listeners[i]);
+        }
+        m_componentState = STOPPED;
+    }
+
+    private ComponentStateListener[] getListeners() {
+        synchronized (m_stateListeners) {
+            return (ComponentStateListener[]) m_stateListeners.toArray(SERVICE_STATE_LISTENER_TYPE);
+        }
+    }
+
+    /**
+     * Helper method used to invoke state listener "starting" callback.
+     */
+    private void starting(ComponentStateListener l) {
+        try {
+            l.starting(this);
+        }
+        catch (Throwable t) {
+            m_logger.log(Logger.LOG_ERROR, "Error invoking listener starting method.", t);
+        }
+    }
+    
+    /**
+     * Helper method used to invoke state listener "started" callback.
+     */        
+    private void started(ComponentStateListener l) {
+        try {
+            l.started(this);
+        }
+        catch (Throwable t) {
+            m_logger.log(Logger.LOG_ERROR, "Error invoking listener started method.", t);
+        }
+    }
+
+    /**
+     * Helper method used to invoke state listener "stopping" callback.
+     */        
+    private void stopping(ComponentStateListener l) {
+        try {
+            l.stopping(this);
+        }
+        catch (Throwable t) {
+            m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopping method.", t);
+        }
+    }
+    
+    /**
+     * Helper method used to invoke state listener "stopped" callback.
+     */        
+    private void stopped(ComponentStateListener l) {
+        try {
+            l.stopped(this);
+        }
+        catch (Throwable t) {
+            m_logger.log(Logger.LOG_ERROR, "Error invoking listener stopped method.", t);
+        }
+    }
+
+    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() {
+        StringBuffer sb = new StringBuffer();
+        Object serviceName = m_serviceName;
+        if (serviceName instanceof String[]) {
+            String[] names = (String[]) serviceName;
+            for (int i = 0; i < names.length; i++) {
+                if (i > 0) {
+                    sb.append(", ");
+                }
+                sb.append(names[i]);
+            }
+            appendProperties(sb);
+        } else if (serviceName instanceof String) {
+            sb.append(serviceName.toString());
+            appendProperties(sb);
+        } else {
+            Object implementation = m_implementation;
+            if (implementation != null) {
+                if (implementation instanceof Class) {
+                    sb.append(((Class) implementation).getName());
+                } else {
+                    // If the implementation instance does not override "toString", just display
+                    // the class name, else display the component using its toString method
+                    try {
+                	Method m = implementation.getClass().getMethod("toString", new Class[0]);
+                        if (m.getDeclaringClass().equals(Object.class)) {
+                            sb.append(implementation.getClass().getName());
+                        } else {
+                            sb.append(implementation.toString());
+                        }
+                    }  catch (java.lang.NoSuchMethodException e) {
+                        // Just display the class name
+                        sb.append(implementation.getClass().getName());
+                    }
+                }
+            } else {
+                sb.append(super.toString());
+            }
+        }
+        return sb.toString();
+    }
+    
+    public String getClassName() {
+        Object serviceInstance = m_serviceInstance;
+        if (serviceInstance != null) {
+            return serviceInstance.getClass().getName();
+        } 
+        
+        Object implementation = m_implementation;
+        if (implementation != null) {
+            if (implementation instanceof Class) {
+                return ((Class) implementation).getName();
+            }
+            return implementation.getClass().getName();
+        } 
+        
+        Object instanceFactory = m_instanceFactory;
+        if (instanceFactory != null) {
+            return instanceFactory.getClass().getName();
+        } else {
+            // Unexpected ...
+            return getClass().getName();
+        }
+    }
+    
+    private void appendProperties(StringBuffer result) {
+        Dictionary properties = calculateServiceProperties();
+        if (properties != null) {
+            result.append("(");
+            Enumeration enumeration = properties.keys();
+            while (enumeration.hasMoreElements()) {
+                Object key = enumeration.nextElement();
+                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());
+                }
+                if (enumeration.hasMoreElements()) {
+                    result.append(',');
+                }
+            }
+            result.append(")");
+        }
+    }
+
+    public int getState() {
+        return (isRegistered() ? 1 : 0);
+    }
+    
+    public long getId() {
+        return m_id;
+    }
+        
+    public synchronized String[] getServices() {
+        if (m_serviceName instanceof String[]) {
+            return (String[]) m_serviceName;
+        } else if (m_serviceName instanceof String) {
+            return new String[] { (String) m_serviceName };
+        } else {
+            return null;
+        }
+    }
+    
+    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/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java (added)
+++ felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/DefaultNullObject.java Wed Feb  5 23:22:32 2014
@@ -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

Added: felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java (added)
+++ felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FactoryConfigurationAdapterServiceImpl.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,296 @@
+/*
+ * 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 {
+    // Our Managed Service Factory PID
+    protected final String m_factoryPid;
+    
+    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.
+        m_factoryPid = factoryPid;
+
+        Hashtable props = new Hashtable();
+        props.put(Constants.SERVICE_PID, factoryPid);
+        m_component
+            .setInterface(ManagedServiceFactory.class.getName(), props)
+            .setImplementation(new AdapterImpl(update, propagate))
+            .setCallbacks("init", null, "stop", null);
+    }
+    
+    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.
+        m_factoryPid = factoryPid;
+        Hashtable props = new Hashtable();
+        props.put(Constants.SERVICE_PID, factoryPid);
+        m_component
+            .setInterface(ManagedServiceFactory.class.getName(), props)
+            .setImplementation(new MetaTypeAdapterImpl(update, propagate,
+                bctx, logger, heading, description,
+                localization, properyMetaData))
+            .setCallbacks("init", null, "stop", null);
+    }
+    
+    public String getName() {
+        return "Adapter for factory pid " + m_factoryPid;
+    }
+    
+    /**
+     * Creates, updates, or removes a service, when a ConfigAdmin factory configuration is created/updated or deleted.
+     */
+    public class AdapterImpl extends AbstractDecorator implements ManagedServiceFactory {        
+        // The adapter "update" method used to provide the configuration
+        protected final String m_update;
+
+        // Tells if the CM config must be propagated along with the adapter service properties
+        protected final 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 updateMethod, boolean propagate) {
+            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 final MetaTypeProviderImpl m_metaType;
+        
+        public MetaTypeAdapterImpl(String updateMethod, boolean propagate,
+                                   BundleContext bctx, Logger logger, String heading, 
+                                   String description, String localization,
+                                   PropertyMetaData[] properyMetaData) {
+            super(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/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java (added)
+++ felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/FilterService.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,292 @@
+/*
+ * 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 String toString() {
+        return m_component.toString();
+    }
+    
+    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 String getClassName() {
+        return m_component.getClassName();
+    }
+    
+    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 long getId() {
+        return m_component.getId();
+    }
+
+    public String[] getServices() {
+        return m_component.getServices();
+    }
+    
+    public BundleContext getBundleContext() {
+        return m_component.getBundleContext();
+    };
+}
\ No newline at end of file

Added: felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java?rev=1564995&view=auto
==============================================================================
--- felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java (added)
+++ felix/sandbox/pderop/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/Logger.java Wed Feb  5 23:22:32 2014
@@ -0,0 +1,235 @@
+/*
+ * 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.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkUtil;
+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 {
+	private static final String LOG_SINGLE_CONTEXT = "org.apache.felix.dependencymanager.singleContextLog";
+    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) {
+    	if ("true".equals(System.getProperty(LOG_SINGLE_CONTEXT))) {
+    		m_context = FrameworkUtil.getBundle(DependencyManager.class).getBundleContext();
+    	} else {
+    		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 != null && 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



Mime
View raw message