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