You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2007/03/28 16:34:04 UTC

svn commit: r523345 [2/2] - /incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/

Added: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java?view=auto&rev=523345
==============================================================================
--- incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java (added)
+++ incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java Wed Mar 28 07:34:01 2007
@@ -0,0 +1,731 @@
+/* 
+ * 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.scr;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+
+/**
+ * The <code>DependencyManager</code> extends the <code>ServiceTracker</code>
+ * overwriting the {@link #addingService(ServiceReference)} and
+ * {@link #removedService(ServiceReference, Object)} methods to manage the
+ * a declared reference of a service component.
+ */
+class DependencyManager implements ServiceListener
+{
+    // mask of states ok to send events
+    private static final int STATE_MASK = AbstractComponentManager.STATE_UNSATISFIED
+        | AbstractComponentManager.STATE_ACTIVATING | AbstractComponentManager.STATE_ACTIVE
+        | AbstractComponentManager.STATE_REGISTERED | AbstractComponentManager.STATE_FACTORY;
+
+    // the component to which this dependency belongs
+    private AbstractComponentManager m_componentManager;
+
+    // Reference to the metadata
+    private ReferenceMetadata m_dependencyMetadata;
+
+    // A flag that defines if the bind method receives a ServiceReference
+    private boolean m_bindUsesServiceReference;
+
+    private Map m_tracked;
+
+
+    /**
+     * Constructor that receives several parameters.
+     * 
+     * @param dependency An object that contains data about the dependency
+     */
+    DependencyManager( AbstractComponentManager componentManager, ReferenceMetadata dependency )
+        throws InvalidSyntaxException
+    {
+        m_componentManager = componentManager;
+        m_dependencyMetadata = dependency;
+        m_bindUsesServiceReference = false;
+        m_tracked = new HashMap();
+
+        // register the service listener
+        String filterString = "(" + Constants.OBJECTCLASS + "=" + dependency.getInterface() + ")";
+        if ( dependency.getTarget() != null )
+        {
+            filterString = "(&" + filterString + dependency.getTarget() + ")";
+        }
+        componentManager.getActivator().getBundleContext().addServiceListener( this, filterString );
+
+        // initial registration of services
+        ServiceReference refs[] = componentManager.getActivator().getBundleContext().getServiceReferences( null,
+            filterString );
+        for ( int i = 0; refs != null && i < refs.length; i++ )
+        {
+            addingService( refs[i] );
+        }
+    }
+
+
+    //---------- ServiceListener interface ------------------------------------
+
+    public void serviceChanged( ServiceEvent event )
+    {
+        switch ( event.getType() )
+        {
+            case ServiceEvent.REGISTERED:
+                addingService( event.getServiceReference() );
+                break;
+            case ServiceEvent.MODIFIED:
+                removedService( event.getServiceReference() );
+                addingService( event.getServiceReference() );
+                break;
+            case ServiceEvent.UNREGISTERING:
+                removedService( event.getServiceReference() );
+                break;
+        }
+    }
+
+
+    //---------- Service tracking support -------------------------------------
+
+    /**
+     * Stops using this dependency manager
+     */
+    void close()
+    {
+        BundleContext context = m_componentManager.getActivator().getBundleContext();
+        context.removeServiceListener( this );
+
+        synchronized ( m_tracked )
+        {
+            for ( Iterator ri = m_tracked.keySet().iterator(); ri.hasNext(); )
+            {
+                ServiceReference sr = ( ServiceReference ) ri.next();
+                context.ungetService( sr );
+                ri.remove();
+            }
+        }
+    }
+
+
+    /**
+     * Returns the number of services currently tracked
+     */
+    int size()
+    {
+        synchronized ( m_tracked )
+        {
+            return m_tracked.size();
+        }
+    }
+
+
+    /**
+     * Returns a single (unspecified) service reference
+     */
+    ServiceReference getServiceReference()
+    {
+        synchronized ( m_tracked )
+        {
+            if ( m_tracked.size() > 0 )
+            {
+                return ( ServiceReference ) m_tracked.keySet().iterator().next();
+            }
+
+            return null;
+        }
+    }
+
+
+    /**
+     * Returns an array of service references of the currently tracked
+     * services
+     */
+    ServiceReference[] getServiceReferences()
+    {
+        synchronized ( m_tracked )
+        {
+            if ( m_tracked.size() > 0 )
+            {
+                return ( ServiceReference[] ) m_tracked.keySet().toArray( new ServiceReference[m_tracked.size()] );
+            }
+
+            return null;
+        }
+    }
+
+
+    /**
+     * Returns the service described by the ServiceReference
+     */
+    Object getService( ServiceReference serviceReference )
+    {
+        synchronized ( m_tracked )
+        {
+            return m_tracked.get( serviceReference );
+        }
+    }
+
+
+    /**
+     * Returns a single service instance
+     */
+    Object getService()
+    {
+        synchronized ( m_tracked )
+        {
+            if ( m_tracked.size() > 0 )
+            {
+                return m_tracked.values().iterator().next();
+            }
+
+            return null;
+        }
+    }
+
+
+    /**
+     * Returns an array of service references of the currently tracked
+     * services
+     */
+    Object[] getServices()
+    {
+        synchronized ( m_tracked )
+        {
+            if ( m_tracked.size() > 0 )
+            {
+                return m_tracked.values().toArray( new ServiceReference[m_tracked.size()] );
+            }
+
+            return null;
+        }
+    }
+
+
+    //---------- DependencyManager core ---------------------------------------
+
+    /**
+     * Returns the name of the service reference.
+     */
+    String getName()
+    {
+        return m_dependencyMetadata.getName();
+    }
+
+
+    /**
+     * Returns <code>true</code> if we have at least one service reference or
+     * the dependency is optional.
+     */
+    boolean isValid()
+    {
+        return size() > 0 || m_dependencyMetadata.isOptional();
+    }
+
+
+    /**
+     * initializes a dependency. This method binds all of the service
+     * occurrences to the instance object
+     * 
+     * @return true if the operation was successful, false otherwise
+     */
+    boolean bind( Object instance )
+    {
+        // If no references were received, we have to check if the dependency
+        // is optional, if it is not then the dependency is invalid
+        if ( !isValid() )
+        {
+            return false;
+        }
+
+        // if the instance is null, we do nothing actually but assume success
+        // the instance might be null in the delayed component situation
+        if ( instance == null )
+        {
+            return true;
+        }
+
+        // Get service references
+        ServiceReference refs[] = getServiceReferences();
+
+        // refs can be null if the dependency is optional
+        if ( refs != null )
+        {
+            int max = 1;
+            boolean retval = true;
+
+            if ( m_dependencyMetadata.isMultiple() == true )
+            {
+                max = refs.length;
+            }
+
+            for ( int index = 0; index < max; index++ )
+            {
+                retval = invokeBindMethod( instance, refs[index], getService( refs[index] ) );
+                if ( retval == false && ( max == 1 ) )
+                {
+                    // There was an exception when calling the bind method
+                    Activator.error( "Dependency Manager: Possible exception in the bind method during initialize()",
+                        m_componentManager.getComponentMetadata() );
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * Revoke all bindings. This method cannot throw an exception since it must
+     * try to complete all that it can
+     */
+    void unbind( Object instance )
+    {
+        // if the instance is null, we do nothing actually
+        // the instance might be null in the delayed component situation
+        if ( instance == null )
+        {
+            return;
+        }
+
+        ServiceReference[] allrefs = getServiceReferences();
+
+        if ( allrefs == null )
+            return;
+
+        for ( int i = 0; i < allrefs.length; i++ )
+        {
+            invokeUnbindMethod( instance, allrefs[i], getService( allrefs[i] ) );
+        }
+    }
+
+
+    /**
+     * Gets a bind or unbind method according to the policies described in the
+     * specification
+     * 
+     * @param methodname The name of the method
+     * @param targetClass the class to which the method belongs to
+     * @param parameterClassName the name of the class of the parameter that is
+     *            passed to the method
+     * @return the method or null
+     * @throws java.lang.ClassNotFoundException if the class was not found
+     */
+    private Method getBindingMethod( String methodname, Class targetClass, String parameterClassName )
+    {
+        Method method = null;
+
+        Class parameterClass = null;
+
+        // 112.3.1 The method is searched for using the following priority
+        // 1. The method's parameter type is org.osgi.framework.ServiceReference
+        // 2. The method's parameter type is the type specified by the
+        // reference's interface attribute
+        // 3. The method's parameter type is assignable from the type specified
+        // by the reference's interface attribute
+        try
+        {
+            // Case 1
+
+            method = AbstractComponentManager.getMethod( targetClass, methodname, new Class[]
+                { ServiceReference.class } );
+
+            m_bindUsesServiceReference = true;
+        }
+        catch ( NoSuchMethodException ex )
+        {
+
+            try
+            {
+                // Case2
+
+                m_bindUsesServiceReference = false;
+
+                parameterClass = m_componentManager.getActivator().getBundleContext().getBundle().loadClass(
+                    parameterClassName );
+
+                method = AbstractComponentManager.getMethod( targetClass, methodname, new Class[]
+                    { parameterClass } );
+            }
+            catch ( NoSuchMethodException ex2 )
+            {
+
+                // Case 3
+                method = null;
+
+                // iterate on class hierarchy
+                for ( ; method == null && targetClass != null; targetClass = targetClass.getSuperclass() )
+                {
+                    // Get all potential bind methods
+                    Method candidateBindMethods[] = targetClass.getDeclaredMethods();
+
+                    // Iterate over them
+                    for ( int i = 0; method == null && i < candidateBindMethods.length; i++ )
+                    {
+                        Method currentMethod = candidateBindMethods[i];
+
+                        // Get the parameters for the current method
+                        Class[] parameters = currentMethod.getParameterTypes();
+
+                        // Select only the methods that receive a single
+                        // parameter
+                        // and a matching name
+                        if ( parameters.length == 1 && currentMethod.getName().equals( methodname ) )
+                        {
+
+                            // Get the parameter type
+                            Class theParameter = parameters[0];
+
+                            // Check if the parameter type is assignable from
+                            // the type specified by the reference's interface
+                            // attribute
+                            if ( theParameter.isAssignableFrom( parameterClass ) )
+                            {
+
+                                // Final check: it must be public or protected
+                                if ( Modifier.isPublic( method.getModifiers() )
+                                    || Modifier.isProtected( method.getModifiers() ) )
+                                {
+                                    if ( !method.isAccessible() )
+                                    {
+                                        method.setAccessible( true );
+                                    }
+                                    method = currentMethod;
+
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            catch ( ClassNotFoundException ex2 )
+            {
+                Activator.exception( "Cannot load class used as parameter " + parameterClassName, m_componentManager
+                    .getComponentMetadata(), ex2 );
+            }
+        }
+
+        return method;
+    }
+
+
+    /**
+     * Call the bind method. In case there is an exception while calling the
+     * bind method, the service is not considered to be bound to the instance
+     * object
+     * 
+     * @param implementationObject The object to which the service is bound
+     * @param ref A ServiceReference with the service that will be bound to the
+     *            instance object
+     * @param storeRef A boolean that indicates if the reference must be stored
+     *            (this is used for the delayed components)
+     * @return true if the call was successful, false otherwise
+     */
+    private boolean invokeBindMethod( Object implementationObject, ServiceReference ref, Object service )
+    {
+        // The bind method is only invoked if the implementation object is not
+        // null. This is valid
+        // for both immediate and delayed components
+        if ( implementationObject != null )
+        {
+
+            try
+            {
+                // Get the bind method
+                Activator.trace( "getting bind: " + m_dependencyMetadata.getBind(), m_componentManager
+                    .getComponentMetadata() );
+                Method bindMethod = getBindingMethod( m_dependencyMetadata.getBind(), implementationObject.getClass(),
+                    m_dependencyMetadata.getInterface() );
+
+                if ( bindMethod == null )
+                {
+                    // 112.3.1 If the method is not found , SCR must log an
+                    // error
+                    // message with the log service, if present, and ignore the
+                    // method
+                    Activator.error( "bind() method not found", m_componentManager.getComponentMetadata() );
+                    return false;
+                }
+
+                // Get the parameter
+                Object parameter;
+
+                if ( m_bindUsesServiceReference == false )
+                {
+                    parameter = service;
+                }
+                else
+                {
+                    parameter = ref;
+                }
+
+                // Invoke the method
+                bindMethod.invoke( implementationObject, new Object[]
+                    { parameter } );
+
+                Activator.trace( "bound: " + getName(), m_componentManager.getComponentMetadata() );
+
+                return true;
+            }
+            catch ( IllegalAccessException ex )
+            {
+                // 112.3.1 If the method is not is not declared protected or
+                // public, SCR must log an error
+                // message with the log service, if present, and ignore the
+                // method
+                Activator.exception( "bind() method cannot be called", m_componentManager.getComponentMetadata(), ex );
+                return false;
+            }
+            catch ( InvocationTargetException ex )
+            {
+                Activator.exception( "DependencyManager : exception while invoking " + m_dependencyMetadata.getBind()
+                    + "()", m_componentManager.getComponentMetadata(), ex );
+                return false;
+            }
+        }
+        else if ( implementationObject == null && m_componentManager.getComponentMetadata().isImmediate() == false )
+        {
+            return true;
+        }
+        else
+        {
+            // this is not expected: if the component is immediate the
+            // implementationObject is not null (asserted by the caller)
+            return false;
+        }
+    }
+
+
+    /**
+     * Call the unbind method
+     * 
+     * @param implementationObject The object from which the service is unbound
+     * @param ref A service reference corresponding to the service that will be
+     *            unbound
+     * @return true if the call was successful, false otherwise
+     */
+    private boolean invokeUnbindMethod( Object implementationObject, ServiceReference ref, Object service )
+    {
+        // The unbind method is only invoked if the implementation object is not
+        // null. This is valid for both immediate and delayed components
+        if ( implementationObject != null )
+        {
+            try
+            {
+                Activator.trace( "getting unbind: " + m_dependencyMetadata.getUnbind(), m_componentManager
+                    .getComponentMetadata() );
+                Method unbindMethod = getBindingMethod( m_dependencyMetadata.getUnbind(), implementationObject
+                    .getClass(), m_dependencyMetadata.getInterface() );
+
+                // Recover the object that is bound from the map.
+                // Object parameter = m_boundServices.get(ref);
+                Object parameter = null;
+
+                if ( m_bindUsesServiceReference == true )
+                {
+                    parameter = ref;
+                }
+                else
+                {
+                    parameter = service;
+                }
+
+                if ( unbindMethod == null )
+                {
+                    // 112.3.1 If the method is not found , SCR must log an
+                    // error
+                    // message with the log service, if present, and ignore the
+                    // method
+                    Activator.error( "unbind() method not found", m_componentManager.getComponentMetadata() );
+                    return false;
+                }
+
+                unbindMethod.invoke( implementationObject, new Object[]
+                    { parameter } );
+
+                Activator.trace( "unbound: " + getName(), m_componentManager.getComponentMetadata() );
+
+                return true;
+            }
+            catch ( IllegalAccessException ex )
+            {
+                // 112.3.1 If the method is not is not declared protected or
+                // public, SCR must log an error
+                // message with the log service, if present, and ignore the
+                // method
+                Activator.exception( "unbind() method cannot be called", m_componentManager.getComponentMetadata(), ex );
+                return false;
+            }
+            catch ( InvocationTargetException ex )
+            {
+                Activator.exception( "DependencyManager : exception while invoking " + m_dependencyMetadata.getUnbind()
+                    + "()", m_componentManager.getComponentMetadata(), ex );
+                return false;
+            }
+
+        }
+        else if ( implementationObject == null && m_componentManager.getComponentMetadata().isImmediate() == false )
+        {
+            return true;
+        }
+        else
+        {
+            // this is not expected: if the component is immediate the
+            // implementationObject is not null (asserted by the caller)
+            return false;
+        }
+    }
+
+
+    private void addingService( ServiceReference reference )
+    {
+        // get the service and keep it here (for now or later)
+        Object service = m_componentManager.getActivator().getBundleContext().getService( reference );
+        synchronized ( m_tracked )
+        {
+            m_tracked.put( reference, service );
+        }
+
+        // forward the event if in event hanlding state
+        if ( handleServiceEvent() )
+        {
+
+            // the component is UNSATISFIED if enabled but any of the references
+            // have been missing when activate was running the last time or
+            // the component has been deactivated
+            if ( m_componentManager.getState() == AbstractComponentManager.STATE_UNSATISFIED )
+            {
+                m_componentManager.activate();
+            }
+
+            // Otherwise, this checks for dynamic 0..1, 0..N, and 1..N
+            // it never
+            // checks for 1..1 dynamic which is done above by the
+            // validate()
+            else if ( !m_dependencyMetadata.isStatic() )
+            {
+                // For dependency that are aggregates, always bind the
+                // service
+                // Otherwise only bind if bind services is zero, which
+                // captures the 0..1 case
+                // (size is still zero as we are called for the first service)
+                if ( m_dependencyMetadata.isMultiple() || size() == 0 )
+                {
+                    invokeBindMethod( m_componentManager.getInstance(), reference, service );
+                }
+            }
+        }
+    }
+
+
+    public void removedService( ServiceReference reference )
+    {
+        // remove the service from the internal registry, ignore if not cached
+        Object service;
+        synchronized ( m_tracked )
+        {
+            service = m_tracked.remove( reference );
+        }
+
+        // do nothing in the unlikely case that we do not have it cached
+        if ( service == null )
+        {
+            return;
+        }
+
+        if ( handleServiceEvent() )
+        {
+            // A static dependency is broken the instance manager will
+            // be invalidated
+            if ( m_dependencyMetadata.isStatic() )
+            {
+                // setStateDependency(DependencyChangeEvent.DEPENDENCY_INVALID);
+                try
+                {
+                    Activator.trace( "Dependency Manager: Static dependency is broken", m_componentManager
+                        .getComponentMetadata() );
+                    m_componentManager.reactivate();
+                }
+                catch ( Exception ex )
+                {
+                    Activator.exception( "Exception while recreating dependency ", m_componentManager
+                        .getComponentMetadata(), ex );
+                }
+            }
+            // dynamic dependency
+            else
+            {
+                // Release references to the service, call unbinder
+                // method
+                // and eventually request service unregistration
+                Object instance = m_componentManager.getInstance();
+                invokeUnbindMethod( instance, reference, service );
+
+                // The only thing we need to do here is check if we can
+                // reinitialize
+                // once the bound services becomes zero. This tries to
+                // repair dynamic
+                // 1..1 or rebind 0..1, since replacement services may
+                // be available.
+                // In the case of aggregates, this will only invalidate
+                // them since they
+                // can't be repaired.
+                if ( size() == 0 )
+                {
+                    // try to reinitialize
+                    if ( !bind( instance ) )
+                    {
+                        if ( !m_dependencyMetadata.isOptional() )
+                        {
+                            Activator
+                                .trace(
+                                    "Dependency Manager: Mandatory dependency not fullfilled and no replacements available... unregistering service...",
+                                    m_componentManager.getComponentMetadata() );
+                            m_componentManager.reactivate();
+                        }
+                    }
+                }
+            }
+        }
+
+        // finally unget the service
+        m_componentManager.getActivator().getBundleContext().ungetService( reference );
+    }
+
+
+    private boolean handleServiceEvent()
+    {
+        return ( m_componentManager.getState() & STATE_MASK ) != 0;
+        //        return state != AbstractComponentManager.INSTANCE_DESTROYING
+        //            && state != AbstractComponentManager.INSTANCE_DESTROYED
+        //            && state != AbstractComponentManager.INSTANCE_CREATING 
+        //            && state != AbstractComponentManager.INSTANCE_CREATED;
+    }
+}

Propchange: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java?view=auto&rev=523345
==============================================================================
--- incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java (added)
+++ incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java Wed Mar 28 07:34:01 2007
@@ -0,0 +1,299 @@
+/* 
+ * 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.scr;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentInstance;
+
+
+/**
+ * The default ComponentManager. Objects of this class are responsible for managing
+ * implementation object's lifecycle.  
+ *
+ */
+class ImmediateComponentManager extends AbstractComponentManager
+{
+    // the component ID
+    private long m_componentId;
+
+    // The object that implements the service and that is bound to other services
+    private Object m_implementationObject = null;
+
+    // The context that will be passed to the implementationObject
+    private ComponentContext m_componentContext = null;
+    
+    // optional properties provided in the ComponentFactory.newInstance method
+    private Dictionary m_factoryProperties; 
+    
+    // the component properties, also used as service properties
+    private Dictionary m_properties; 
+    
+    /**
+     * The constructor receives both the activator and the metadata
+     * 
+     * @param activator
+     * @param metadata
+     */
+    ImmediateComponentManager(BundleComponentActivator activator, ComponentMetadata metadata, long componentId)
+    {
+        super(activator, metadata);
+        
+        m_componentId = componentId;
+    }
+  
+
+    // 1. Load the component implementation class
+    // 2. Create the component instance and component context
+    // 3. Bind the target services
+    // 4. Call the activate method, if present
+    protected void createComponent()
+    {
+        ComponentContext tmpContext = new ComponentContextImpl( this );
+        Object tmpObject = createImplementationObject( tmpContext );
+        
+        // if something failed craeating the object, we fell back to
+        // unsatisfied !!
+        if (tmpObject != null) {
+            m_componentContext = tmpContext;
+            m_implementationObject = tmpObject;
+        }
+    }
+    
+    protected void deleteComponent() {
+        deactivateImplementationObject( m_implementationObject, m_componentContext );
+        m_implementationObject = null;
+        m_componentContext = null;
+        m_properties = null;
+    }
+
+
+    //**********************************************************************************************************
+    
+    /**
+    * Get the object that is implementing this descriptor
+    *
+    * @return the object that implements the services
+    */
+    public Object getInstance() {
+        return m_implementationObject;
+    }
+
+    protected Object createImplementationObject(ComponentContext componentContext) {
+        Object implementationObject;
+        
+        // 1. Load the component implementation class
+        // 2. Create the component instance and component context
+        // If the component is not immediate, this is not done at this moment
+        try
+        {
+            // 112.4.4 The class is retrieved with the loadClass method of the component's bundle
+            Class c = getActivator().getBundleContext().getBundle().loadClass(getComponentMetadata().getImplementationClassName());
+            
+            // 112.4.4 The class must be public and have a public constructor without arguments so component instances
+            // may be created by the SCR with the newInstance method on Class
+            implementationObject = c.newInstance();
+        }
+        catch (Exception ex)
+        {
+            // failed to instantiate, deactivate the component and return null
+            Activator.exception( "Error during instantiation of the implementation object", getComponentMetadata(), ex );
+            deactivate();
+            return null;
+        }
+        
+        
+        // 3. Bind the target services
+        Iterator it = getDependencyManagers();
+        while ( it.hasNext() )
+        {
+            // if a dependency turned unresolved since the validation check,
+            // creating the instance fails here, so we deactivate and return
+            // null.
+            DependencyManager dm = ( DependencyManager ) it.next();
+            if ( !dm.bind( implementationObject ) )
+            {
+                Activator.error( "Cannot create component instance due to failure to bind reference " + dm.getName(),
+                    getComponentMetadata() );
+                deactivate();
+                return null;
+            }
+        }
+        
+        // 4. Call the activate method, if present
+        // Search for the activate method
+        try
+        {
+            Method activateMethod = getMethod( implementationObject.getClass(), "activate", new Class[]
+                { ComponentContext.class } );
+            activateMethod.invoke( implementationObject, new Object[]
+                { componentContext } );
+        }
+        catch ( NoSuchMethodException ex )
+        {
+            // We can safely ignore this one
+            Activator.trace( "activate() method is not implemented", getComponentMetadata() );
+        }
+        catch ( IllegalAccessException ex )
+        {
+            // Ignored, but should it be logged?
+            Activator.trace( "activate() method cannot be called", getComponentMetadata() );
+        }
+        catch ( InvocationTargetException ex )
+        {
+            // 112.5.8 If the activate method throws an exception, SCR must log an error message
+            // containing the exception with the Log Service
+            Activator.exception( "The activate method has thrown an exception", getComponentMetadata(), ex );
+        }
+        
+        return implementationObject;
+    }
+
+    protected void deactivateImplementationObject( Object implementationObject, ComponentContext componentContext )
+    {
+        // 1. Call the deactivate method, if present
+        // Search for the activate method
+        try
+        {
+            Method deactivateMethod = getMethod( implementationObject.getClass(), "deactivate", new Class[]
+                { ComponentContext.class } );
+            deactivateMethod.invoke( implementationObject, new Object[]
+                { componentContext } );
+        }
+        catch ( NoSuchMethodException ex )
+        {
+            // We can safely ignore this one
+            Activator.trace( "deactivate() method is not implemented", getComponentMetadata() );
+        }
+        catch ( IllegalAccessException ex )
+        {
+            // Ignored, but should it be logged?
+            Activator.trace( "deactivate() method cannot be called", getComponentMetadata() );
+        }
+        catch ( InvocationTargetException ex )
+        {
+            // 112.5.12 If the deactivate method throws an exception, SCR must log an error message
+            // containing the exception with the Log Service and continue
+            Activator.exception( "The deactivate method has thrown an exception", getComponentMetadata(), ex );
+        }
+
+        // 2. Unbind any bound services
+        Iterator it = getDependencyManagers();
+
+        while ( it.hasNext() )
+        {
+            DependencyManager dm = ( DependencyManager ) it.next();
+            dm.unbind( implementationObject );
+        }
+
+        // 3. Release all references
+        // nothing to do, we keep no references on per-Bundle services
+    }
+    
+    /**
+     * Returns the service object to be registered if the service element is
+     * specified.
+     * <p>
+     * Extensions of this class may overwrite this method to return a
+     * ServiceFactory to register in the case of a delayed or a service
+     * factory component. 
+     */
+    protected Object getService() {
+        return m_implementationObject;
+    }
+    
+    protected void setFactoryProperties(Dictionary dictionary) {
+        m_factoryProperties = copyTo( null, dictionary );
+    }
+    
+    /**
+     * Returns the (private copy) of the Component properties to be used
+     * for the ComponentContext as well as eventual service registration.
+     * <p>
+     * Method implements the Component Properties provisioning as described
+     * in 112.6, Component Properties.
+     * 
+     * @return a private Hashtable of component properties
+     */
+    protected Dictionary getProperties()
+    {
+
+        // TODO: Currently on ManagedService style configuration is supported, ManagedServiceFactory style is missing
+
+        if ( m_properties == null )
+        {
+
+            // 1. the properties from the component descriptor
+            Dictionary props = copyTo( null, getComponentMetadata().getProperties() );
+
+            // 2. overlay with Configuration Admin properties
+            ConfigurationAdmin ca = getActivator().getConfigurationAdmin();
+            if ( ca != null )
+            {
+                try
+                {
+                    Configuration cfg = ca.getConfiguration( getComponentMetadata().getName() );
+                    if (cfg != null) {
+                        copyTo( props, cfg.getProperties() );
+                    }
+                }
+                catch ( IOException ioe )
+                {
+                    Activator.exception( "Problem getting Configuration", getComponentMetadata(), ioe );
+                }
+            }
+
+            // 3. copy any component factory properties, not supported yet
+            copyTo( props, m_factoryProperties );
+            
+            // 4. set component.name and component.id
+            props.put( ComponentConstants.COMPONENT_NAME, getComponentMetadata().getName() );
+            props.put( ComponentConstants.COMPONENT_ID, new Long( m_componentId ) );
+            
+            m_properties = props;
+        }
+
+        return m_properties;
+    }
+    
+}

Propchange: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Modified: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ManagerFactory.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ManagerFactory.java?view=diff&rev=523345&r1=523344&r2=523345
==============================================================================
--- incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ManagerFactory.java (original)
+++ incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ManagerFactory.java Wed Mar 28 07:34:01 2007
@@ -18,15 +18,34 @@
  */
 package org.apache.felix.scr;
 
+
 /**
  * This factory allows other types of ComponentManagers to be provided.
  * 
  * 
  */
-public class ManagerFactory {
-	
-	static ComponentManager createManager(BundleComponentActivator activator, ComponentMetadata metadata) {
-	    Activator.trace("ManagerFactory.createManager", metadata);
-	    return new ComponentManagerImpl(activator,metadata);
-	}
+public class ManagerFactory
+{
+
+    static ComponentManager createManager( BundleComponentActivator activator, ComponentMetadata metadata,
+        long componentId )
+    {
+        Activator.trace( "ManagerFactory.createManager", metadata );
+        if ( metadata.isImmediate() )
+        {
+            return new ImmediateComponentManager( activator, metadata, componentId );
+        }
+        else if ( metadata.getServiceMetadata() != null )
+        {
+            if ( metadata.getServiceMetadata().isServiceFactory() )
+            {
+                return new ServiceFactoryComponentManager( activator, metadata, componentId );
+            }
+
+            return new DelayedComponentManager( activator, metadata, componentId );
+        }
+
+        // if we get here, which is not expected after all, we fail
+        throw new IllegalArgumentException( "Cannot create a component manager for " + metadata.getName() );
+    }
 }

Added: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ReadOnlyDictionary.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ReadOnlyDictionary.java?view=auto&rev=523345
==============================================================================
--- incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ReadOnlyDictionary.java (added)
+++ incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ReadOnlyDictionary.java Wed Mar 28 07:34:01 2007
@@ -0,0 +1,108 @@
+/* 
+ * 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.scr;
+
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+
+/**
+ * The <code>ReadOnlyDictionary</code> is a <code>Dictionary</code> whose
+ * {@link #put(Object, Object)} and {@link #remove(Object)} methods have 
+ * no effect and always return <code>null</code>.
+ *
+ * @author fmeschbe
+ */
+public class ReadOnlyDictionary extends Dictionary
+{
+
+    private Dictionary delegatee;
+
+
+    ReadOnlyDictionary( Dictionary delegatee )
+    {
+        this.delegatee = delegatee;
+    }
+
+
+    /* (non-Javadoc)
+     * @see java.util.Dictionary#elements()
+     */
+    public Enumeration elements()
+    {
+        return delegatee.elements();
+    }
+
+
+    /* (non-Javadoc)
+     * @see java.util.Dictionary#get(java.lang.Object)
+     */
+    public Object get( Object key )
+    {
+        return delegatee.get( key );
+    }
+
+
+    /* (non-Javadoc)
+     * @see java.util.Dictionary#isEmpty()
+     */
+    public boolean isEmpty()
+    {
+        return delegatee.isEmpty();
+    }
+
+
+    /* (non-Javadoc)
+     * @see java.util.Dictionary#keys()
+     */
+    public Enumeration keys()
+    {
+        return delegatee.keys();
+    }
+
+
+    /**
+     * This method has no effect and always returns <code>null</code> as this
+     * instance is read-only and cannot modify and properties.
+     */
+    public Object put( Object arg0, Object arg1 )
+    {
+        return null;
+    }
+
+
+    /**
+     * This method has no effect and always returns <code>null</code> as this
+     * instance is read-only and cannot modify and properties.
+     */
+    public Object remove( Object key )
+    {
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see java.util.Dictionary#size()
+     */
+    public int size()
+    {
+        return delegatee.size();
+    }
+}

Propchange: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ReadOnlyDictionary.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ReadOnlyDictionary.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java?view=auto&rev=523345
==============================================================================
--- incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java (added)
+++ incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java Wed Mar 28 07:34:01 2007
@@ -0,0 +1,180 @@
+/* 
+ * 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.scr;
+
+
+import java.util.IdentityHashMap;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentInstance;
+
+
+/**
+ * The <code>ServiceFactoryComponentManager</code> TODO
+ *
+ * @author fmeschbe
+ * @version $Rev$, $Date$
+ */
+public class ServiceFactoryComponentManager extends ImmediateComponentManager implements ServiceFactory
+{
+
+    // we do not have to maintain references to the actual service
+    // instances as those are handled by the ServiceManager and given
+    // to the ungetService method when the bundle releases the service
+
+    // maintain the map of componentContext objects created for the
+    // service instances
+    private IdentityHashMap componentContexts = new IdentityHashMap();
+
+
+    /**
+     * @param activator
+     * @param metadata
+     */
+    public ServiceFactoryComponentManager( BundleComponentActivator activator, ComponentMetadata metadata,
+        long componentId )
+    {
+        super( activator, metadata, componentId );
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.scr.AbstractComponentManager#createComponent()
+     */
+    protected void createComponent()
+    {
+        // nothing to do, this is handled by getService
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.scr.AbstractComponentManager#deleteComponent()
+     */
+    protected void deleteComponent()
+    {
+        // nothing to do, this is handled by ungetService
+    }
+
+
+    protected Object getService()
+    {
+        return this;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.felix.scr.AbstractComponentManager#getInstance()
+     */
+    public Object getInstance()
+    {
+        // this method is not expected to be called as the base call is
+        // overwritten in the BundleComponentContext class
+        return null;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
+     */
+    public Object getService( Bundle bundle, ServiceRegistration registration )
+    {
+        Activator.trace( "DelayedServiceFactoryServiceFactory.getService()", getComponentMetadata() );
+        // When the getServiceMethod is called, the implementation object must be created
+
+        // private ComponentContext and implementation instances
+        BundleComponentContext componentContext = new BundleComponentContext( this, bundle );
+        Object implementationObject = createImplementationObject( componentContext );
+
+        // register the components component context if successfull
+        if (implementationObject != null) {
+            componentContext.setImplementationObject( implementationObject );
+            componentContexts.put( implementationObject, componentContext );
+
+            // if this is the first use of this component, switch to ACTIVE state
+            if (getState() == STATE_REGISTERED)
+            {
+                setState( STATE_ACTIVE );
+            }
+        }
+        
+        return implementationObject;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.osgi.framework.ServiceFactory#ungetService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration, java.lang.Object)
+     */
+    public void ungetService( Bundle bundle, ServiceRegistration registration, Object service )
+    {
+        Activator.trace( "DelayedServiceFactoryServiceFactory.ungetService()", getComponentMetadata() );
+        // When the ungetServiceMethod is called, the implementation object must be deactivated
+
+        // private ComponentContext and implementation instances
+        ComponentContext componentContext = ( ComponentContext ) componentContexts.remove( service );
+        deactivateImplementationObject( service, componentContext );
+        
+        // if this was the last use of the component, go back to REGISTERED state
+        if ( componentContexts.isEmpty() && getState() == STATE_ACTIVE )
+        {
+            setState( STATE_REGISTERED );
+        }
+    }
+
+    private static class BundleComponentContext extends ComponentContextImpl implements ComponentInstance {
+        
+        private Bundle m_usingBundle;
+        private Object m_implementationObject;
+
+        BundleComponentContext(AbstractComponentManager componentManager, Bundle usingBundle) {
+            super(componentManager);
+            
+            m_usingBundle = usingBundle;
+        }
+        
+        private void setImplementationObject( Object implementationObject )
+        {
+            m_implementationObject = implementationObject;
+        }
+        
+        public Bundle getUsingBundle()
+        {
+            return m_usingBundle;
+        }
+        
+        public ComponentInstance getComponentInstance()
+        {
+            return this;
+        }
+        
+        //---------- ComponentInstance interface ------------------------------
+        
+        public Object getInstance()
+        {
+            return m_implementationObject;
+        }
+        
+        public void dispose()
+        {
+            getComponentManager().dispose();
+        }
+    }
+}

Propchange: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/felix/trunk/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url