FELIX-258 Support Configuration Admin configuration
FELIX-259 Add support for factory components
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@523345 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java
new file mode 100644
index 0000000..0115d58
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/AbstractComponentManager.java
@@ -0,0 +1,576 @@
+/*
+ * 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.
+ *
+ */
+abstract class AbstractComponentManager implements ComponentManager, ComponentInstance
+{
+ // manager has been newly created or disabled
+ static final int STATE_DISABLED = 1;
+
+ // manager has just been enabled and is going to be activated
+ static final int STATE_ENABLED = 2;
+
+ // manager has been enabled but not satisfied
+ static final int STATE_UNSATISFIED = 4;
+
+ // manager is currently activating
+ static final int STATE_ACTIVATING = 8;
+
+ // manager is now active
+ static final int STATE_ACTIVE = 16;
+
+ // manager for a delayed component has been registered (not active yet)
+ static final int STATE_REGISTERED = 32;
+
+ // manager for a component factory has been registered
+ static final int STATE_FACTORY = 64;
+
+ // manager is current deactivating
+ static final int STATE_DEACTIVATING = 128;
+
+ // manager has been destroyed and may not be used anymore
+ static final int STATE_DESTROYED = 256;
+
+ // The state of this instance manager
+ private int m_state;
+
+ // The metadata
+ private ComponentMetadata m_componentMetadata;
+
+ // The dependency managers that manage every dependency
+ private List m_dependencyManagers;
+
+ // A reference to the BundleComponentActivator
+ private BundleComponentActivator m_activator;
+
+ // The ServiceRegistration
+ private ServiceRegistration m_serviceRegistration;
+
+ /**
+ * The constructor receives both the activator and the metadata
+ *
+ * @param activator
+ * @param metadata
+ */
+ protected AbstractComponentManager(BundleComponentActivator activator, ComponentMetadata metadata)
+ {
+ m_activator = activator;
+ m_componentMetadata = metadata;
+
+ m_state = STATE_DISABLED;
+ m_dependencyManagers = new ArrayList();
+ }
+
+ /**
+ * Enable this component
+ *
+ * @return true if enabling was successful
+ */
+ public synchronized boolean enable() {
+
+ if (getState() == STATE_DESTROYED)
+ {
+ Activator.error( "Destroyed Component cannot be enabled", m_componentMetadata );
+ return false;
+ }
+ else if (getState() != STATE_DISABLED)
+ {
+ Activator.trace( "Component is already enabled", m_componentMetadata );
+ return true;
+ }
+
+ Activator.trace("Enabling component", m_componentMetadata);
+
+ try
+ {
+ // If this component has got dependencies, create dependency managers for each one of them.
+ if (m_componentMetadata.getDependencies().size() != 0)
+ {
+ Iterator dependencyit = m_componentMetadata.getDependencies().iterator();
+
+ while(dependencyit.hasNext())
+ {
+ ReferenceMetadata currentdependency = (ReferenceMetadata)dependencyit.next();
+
+ DependencyManager depmanager = new DependencyManager(this, currentdependency);
+
+ m_dependencyManagers.add(depmanager);
+ }
+ }
+
+ // enter enabled state before trying to activate
+ setState(STATE_ENABLED);
+
+ activate();
+
+ return true;
+ }
+ catch(Exception ex)
+ {
+ Activator.exception( "Failed enabled Component", m_componentMetadata, ex );
+
+ // ensure we get back to DISABLED state
+ disable();
+
+ return false;
+ }
+ }
+
+ /**
+ * Activate this Instance manager.
+ *
+ * 112.5.6 Activating a component configuration consists of the following steps
+ * 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
+ * [5. Register provided services]
+ */
+ synchronized void activate()
+ {
+ // CONCURRENCY NOTE: This method is called either by the enable()
+ // method or by the dependency managers or the reconfigure() method
+ if ( (getState() & (STATE_ENABLED|STATE_UNSATISFIED)) == 0)
+ {
+ // This state can only be entered from the ENABLED (in the enable()
+ // method) or UNSATISFIED (missing references) states
+ return;
+ }
+
+ // go to the activating state
+ setState(STATE_ACTIVATING);
+
+ // Before creating the implementation object, we are going to
+ // test if all the mandatory dependencies are satisfied
+ Iterator it = m_dependencyManagers.iterator();
+ while (it.hasNext())
+ {
+ DependencyManager dm = (DependencyManager)it.next();
+ if (!dm.isValid())
+ {
+ // at least one dependency is not satisfied
+ Activator.trace( "Dependency not satisfied: " + dm.getName(), m_componentMetadata );
+ setState(STATE_UNSATISFIED);
+ return;
+ }
+ }
+
+ // 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
+ createComponent();
+
+ // Validation occurs before the services are provided, otherwhise the
+ // service provider's service may be called by a service requester
+ // while it is still ACTIVATING
+ setState(getSatisfiedState());
+
+ // 5. Register provided services
+ m_serviceRegistration = registerComponentService();
+ }
+
+ /**
+ * Method is called by {@link #activate()} in STATE_ACTIVATING or by
+ * {@link DelayedComponentManager#getService(Bundle, ServiceRegistration)}
+ * in STATE_REGISTERED.
+ */
+ protected abstract void createComponent();
+
+ /**
+ * Method is called by {@link #deactivate()} in STATE_DEACTIVATING
+ *
+ */
+ protected abstract void deleteComponent();
+
+ /**
+ * Returns the state value to set, when the component is satisfied. The
+ * return value depends on the kind of the component:
+ * <dl>
+ * <dt>Immediate</dt><dd><code>STATE_ACTIVE</code></dd>
+ * <dt>Delayed</dt><dd><code>STATE_REGISTERED</code></dd>
+ * <dt>Component Factory</dt><dd><code>STATE_FACTORY</code></dd>
+ * </dl>
+ *
+ * @return
+ */
+ private int getSatisfiedState() {
+ if (m_componentMetadata.isFactory())
+ {
+ return STATE_FACTORY;
+ }
+ else if (m_componentMetadata.isImmediate())
+ {
+ return STATE_ACTIVE;
+ }
+ else
+ {
+ return STATE_REGISTERED;
+ }
+ }
+
+ /**
+ * 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 abstract Object getService();
+
+
+ // 5. Register provided services
+ protected ServiceRegistration registerComponentService()
+ {
+ if ( getComponentMetadata().getServiceMetadata() != null )
+ {
+ Activator.trace( "registering services", getComponentMetadata() );
+
+ // get a copy of the component properties as service properties
+ Dictionary serviceProperties = copyTo( null, getProperties() );
+
+ return getActivator().getBundleContext().registerService(
+ getComponentMetadata().getServiceMetadata().getProvides(), getService(), serviceProperties );
+ }
+
+ return null;
+ }
+
+ protected void unregisterComponentService()
+ {
+ if ( m_serviceRegistration != null )
+ {
+ m_serviceRegistration.unregister();
+ m_serviceRegistration = null;
+
+ Activator.trace( "unregistering the services", getComponentMetadata() );
+ }
+ }
+
+ /**
+ * Reconfigures this component by deactivating and activating it. During
+ * activation the new configuration data is retrieved from the Configuration
+ * Admin Service.
+ */
+ public void reconfigure()
+ {
+ Activator.trace( "Deactivating and Activating to reconfigure", m_componentMetadata );
+ reactivate();
+ }
+
+ /**
+ * Deactivates and activates this component instance.
+ */
+ void reactivate() {
+ deactivate();
+ Activator.trace( "Dependency Manager: RECREATING", m_componentMetadata );
+ activate();
+ }
+
+ /**
+ * This method deactivates the manager, performing the following steps
+ *
+ * [0. Remove published services from the registry]
+ * 1. Call the deactivate() method, if present
+ * 2. Unbind any bound services
+ * 3. Release references to the component instance and component context
+ **/
+ synchronized void deactivate()
+ {
+ // CONCURRENCY NOTE: This method may be called either from application
+ // code or by the dependency managers or reconfiguration
+ if ((getState() & (STATE_ACTIVATING|STATE_ACTIVE|STATE_REGISTERED|STATE_FACTORY)) == 0)
+ {
+ // This state can only be entered from the ACTIVATING (if activation
+ // fails), ACTIVE, REGISTERED or FACTORY states
+ return;
+ }
+// if (m_state != INSTANCE_VALID && m_state != INSTANCE_VALIDATING && m_state != INSTANCE_DESTROYING) {
+// return;
+// }
+
+ // start deactivation by resetting the state
+ setState( STATE_DEACTIVATING );
+
+ // 0.- Remove published services from the registry
+ unregisterComponentService();
+
+ // 1.- Call the deactivate method, if present
+ // 2. Unbind any bound services
+ // 3. Release references to the component instance and component context
+ deleteComponent();
+
+ //Activator.trace("InstanceManager from bundle ["+ m_activator.getBundleContext().getBundle().getBundleId() + "] was invalidated.");
+
+ // reset to state UNSATISFIED
+ setState( STATE_UNSATISFIED );
+ }
+
+ public synchronized void disable()
+ {
+ // CONCURRENCY NOTE: This method is only called from the BundleComponentActivator or by application logic
+ // but not by the dependency managers
+
+ // deactivate first, this does nothing if not active/registered/factory
+ deactivate();
+
+ // close all service listeners now, they are recreated on enable
+ // Stop the dependency managers to listen to events...
+ Iterator it = m_dependencyManagers.iterator();
+ while (it.hasNext())
+ {
+ DependencyManager dm = (DependencyManager)it.next();
+ dm.close();
+ }
+ m_dependencyManagers.clear();
+
+ // we are now disabled, ready for re-enablement or complete destroyal
+ setState( STATE_DISABLED );
+ }
+
+ /**
+ *
+ */
+ public synchronized void dispose()
+ {
+ // CONCURRENCY NOTE: This method is only called from the BundleComponentActivator or by application logic
+ // but not by the dependency managers
+
+ // disable first to clean up correctly
+ disable();
+
+ // this component must not be used any more
+ setState( STATE_DISABLED );
+
+ // release references (except component metadata for logging purposes)
+ m_activator = null;
+ m_dependencyManagers = null;
+ }
+
+ //**********************************************************************************************************
+
+ BundleComponentActivator getActivator() {
+ return m_activator;
+ }
+
+ Iterator getDependencyManagers() {
+ return m_dependencyManagers.iterator();
+ }
+
+ DependencyManager getDependencyManager( String name )
+ {
+ Iterator it = getDependencyManagers();
+ while ( it.hasNext() )
+ {
+ DependencyManager dm = ( DependencyManager ) it.next();
+ if ( name.equals( dm.getName() ) )
+ {
+ // only return the dm if it has service references
+ return ( dm.size() > 0 ) ? dm : null;
+ }
+ }
+
+ // not found
+ return null;
+ }
+
+ /**
+ * Get the object that is implementing this descriptor
+ *
+ * @return the object that implements the services
+ */
+ public abstract Object getInstance();
+ protected abstract Dictionary getProperties();
+
+ /**
+ * Copies the properties from the <code>source</code> <code>Dictionary</code>
+ * into the <code>target</code> <code>Dictionary</code>.
+ *
+ * @param target The <code>Dictionary</code> into which to copy the
+ * properties. If <code>null</code> a new <code>Hashtable</code> is
+ * created.
+ * @param source The <code>Dictionary</code> providing the properties to
+ * copy. If <code>null</code> or empty, nothing is copied.
+ *
+ * @return The <code>target</code> is returned, which may be empty if
+ * <code>source</code> is <code>null</code> or empty and
+ * <code>target</code> was <code>null</code>.
+ */
+ protected Dictionary copyTo( Dictionary target, Dictionary source )
+ {
+ if ( target == null )
+ {
+ target = new Hashtable();
+ }
+
+ if ( source != null && !source.isEmpty() )
+ {
+ for ( Enumeration ce = source.keys(); ce.hasMoreElements(); )
+ {
+ Object key = ce.nextElement();
+ target.put( key, source.get( key ) );
+ }
+ }
+
+ return target;
+ }
+
+ ServiceReference getServiceReference() {
+ return ( m_serviceRegistration != null ) ? m_serviceRegistration.getReference() : null;
+ }
+
+ /**
+ *
+ */
+ public ComponentMetadata getComponentMetadata() {
+ return m_componentMetadata;
+ }
+
+ int getState() {
+ return m_state;
+ }
+
+ /**
+ * sets the state of the manager
+ **/
+ protected synchronized void setState(int newState) {
+ Activator.trace( "State transition : " + stateToString( m_state ) + " -> " + stateToString( newState ),
+ m_componentMetadata );
+
+ m_state = newState;
+ }
+
+ private String stateToString(int state) {
+ switch (state) {
+ case STATE_DESTROYED:
+ return "Destroyed";
+ case STATE_DISABLED:
+ return "Disabled";
+ case STATE_ENABLED:
+ return "Enabled";
+ case STATE_UNSATISFIED:
+ return "Unsatisfied";
+ case STATE_ACTIVATING:
+ return "Activating";
+ case STATE_ACTIVE:
+ return "Active";
+ case STATE_REGISTERED:
+ return "Registered";
+ case STATE_FACTORY:
+ return "Factory";
+ case STATE_DEACTIVATING:
+ return "Deactivating";
+ default:
+ return String.valueOf(state);
+ }
+ }
+ /**
+ * Finds the named public or protected method in the given class or any
+ * super class. If such a method is found, its accessibility is enfored by
+ * calling the <code>Method.setAccessible</code> method if required and
+ * the method is returned. Enforcing accessibility is required to support
+ * invocation of protected methods.
+ *
+ * @param clazz The <code>Class</code> which provides the method.
+ * @param name The name of the method.
+ * @param parameterTypes The parameters to the method. Passing
+ * <code>null</code> is equivalent to using an empty array.
+ *
+ * @return The named method with enforced accessibility
+ *
+ * @throws NoSuchMethodException If no public or protected method with
+ * the given name can be found in the class or any of its super classes.
+ */
+ static Method getMethod(Class clazz, String name, Class[] parameterTypes)
+ throws NoSuchMethodException
+ {
+ // try the default mechanism first, which only yields public methods
+ try
+ {
+ return clazz.getMethod(name, parameterTypes);
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ // it is ok to not find a public method, try to find a protected now
+ }
+
+ // now use method declarations, requiring walking up the class
+ // hierarchy manually. this algorithm also returns protected methods
+ // which is, what we need here
+ for ( ; clazz != null; clazz = clazz.getSuperclass())
+ {
+ try
+ {
+ Method method = clazz.getDeclaredMethod(name, parameterTypes);
+
+ // only accept a protected method, a public method should
+ // have been found above and neither private nor package
+ // protected methods are acceptable here
+ if (Modifier.isProtected(method.getModifiers())) {
+ method.setAccessible(true);
+ return method;
+ }
+ }
+ catch (NoSuchMethodException nsme)
+ {
+ // ignore for now
+ }
+ }
+
+ // walked up the complete super class hierarchy and still not found
+ // anything, sigh ...
+ throw new NoSuchMethodException(name);
+ }
+
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/Activator.java b/scr/src/main/java/org/apache/felix/scr/Activator.java
index 9c7114f..0eb1c94 100644
--- a/scr/src/main/java/org/apache/felix/scr/Activator.java
+++ b/scr/src/main/java/org/apache/felix/scr/Activator.java
@@ -18,18 +18,28 @@
*/
package org.apache.felix.scr;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.util.*;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.logging.Logger;
-import org.osgi.framework.*;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.Constants;
+import org.osgi.framework.SynchronousBundleListener;
import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
/**
* This activator is used to cover requirement described in section 112.8.1 @@ -27,14
* 37,202 @@ in active bundles.
*
*/
-public class Activator implements BundleActivator, SynchronousBundleListener, ServiceListener
+public class Activator implements BundleActivator, SynchronousBundleListener
{
// name of the LogService class
private static final String LOGSERVICE_CLASS = LogService.class.getName();
@@ -41,37 +51,20 @@
private static boolean m_error = true;
// A string containing the version number
- private static String m_version = "1.0.0 (12012006)";
+ private static String m_version = "1.0.0 (20070320)";
// this bundle's context
private BundleContext m_context;
// the log service to log messages to
- private static /* TODO: not very good, is it ? */ LogService m_logService;
+ private static ServiceTracker m_logService;
// map of BundleComponentActivator instances per Bundle indexed by Bundle symbolic
// name
private Map m_componentBundles;
- // Static initializations based on system properties
- static {
- // Get system properties to see if traces or errors need to be displayed
- String result = System.getProperty("ds.showtrace");
- if(result != null && result.equals("true"))
- {
- m_trace = true;
- }
- result = System.getProperty("ds.showerrors");
- if(result != null && result.equals("false"))
- {
- m_error = false;
- }
- result = System.getProperty("ds.showversion");
- if(result != null && result.equals("true"))
- {
- System.out.println("[ Version = "+m_version+" ]\n");
- }
- }
+ // registry of managed component
+ private ComponentRegistry m_componentRegistry;
/**
* Registers this instance as a (synchronous) bundle listener and loads the
@@ -84,15 +77,21 @@
{
m_context = context;
m_componentBundles = new HashMap();
+ m_componentRegistry = new ComponentRegistry( m_context );
// require the log service
- ServiceReference logRef = context.getServiceReference(LOGSERVICE_CLASS);
- if (logRef != null) {
- m_logService = (LogService) context.getService(logRef);
- }
- context.addServiceListener(this,
- "(" + Constants.OBJECTCLASS + "=" + LOGSERVICE_CLASS + ")");
+ m_logService = new ServiceTracker(context, LOGSERVICE_CLASS, null);
+ m_logService.open();
+ // configure logging from context properties
+ m_trace = "true".equalsIgnoreCase( context.getProperty( "ds.showtrace" ) );
+ m_error = !"false".equalsIgnoreCase( context.getProperty( "ds.showerrors" ) );
+ if ( "true".equalsIgnoreCase( context.getProperty( "ds.showversion" ) ) )
+ {
+ trace( context.getBundle().getSymbolicName() + "[ Version = "
+ + context.getBundle().getHeaders().get( Constants.BUNDLE_VERSION ) + " ]", null );
+ }
+
// register for bundle updates
context.addBundleListener(this);
@@ -115,6 +114,9 @@
// 112.8.2 dispose off all active components
disposeAllComponents();
+
+ // dispose off the component registry
+ m_componentRegistry.dispose();
}
// ---------- BundleListener Interface -------------------------------------
@@ -139,23 +141,7 @@
}
}
- //---------- ServiceListener ----------------------------------------------
-
- // TODO:
- public void serviceChanged(ServiceEvent event)
- {
- if (event.getType() == ServiceEvent.REGISTERED)
- {
- m_logService = (LogService) m_context.getService(event.getServiceReference());
- }
- else if (event.getType() == ServiceEvent.UNREGISTERING)
- {
- m_logService = null;
- m_context.ungetService(event.getServiceReference());
- }
- }
-
- // ---------- Component Management -----------------------------------------
+ //---------- Component Management -----------------------------------------
// Loads the components of all bundles currently active.
private void loadAllComponents(BundleContext context)
@@ -192,14 +178,13 @@
BundleContext context = getBundleContext(bundle);
if (context == null)
{
- error("Cannot get BundleContext of bundle "
- + bundle.getSymbolicName());
+ error( "Cannot get BundleContext of bundle " + bundle.getSymbolicName(), null );
return;
}
try
{
- BundleComponentActivator ga = new BundleComponentActivator(context);
+ BundleComponentActivator ga = new BundleComponentActivator( m_componentRegistry, context );
m_componentBundles.put(bundle.getSymbolicName(), ga);
}
catch (Exception e)
@@ -267,15 +252,21 @@
*/
private BundleContext getBundleContext(Bundle bundle)
{
- for (Class clazz = bundle.getClass(); clazz != null; clazz = clazz.getSuperclass())
+// try {
+// return bundle.getBundleContext();
+// } catch (Throwable t) {
+// // don't care, might be that the implementation is not yet updated
+// // to OSGi Rev 4.1
+// }
+
+ BundleContext context = null;
+ for (Class clazz = bundle.getClass(); context == null && clazz != null; clazz = clazz.getSuperclass())
{
try
{
- Method m = clazz.getDeclaredMethod("getContext", null);
- if (m.getReturnType().equals(BundleContext.class))
- {
- m.setAccessible(true);
- return (BundleContext) m.invoke(bundle, null);
+ context = getBundleContext( clazz, bundle, "getBundleContext" );
+ if (context == null) {
+ context = getBundleContext( clazz, bundle, "getContext" );
}
}
catch (NoSuchMethodException nsme)
@@ -289,10 +280,23 @@
}
}
- // fall back to nothing
- return null;
+ // return what we found
+ return context;
}
+ private BundleContext getBundleContext( Class clazz, Bundle bundle, String methodName )
+ throws NoSuchMethodException, InvocationTargetException, IllegalAccessException
+ {
+ Method m = clazz.getDeclaredMethod( methodName, null );
+ if ( m.getReturnType().equals( BundleContext.class ) )
+ {
+ m.setAccessible( true );
+ return ( BundleContext ) m.invoke( bundle, null );
+ }
+
+ // method exists but has wrong return type
+ return null;
+ }
/**
* Method to display traces
@@ -310,7 +314,7 @@
}
msg.append(message);
- LogService log = m_logService;
+ LogService log = (LogService) m_logService.getService();
if (log == null)
{
System.out.println(msg);
@@ -326,14 +330,19 @@
* Method to display errors
*
* @param message a string to be displayed
+ * @param metadata optional metadata providing more information to log
**/
- static void error(String message)
+ static void error(String message, ComponentMetadata metadata)
{
if(m_error)
{
- StringBuffer msg = new StringBuffer("### ").append(message);
+ StringBuffer msg = new StringBuffer("### ");
+ if(metadata != null) {
+ msg.append("[").append(metadata.getName()).append("] ");
+ }
+ msg.append(message);
- LogService log = m_logService;
+ LogService log = (LogService) m_logService.getService();
if (log == null)
{
System.err.println(msg);
@@ -361,7 +370,7 @@
msg.append("Exception with component : ");
msg.append(message).append(" ---");
- LogService log = m_logService;
+ LogService log = (LogService) m_logService.getService();
if (log == null)
{
System.err.println(msg);
diff --git a/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java b/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java
index 681f1c5..ac8c9cb 100644
--- a/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/BundleComponentActivator.java
@@ -24,15 +24,21 @@
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
+import javax.naming.ConfigurationException;
+
import org.apache.felix.scr.parser.KXml2SAXParser;
import org.osgi.framework.BundleContext;
+import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentException;
+import org.osgi.util.tracker.ServiceTracker;
/**
* The BundleComponentActivator is helper class to load and unload Components of
@@ -41,27 +47,41 @@
*/
class BundleComponentActivator
{
- // The bundle context
+ // global component registration
+ private ComponentRegistry m_componentRegistry;
+
+ // The bundle context owning the registered component
private BundleContext m_context = null;
// This is a list of component instance managers that belong to a particular bundle
private List m_managers = new ArrayList();
- // Global Registry of component names
- private static Set m_componentNames = new HashSet();
+ // The Configuration Admin tracker providing configuration for components
+ private ServiceTracker m_configurationAdmin;
/**
* Called upon starting of the bundle. This method invokes initialize() which
* parses the metadata and creates the instance managers
*
- * @param context The bundle context passed by the framework
- * @exception Exception any exception thrown from initialize
+ * @param componentRegistry The <code>ComponentRegistry</code> used to
+ * register components with to ensure uniqueness of component names
+ * and to ensure configuration updates.
+ * @param context The bundle context owning the components
+ *
+ * @throws ComponentException if any error occurrs initializing this class
*/
- BundleComponentActivator(BundleContext context) throws ComponentException
+ BundleComponentActivator(ComponentRegistry componentRegistry, BundleContext context) throws ComponentException
{
+ // The global "Component" registry
+ this.m_componentRegistry = componentRegistry;
+
// Stores the context
m_context = context;
+ // have the Configuration Admin Service handy (if available)
+ m_configurationAdmin = new ServiceTracker(context, ConfigurationAdmin.class.getName(), null);
+ m_configurationAdmin.open();
+
// Get the Metadata-Location value from the manifest
String descriptorLocations =
(String) m_context.getBundle().getHeaders().get("Service-Component");
@@ -95,12 +115,13 @@
{
// 112.4.1 If an XML document specified by the header cannot be located in the bundle and its attached
// fragments, SCR must log an error message with the Log Service, if present, and continue.
- Activator.error("Component descriptor entry '" + descriptorLocation + "' not found");
+ Activator.error( "Component descriptor entry '" + descriptorLocation + "' not found", null );
continue;
}
+ InputStream stream = null;
try {
- InputStream stream = descriptorURL.openStream();
+ stream = descriptorURL.openStream();
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
XmlHandler handler = new XmlHandler();
@@ -121,16 +142,23 @@
validate(metadata);
// Request creation of the component manager
- ComponentManager manager = ManagerFactory.createManager(this,metadata);
+ ComponentManager manager;
+
+ if (metadata.isFactory()) {
+ // 112.2.4 SCR must register a Component Factory service on behalf ot the component
+ // as soon as the component factory is satisfied
+ manager = new ComponentFactoryImpl(this, metadata, m_componentRegistry);
+ } else {
+ manager = ManagerFactory.createManager( this, metadata, m_componentRegistry
+ .createComponentId() );
+ }
- if(metadata.isFactory())
+ // register the component after validation
+ m_componentRegistry.registerComponent( metadata.getName(), manager );
+
+ // enable the component
+ if(metadata.isEnabled())
{
- // 112.2.4 SCR must register a Component Factory service on behalf ot the component
- // as soon as the component factory is satisfied
- }
- else if(metadata.isEnabled())
- {
- // enable the component
manager.enable();
}
@@ -144,9 +172,6 @@
Activator.exception("Cannot register Component", metadata, e);
}
}
-
- stream.close();
-
}
catch ( IOException ex )
{
@@ -161,6 +186,19 @@
Activator.exception("General problem with descriptor entry '"
+ descriptorLocation + "'", null, ex);
}
+ finally
+ {
+ if ( stream != null )
+ {
+ try
+ {
+ stream.close();
+ }
+ catch ( IOException ignore )
+ {
+ }
+ }
+ }
}
}
@@ -193,11 +231,16 @@
}
finally
{
- m_componentNames.remove(manager.getComponentMetadata().getName());
+ m_componentRegistry.unregisterComponent( manager.getComponentMetadata().getName() );
}
}
+ // close the Configuration Admin tracker
+ if (m_configurationAdmin != null) {
+ m_configurationAdmin.close();
+ }
+
Activator.trace("BundleComponentActivator : Bundle ["
+ m_context.getBundle().getBundleId() + "] STOPPED", null);
@@ -225,6 +268,16 @@
}
/**
+ * Returns the <code>ConfigurationAdmin</code> service used to retrieve
+ * configuration data for components managed by this activator or
+ * <code>null</code> if no Configuration Admin Service is available in the
+ * framework.
+ */
+ protected ConfigurationAdmin getConfigurationAdmin() {
+ return (ConfigurationAdmin) m_configurationAdmin.getService();
+ }
+
+ /**
* Implements the <code>ComponentContext.enableComponent(String)</code>
* method by first finding the component(s) for the <code>name</code> and
* then starting a thread to actually enable all components found.
@@ -255,8 +308,7 @@
}
catch (Throwable t)
{
- Activator.exception("Cannot enable component",
- cm[i].getComponentMetadata(), t);
+ Activator.exception( "Cannot enable component", cm[i].getComponentMetadata(), t );
}
}
}
@@ -291,7 +343,7 @@
{
try
{
- cm[i].dispose();
+ cm[i].disable();
}
catch (Throwable t)
{
@@ -326,7 +378,7 @@
return (ComponentManager[]) m_managers.toArray(new ComponentManager[m_managers.size()]);
}
- if (m_componentNames.contains(name))
+ if ( m_componentRegistry.getComponent( name ) != null )
{
// otherwise just find it
Iterator it = m_managers.iterator();
@@ -358,16 +410,19 @@
void validate(ComponentMetadata component) throws ComponentException
{
- if(m_componentNames.contains(component.getName()))
- {
- throw new ComponentException("The component name '"+component.getName()+"' has already been registered.");
- }
+ m_componentRegistry.checkComponentName( component.getName() );
- component.validate();
+ try
+ {
+ component.validate();
+ }
+ catch ( ComponentException ce )
+ {
+ // remove the reservation before leaving
+ m_componentRegistry.unregisterComponent( component.getName() );
+ throw ce;
+ }
- // register the component after validation
- m_componentNames.add(component.getName());
-
- Activator.trace("Validated and registered component",component);
+ Activator.trace( "Validated and registered component", component );
}
}
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentContextImpl.java b/scr/src/main/java/org/apache/felix/scr/ComponentContextImpl.java
new file mode 100644
index 0000000..e2a022c
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/ComponentContextImpl.java
@@ -0,0 +1,157 @@
+/*
+ * 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 org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.ComponentInstance;
+
+
+/**
+ * Implementation for the ComponentContext interface
+ *
+ */
+class ComponentContextImpl implements ComponentContext
+{
+
+ private AbstractComponentManager m_componentManager;
+
+
+ ComponentContextImpl( AbstractComponentManager componentManager )
+ {
+ m_componentManager = componentManager;
+ }
+
+
+ protected AbstractComponentManager getComponentManager()
+ {
+ return m_componentManager;
+ }
+
+ public Dictionary getProperties()
+ {
+ // 112.11.3.5 The Dictionary is read-only and cannot be modified
+ return new ReadOnlyDictionary( m_componentManager.getProperties() );
+ }
+
+
+ public Object locateService( String name )
+ {
+ DependencyManager dm = m_componentManager.getDependencyManager( name );
+ if ( dm == null )
+ {
+ return null;
+ }
+
+ ServiceReference selectedRef;
+ if ( dm.size() == 1 )
+ {
+ // short cut for single bound service
+ selectedRef = dm.getServiceReference();
+ }
+ else
+ {
+ // is it correct to assume an ordered bound services set ?
+ int maxRanking = Integer.MIN_VALUE;
+ long minId = Long.MAX_VALUE;
+ selectedRef = null;
+
+ ServiceReference[] refs = dm.getServiceReferences();
+ for ( int i = 0; refs != null && i < refs.length; i++ )
+ {
+ ServiceReference ref = refs[i];
+ Integer rank = ( Integer ) ref.getProperty( Constants.SERVICE_RANKING );
+ int ranking = ( rank == null ) ? Integer.MIN_VALUE : rank.intValue();
+ long id = ( ( Long ) ref.getProperty( Constants.SERVICE_ID ) ).longValue();
+ if ( maxRanking < ranking || ( maxRanking == ranking && id < minId ) )
+ {
+ maxRanking = ranking;
+ minId = id;
+ selectedRef = ref;
+ }
+ }
+ }
+
+ // this is not realistic, as at least one service is available
+ // whose service id is smaller than Long.MAX_VALUE, still be sure
+ if ( selectedRef == null )
+ {
+ return null;
+ }
+
+ // return the service for the selected reference
+ return dm.getService( selectedRef );
+ }
+
+
+ public Object locateService( String name, ServiceReference ref )
+ {
+ DependencyManager dm = m_componentManager.getDependencyManager( name );
+ return ( dm != null ) ? dm.getService( ref ) : null;
+ }
+
+
+ public Object[] locateServices( String name )
+ {
+ DependencyManager dm = m_componentManager.getDependencyManager( name );
+ return ( dm != null ) ? dm.getServices() : null;
+ }
+
+
+ public BundleContext getBundleContext()
+ {
+ return m_componentManager.getActivator().getBundleContext();
+ }
+
+
+ public Bundle getUsingBundle()
+ {
+ return null;
+ }
+
+
+ public ComponentInstance getComponentInstance()
+ {
+ return m_componentManager;
+ }
+
+
+ public void enableComponent( String name )
+ {
+ m_componentManager.getActivator().enableComponent( name );
+ }
+
+
+ public void disableComponent( String name )
+ {
+ m_componentManager.getActivator().disableComponent( name );
+ }
+
+
+ public ServiceReference getServiceReference()
+ {
+ return m_componentManager.getServiceReference();
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/ComponentFactoryImpl.java
new file mode 100644
index 0000000..8631883
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/ComponentFactoryImpl.java
@@ -0,0 +1,248 @@
+/*
+ * 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.HashMap;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.component.ComponentConstants;
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
+
+
+/**
+ * The <code>ComponentFactoryImpl</code> TODO
+ *
+ * @author fmeschbe
+ */
+public class ComponentFactoryImpl extends AbstractComponentManager implements ComponentFactory, ManagedServiceFactory
+{
+
+ // The component registry used to retrieve component IDs
+ private ComponentRegistry m_componentRegistry;
+
+ // The map of components created from Configuration objects
+ // maps PID to ComponentManager for configuration updating
+ // this map is lazily created
+ private Map m_configuredServices;
+
+ // Actually we only use the identity key stuff, but there is
+ // no IdentityHashSet and HashSet internally uses a HashMap anyway
+ private Map m_createdComponents;
+
+ ComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata,
+ ComponentRegistry componentRegistry )
+ {
+ super( activator, metadata );
+ m_componentRegistry = componentRegistry;
+ m_createdComponents = new IdentityHashMap();
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.osgi.service.component.ComponentFactory#newInstance(java.util.Dictionary)
+ */
+ public ComponentInstance newInstance( Dictionary dictionary )
+ {
+ return ( ComponentInstance ) createComponentManager( dictionary );
+ }
+
+
+ protected void createComponent()
+ {
+ // not component to create, newInstance must be used instead
+ }
+
+ public void reconfigure()
+ {
+ super.reconfigure();
+ }
+
+ protected void deleteComponent()
+ {
+ // nothing to delete
+ }
+
+
+ protected ServiceRegistration registerComponentService()
+ {
+ Activator.trace( "registering component factory", getComponentMetadata() );
+
+ Dictionary serviceProperties = getProperties();
+ return getActivator().getBundleContext().registerService( new String[]
+ { ComponentFactory.class.getName(), ManagedServiceFactory.class.getName() }, getService(),
+ serviceProperties );
+ }
+
+
+ public Object getInstance()
+ {
+ // this does not return the component instance actually
+ return null;
+ }
+
+
+ protected Dictionary getProperties()
+ {
+ Dictionary props = new Hashtable();
+
+ // 112.5.5 The Component Factory service must register with the following properties
+ props.put( ComponentConstants.COMPONENT_NAME, getComponentMetadata().getName() );
+ props.put( ComponentConstants.COMPONENT_FACTORY, getComponentMetadata().getFactoryIdentifier() );
+
+ // also register with the factory PID
+ props.put( Constants.SERVICE_PID, getComponentMetadata().getName() );
+
+ return props;
+ }
+
+
+ protected Object getService()
+ {
+ return this;
+ }
+
+
+ //---------- ManagedServiceFactory interface ------------------------------
+
+ public void updated( String pid, Dictionary configuration )
+ {
+ ComponentManager cm;
+ if ( m_configuredServices != null )
+ {
+ cm = ( ComponentManager ) m_configuredServices.get( pid );
+ }
+ else
+ {
+ m_configuredServices = new HashMap();
+ cm = null;
+ }
+
+ if ( cm == null )
+ {
+ // create a new instance with the current configuration
+ cm = createComponentManager( configuration );
+
+ // keep a reference for future updates
+ m_configuredServices.put( pid, cm );
+ }
+ else
+ {
+ if ( cm instanceof ImmediateComponentManager )
+ {
+ // inject current configuration before cycling
+ ( ( ImmediateComponentManager ) cm ).setFactoryProperties( configuration );
+ }
+
+ // reconfigure the component
+ cm.reconfigure();
+ }
+ }
+
+
+ public void deleted( String pid )
+ {
+ if ( m_configuredServices != null )
+ {
+ ComponentManager cm = ( ComponentManager ) m_configuredServices.remove( pid );
+ if ( cm != null )
+ {
+ disposeComponentManager( cm );
+ }
+ }
+
+ }
+
+
+ public String getName()
+ {
+ return "Component Factory " + getComponentMetadata().getName();
+ }
+
+
+ //---------- internal -----------------------------------------------------
+
+ /**
+ * ComponentManager instances created by this method are not registered
+ * with the ComponentRegistry. Therefore, any configuration update to these
+ * components must be effected by this class !
+ */
+ private ComponentManager createComponentManager( Dictionary configuration )
+ {
+ long componentId = m_componentRegistry.createComponentId();
+ ComponentManager cm = ManagerFactory.createManager( getActivator(), getComponentMetadata(), componentId );
+
+ // add the new component to the activators instances
+ getActivator().getInstanceReferences().add( cm );
+
+ // register with the internal set of created components
+ m_createdComponents.put(cm, cm);
+
+ // inject configuration if possible
+ if ( cm instanceof ImmediateComponentManager )
+ {
+ ( ( ImmediateComponentManager ) cm ).setFactoryProperties( configuration );
+ }
+
+ // immediately enable this ComponentManager
+ cm.enable();
+
+ return cm;
+ }
+
+ private void disposeComponentManager(ComponentManager cm) {
+ // remove from created components
+ m_createdComponents.remove( cm );
+
+ // remove from activators list
+ getActivator().getInstanceReferences().remove( cm );
+
+ // finally dispose it
+ cm.dispose();
+ }
+
+ private class ComponentInstanceWrapper implements ComponentInstance {
+
+ private ComponentManager m_component;
+
+ ComponentInstanceWrapper(ComponentManager component) {
+ m_component = component;
+ }
+
+ public Object getInstance()
+ {
+ return ((ComponentInstance) m_component).getInstance();
+ }
+
+ public void dispose()
+ {
+ disposeComponentManager( m_component );
+ }
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentManager.java b/scr/src/main/java/org/apache/felix/scr/ComponentManager.java
index 5f99652..c3fea75 100644
--- a/scr/src/main/java/org/apache/felix/scr/ComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/ComponentManager.java
@@ -18,6 +18,8 @@
*/
package org.apache.felix.scr;
+import java.util.Dictionary;
+
/**
* This interface is provided so that there can be multiple implementations of
* managers that are responsible for managing component's lifecycle.
@@ -32,9 +34,21 @@
*/
public boolean enable();
+ /**
+ * Reconfigure the component with configuration data newly retrieved from
+ * the Configuration Admin Service.
+ */
+ public void reconfigure();
+
+ /**
+ * Disable the component. After disabling the component may be re-enabled
+ * by calling the {@link #enable()} method.
+ */
+ public void disable();
+
/**
- * Dispose the component
- *
+ * Dispose the component. After disposing the component manager it must not
+ * be used anymore.
*/
public void dispose();
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java b/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java
deleted file mode 100644
index d5af234..0000000
--- a/scr/src/main/java/org/apache/felix/scr/ComponentManagerImpl.java
+++ /dev/null
@@ -1,1305 +0,0 @@
-/*
- * 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.*;
-import java.util.*;
-
-import org.osgi.framework.*;
-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 ComponentManagerImpl implements ComponentManager, ComponentInstance
-{
- // States of the instance manager
- static final int INSTANCE_CREATING = 0;
- static final int INSTANCE_CREATED = 1;
- static final int INSTANCE_VALIDATING = 2;
- static final int INSTANCE_VALID = 3;
- static final int INSTANCE_INVALIDATING = 4;
- static final int INSTANCE_INVALID = 5;
- static final int INSTANCE_DESTROYING = 6;
- static final int INSTANCE_DESTROYED = 7;
-
-
- static final String m_states[]={"CREATING","CREATED",
- "VALIDATING","VALID",
- "INVALIDATING","INVALID",
- "DESTROYING","DESTROYED"
- };
-
- // The state of this instance manager
- private int m_state = INSTANCE_CREATING;
-
- // The metadata
- private ComponentMetadata m_componentMetadata;
-
- // The object that implements the service and that is bound to other services
- private Object m_implementationObject = null;
-
- // The dependency managers that manage every dependency
- private List m_dependencyManagers = new ArrayList();
-
- // The ServiceRegistration
- private ServiceRegistration m_serviceRegistration = null;
-
- // A reference to the BundleComponentActivator
- private BundleComponentActivator m_activator = null;
-
- // The context that will be passed to the implementationObject
- private ComponentContext m_componentContext = null;
-
- // In case of a delayed component, this holds a reference to the factory
- private ServiceFactory m_delayedComponentServiceFactory;
-
- /**
- * The constructor receives both the activator and the metadata
- *
- * @param activator
- * @param metadata
- */
- ComponentManagerImpl(BundleComponentActivator activator, ComponentMetadata metadata)
- {
- // Store the activator reference
- m_activator = activator;
-
- // Store the metadata reference
- m_componentMetadata = metadata;
- }
-
- /**
- * Enable this component
- *
- * @return true if enabling was successful
- */
- public boolean enable() {
-
- Activator.trace("Enabling component", m_componentMetadata);
-
- try
- {
- // If this component has got dependencies, create dependency managers for each one of them.
- if (m_componentMetadata.getDependencies().size() != 0)
- {
- Iterator dependencyit = m_componentMetadata.getDependencies().iterator();
-
- while(dependencyit.hasNext())
- {
- ReferenceMetadata currentdependency = (ReferenceMetadata)dependencyit.next();
-
- DependencyManager depmanager = new DependencyManager(currentdependency);
-
- m_dependencyManagers.add(depmanager);
-
- // Register the dependency managers as listeners to service events so that they begin
- // to manage the dependency autonomously
- m_activator.getBundleContext().addServiceListener(depmanager,depmanager.m_dependencyMetadata.getTarget());
- }
- }
-
- // TODO: create the context
- //m_sbcontext = new ServiceBinderContextImpl(this);
-
- // Add this instance manager to the Generic activator list
- //m_activator.addInstanceManager(this);
-
-
- setState(INSTANCE_CREATED);
-
- activate();
-
- return true;
- }
- catch(Exception ex)
- {
- // TODO: Log this error
- return false;
- }
- }
-
- /**
- * Activate this Instance manager.
- *
- * 112.5.6 Activating a component configuration consists of the following steps
- * 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
- * [5. Register provided services]
- */
- synchronized private void activate()
- {
- // CONCURRENCY NOTE: This method is called either by the enable() method or by the dependency
- // managers.
- if (m_state != INSTANCE_INVALID && m_state !=INSTANCE_CREATED) {
- // This state can only be entered from the CREATED or INVALID states
- return;
- }
-
- setState(INSTANCE_VALIDATING);
-
- // Before creating the implementation object, we are going to
- // test if all the mandatory dependencies are satisfied
- Iterator it = m_dependencyManagers.iterator();
-
- while (it.hasNext())
- {
- // It is not possible to call the isValid method yet in the DependencyManagers
- // since they have not been initialized yet, but they can't be initialized yet
- // because the implementationObject has not been created yet.
- // This test is necessary, because we don't want to instantiate
- // the implementationObject if the dependency managers aren't valid.
- DependencyManager dm = (DependencyManager)it.next();
- if (dm.getRequiredServiceRefs() == null && dm.m_dependencyMetadata.isOptional() == false)
- {
- setState(INSTANCE_INVALID);
- return;
- }
- }
-
- // 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
- if( m_componentMetadata.isImmediate() == true )
- {
- //Activator.trace("Loading implementation class and creating instance for component '"+m_componentMetadata.getName()+"'");
- try
- {
- // 112.4.4 The class is retrieved with the loadClass method of the component's bundle
- Class c = m_activator.getBundleContext().getBundle().loadClass(m_componentMetadata.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
- m_componentContext = new ComponentContextImpl(null);
- m_implementationObject = c.newInstance();
- }
- catch (Exception ex)
- {
- // TODO: manage this exception when implementation object cannot be created
- Activator.exception("Error during instantiation", m_componentMetadata, ex);
- deactivate();
- //invalidate();
- return;
- }
- }
- else if ( m_componentMetadata.getServiceMetadata() != null
- && m_componentMetadata.getServiceMetadata().isServiceFactory() )
- {
- // delayed component is a ServiceFactory service
- m_delayedComponentServiceFactory = new DelayedServiceFactoryServiceFactory();
- }
- else
- {
- // delayed component is a standard service
- m_delayedComponentServiceFactory = new DelayedComponentServiceFactory();
- }
-
- // 3. Bind the target services
- it = m_dependencyManagers.iterator();
-
- //Activator.trace("Binding target services for component '"+m_componentMetadata.getName()+"'");
-
- while (it.hasNext())
- {
- DependencyManager dm = (DependencyManager)it.next();
-
- // if any of the dependency managers is unable to bind (it is invalid), the component is deactivated
- if (dm.bind() == false)
- {
- deactivate();
- return;
- }
- }
-
- //Activator.trace("Calling activate for component '"+m_componentMetadata.getName()+"'");
-
- // 4. Call the activate method, if present
- // We need to check if we are still validating because it is possible that when we
- // registered the service above our thread causes an instance to become valid which
- // then registered a service that then generated an event that we needed that
- // caused validate() to be called again, thus if we are not still VALIDATING, it
- // means we are already VALID.
- if ( m_componentMetadata.isImmediate() == true && m_state == INSTANCE_VALIDATING)
- {
- // Search for the activate method
- try {
- Method activateMethod = getMethod(m_implementationObject.getClass(), "activate", new Class[]{ComponentContext.class});
- activateMethod.invoke(m_implementationObject, new Object[]{m_componentContext});
- }
- catch(NoSuchMethodException ex) {
- // We can safely ignore this one
- Activator.trace("activate() method not implemented", m_componentMetadata);
- }
- catch(IllegalAccessException ex) {
- // TODO: Log this exception?
- Activator.trace("activate() method cannot be called", m_componentMetadata);
- }
- catch(InvocationTargetException ex) {
- // TODO: 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", m_componentMetadata, ex.getTargetException());
- }
- }
-
- // Validation occurs before the services are provided, otherwhise the service provider's service may be called
- // by a service requester while it is still VALIDATING
- setState(INSTANCE_VALID);
-
- // 5. Register provided services
- if(m_componentMetadata.getServiceMetadata() != null)
- {
- Activator.trace("registering services", m_componentMetadata);
-
- if( m_componentMetadata.isImmediate() == true ) {
- // In the case the component is immediate, the implementation object is registered
- m_serviceRegistration = m_activator.getBundleContext().registerService(m_componentMetadata.getServiceMetadata().getProvides(), m_implementationObject, m_componentMetadata.getProperties());
- }else {
- // In the case the component is delayed, a factory is registered
- m_serviceRegistration = m_activator.getBundleContext().registerService(m_componentMetadata.getServiceMetadata().getProvides(), m_delayedComponentServiceFactory, m_componentMetadata.getProperties());
- }
- }
- }
-
- /**
- * This method deactivates the manager, performing the following steps
- *
- * [0. Remove published services from the registry]
- * 1. Call the deactivate() method, if present
- * 2. Unbind any bound services
- * 3. Release references to the component instance and component context
- **/
- synchronized private void deactivate()
- {
- // CONCURRENCY NOTE: This method may be called either from application code or by the dependency managers
- if (m_state != INSTANCE_VALID && m_state != INSTANCE_VALIDATING && m_state != INSTANCE_DESTROYING) {
- return;
- }
-
- // In case the instance is valid when this is called, the manager is set to an invalidating state
- if (m_state != INSTANCE_DESTROYING)
- {
- setState(INSTANCE_INVALIDATING);
- }
-
- // 0.- Remove published services from the registry
- if(m_serviceRegistration != null)
- {
- m_serviceRegistration.unregister();
- m_serviceRegistration = null;
-
- Activator.trace("unregistering the services", m_componentMetadata);
- }
-
- // 1.- Call the deactivate method, if present
- // Search the deactivate method
- try {
- // It is necessary to check that the implementation Object is not null. This may happen if the component
- // is delayed and its service was never requested.
- if(m_implementationObject != null)
- {
- Method activateMethod = getMethod(m_implementationObject.getClass(), "deactivate", new Class[]{ComponentContext.class});
- activateMethod.invoke(m_implementationObject, new Object[]{m_componentContext});
- }
- }
- catch(NoSuchMethodException ex) {
- // We can safely ignore this one
- Activator.trace("deactivate() method is not implemented", m_componentMetadata);
- }
- catch(IllegalAccessException ex) {
- // Ignored, but should it be logged?
- Activator.trace("deactivate() method cannot be called", m_componentMetadata);
- }
- catch(InvocationTargetException ex) {
- // TODO: 112.5.12 If the deactivate method throws an exception, SCR must log an error message
- // containing the exception with the Log Service
- Activator.exception("The deactivate method has thrown and exception", m_componentMetadata, ex);
- }
-
- // 2. Unbind any bound services
- Iterator it = m_dependencyManagers.iterator();
-
- while (it.hasNext())
- {
- DependencyManager dm = (DependencyManager)it.next();
- dm.unbind();
- }
-
- // 3. Release references to the component instance and component context
- m_implementationObject = null;
- m_componentContext = null;
- m_delayedComponentServiceFactory = null;
-
- //Activator.trace("InstanceManager from bundle ["+ m_activator.getBundleContext().getBundle().getBundleId() + "] was invalidated.");
-
- if (m_state != INSTANCE_DESTROYING)
- {
- setState(INSTANCE_INVALID);
- }
- }
-
- /**
- *
- */
- public synchronized void dispose()
- {
- // CONCURRENCY NOTE: This method is only called from the BundleComponentActivator or by application logic
- // but not by the dependency managers
-
- // Theoretically this should never be in any state other than VALID or INVALID,
- // because validate is called right after creation.
- if (m_state != INSTANCE_VALID && m_state != INSTANCE_INVALID)
- {
- return;
- }
-
- boolean deactivationRequired = (m_state == INSTANCE_VALID);
-
- setState(INSTANCE_DESTROYING);
-
- // Stop the dependency managers to listen to events...
- Iterator it = m_dependencyManagers.iterator();
-
- while (it.hasNext())
- {
- DependencyManager dm = (DependencyManager)it.next();
- m_activator.getBundleContext().removeServiceListener(dm);
- }
-
- // in case the component is disposed when it was VALID, it is necessary to deactivate it first.
- if (deactivationRequired)
- {
- deactivate();
- }
-
- m_dependencyManagers.clear();
-
- setState(INSTANCE_DESTROYED);
-
- m_activator = null;
- }
-
- //**********************************************************************************************************
-
- /**
- * Get the object that is implementing this descriptor
- *
- * @return the object that implements the services
- */
- public Object getInstance() {
- return m_implementationObject;
- }
-
- /**
- *
- */
- public ComponentMetadata getComponentMetadata() {
- return m_componentMetadata;
- }
-
- /**
- * sets the state of the manager
- **/
- private synchronized void setState(int newState) {
- Activator.trace("State transition : "+m_states[m_state]+" -> "+m_states[newState], m_componentMetadata);
-
- m_state = newState;
-
-
-
- if(m_state == INSTANCE_CREATED || m_state == INSTANCE_VALID || m_state == INSTANCE_INVALID || m_state == INSTANCE_DESTROYED)
- {
- //m_activator.fireInstanceChangeEvent(new InstanceChangeEvent(this,m_instanceMetadata,m_state));
- }
- }
-
-/**
- * The DependencyManager task is to listen to service events and to call the * bind/unbind methods on a given object. It is also responsible for requesting * the unregistration of a service in case a dependency is broken.
- */
- class DependencyManager implements ServiceListener
- {
- // Reference to the metadata
- private ReferenceMetadata m_dependencyMetadata;
-
- // The bound services <ServiceReference>
- private Set m_boundServicesRefs = new HashSet();
-
- // A flag that denotes if the dependency is satisfied at any given moment
- private boolean m_isValid;
-
- // A flag that defines if the bind method receives a ServiceReference
- private boolean m_bindUsesServiceReference = false;
-
- /**
- * Constructor that receives several parameters.
- *
- * @param dependency An object that contains data about the dependency
- **/
- private DependencyManager(ReferenceMetadata dependency) throws ClassNotFoundException, NoSuchMethodException
- {
- m_dependencyMetadata = dependency;
- m_isValid = false;
-
- //m_bindMethod = getTargetMethod(m_dependencyMetadata.getBind(), m_componentMetadata.getImplementationClassName(),m_dependencyMetadata.getInterface());
- //m_unbindMethod = getTargetMethod(m_dependencyMetadata.getUnbind(), m_componentMetadata.getImplementationClassName(),m_dependencyMetadata.getInterface());
- }
-
- /**
- * initializes a dependency. This method binds all of the service occurrences to the instance object
- *
- * @return true if the operation was successful, false otherwise
- **/
- private boolean bind()
- {
- /*
- if(getInstance() == null)
- {
- return false;
- }*/
-
- // Get service references
- ServiceReference refs[] = getRequiredServiceRefs();
-
- // If no references were received, we have to check if the dependency
- // is optional, if it is not then the dependency is invalid
- if (refs == null && m_dependencyMetadata.isOptional() == false)
- {
- m_isValid = false;
- return m_isValid;
- }
-
- m_isValid = true;
-
- // 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(m_implementationObject, 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_isValid = false;
- //setStateDependency(DependencyChangeEvent.DEPENDENCY_INVALID);
- return m_isValid;
- }
- }
- }
-
- return m_isValid;
- }
-
- /**
- * Revoke all bindings. This method cannot throw an exception since it must try
- * to complete all that it can
- *
- **/
- private void unbind()
- {
- Object []allrefs = m_boundServicesRefs.toArray();
-
- if (allrefs == null)
- return;
-
- for (int i = 0; i < allrefs.length; i++)
- {
- invokeUnbindMethod(m_implementationObject, (ServiceReference)allrefs[i]);
- }
- }
-
- /**
- *
- * Returns an array containing the service references that are pertinent to the
- * dependency managed by this object. This method filters out services that
- * belong to bundles that are being (or are actually) shutdown. This is an issue
- * since is not clearly specified in the OSGi specification if a getServiceReference
- * call should return the services that belong to bundles that are stopping.
- *
- * @return an array of ServiceReferences valid in the context of this dependency
- **/
- private ServiceReference [] getRequiredServiceRefs()
- {
- try
- {
- ArrayList list=new ArrayList();
-
- ServiceReference temprefs[] = m_activator.getBundleContext().getServiceReferences(m_dependencyMetadata.getInterface(), m_dependencyMetadata.getTarget());
-
- if (temprefs == null)
- {
- return null;
- }
-
- for (int i = 0; i < temprefs.length; i++)
- {
- if (temprefs[i].getBundle().getState() == Bundle.ACTIVE
- || temprefs[i].getBundle().getState() == Bundle.STARTING)
- {
- list.add(temprefs[i]);
- }
- }
-
- return (ServiceReference []) list.toArray(new ServiceReference [temprefs.length]);
-
- }
- catch (Exception e)
- {
- Activator.error("DependencyManager: exception while getting references :"+e);
- return null;
- }
- }
-
- /**
- * 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 = getMethod(targetClass, methodname, new Class[]{ServiceReference.class});
-
- m_bindUsesServiceReference = true;
- }
- catch(NoSuchMethodException ex){
-
- try {
- // Case2
-
- m_bindUsesServiceReference = false;
-
- parameterClass = m_activator.getBundleContext().getBundle().loadClass(parameterClassName);
-
- method = 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_componentMetadata,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) {
- // 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
- 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
- // TODO: log error message
- Activator.trace("bind() method not found", m_componentMetadata);
- return false;
- }
-
- // Get the parameter
- Object parameter;
-
- if(m_bindUsesServiceReference == false) {
- parameter = m_activator.getBundleContext().getService(ref);
- }
- else {
- parameter = ref;
- }
-
- // Invoke the method
- bindMethod.invoke(implementationObject, new Object[] {parameter});
-
- // Store the reference
- m_boundServicesRefs.add(ref);
-
- 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
- // TODO: log error message
- return false;
- }
- catch(InvocationTargetException ex)
- {
- Activator.exception("DependencyManager : exception while invoking "+m_dependencyMetadata.getBind()+"()", m_componentMetadata, ex);
- return false;
- }
- } else if( implementationObject == null && m_componentMetadata.isImmediate() == false) {
- // In the case the implementation object is null and the component is delayed
- // then we still have to store the object that is passed to the bind methods
- // so that it can be used once the implementation object is created.
- m_boundServicesRefs.add(ref);
- return true;
- } else {
- // TODO: assert false : this theoretically never happens...
- 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) {
- // TODO: assert m_boundServices.contains(ref) == true : "DependencyManager : callUnbindMethod UNBINDING UNKNOWN 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
- {
- // TODO: me quede aqui por que el unbind method no funciona
- Activator.trace("getting unbind: "+m_dependencyMetadata.getUnbind(), m_componentMetadata);
- 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 = m_activator.getBundleContext().getService(ref);
- }
-
- 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
- // TODO: log error message
- Activator.trace("unbind() method not found", m_componentMetadata);
- return false;
- }
-
- unbindMethod.invoke(implementationObject, new Object [] {parameter});
-
- m_boundServicesRefs.remove(ref);
-
- m_activator.getBundleContext().ungetService(ref);
-
- 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
- // TODO: log error message
- return false;
- }
- catch (InvocationTargetException ex) {
- Activator.exception("DependencyManager : exception while invoking "+m_dependencyMetadata.getUnbind()+"()", m_componentMetadata, ex);
- return false;
- }
-
- } else if( implementationObject == null && m_componentMetadata.isImmediate() == false) {
- // In the case the implementation object is null and the component is delayed
- // then we still have to store the object that is passed to the bind methods
- // so that it can be used once the implementation object is created.
- m_boundServicesRefs.remove(ref);
- return true;
- } else {
- // TODO: assert false : this theoretically never happens...
- return false;
- }
- }
-
- /**
- * Called upon a service event. This method is responsible for calling the
- * binding and unbinding methods and also to request the eventual unregistering
- * of a service when a dependency breaks
- *
- * @param evt The ServiceEvent
- **/
- public void serviceChanged(ServiceEvent evt)
- {
- synchronized (ComponentManagerImpl.this)
- {
- // If the object is being created or destroyed, we can safely ignore events.
- if (m_state == INSTANCE_DESTROYING || m_state == INSTANCE_DESTROYED || m_state == INSTANCE_CREATING || m_state == INSTANCE_CREATED)
- {
- return;
- }
-
- // If we are in the process of invalidating, it is not necessary to pass
- // unregistration events, since we are unbinding everything anyway.
- else if (m_state == INSTANCE_INVALIDATING && evt.getType() == ServiceEvent.UNREGISTERING)
- {
- return;
- }
-
- // We do not have an entry for VALIDATING because it is reentrant.
-
- // A service is unregistering
- if (evt.getType() == ServiceEvent.UNREGISTERING)
- {
- if (m_boundServicesRefs.contains(evt.getServiceReference()) == true)
- {
- // A static dependency is broken the instance manager will be invalidated
- if (m_dependencyMetadata.isStatic())
- {
- m_isValid = false;
- //setStateDependency(DependencyChangeEvent.DEPENDENCY_INVALID);
- try
- {
- Activator.trace("Dependency Manager: Static dependency is broken", m_componentMetadata);
- deactivate();
- Activator.trace("Dependency Manager: RECREATING", m_componentMetadata);
- activate();
- }
- catch(Exception ex)
- {
- Activator.exception("Exception while recreating dependency ",m_componentMetadata, ex);
- }
- }
- // dynamic dependency
- else
- {
- // Release references to the service, call unbinder method
- // and eventually request service unregistration
-
- invokeUnbindMethod(m_implementationObject, evt.getServiceReference());
-
- // 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 (m_boundServicesRefs.size() == 0)
- {
- // try to reinitialize
- if (!bind())
- {
- if (!m_dependencyMetadata.isOptional())
- {
- Activator.trace("Dependency Manager: Mandatory dependency not fullfilled and no replacements available... unregistering service...", m_componentMetadata);
- deactivate();
- Activator.trace("Dependency Manager: Recreating", m_componentMetadata);
- activate();
- }
- }
- }
- }
- }
- }
- // A service is registering.
- else if (evt.getType() == ServiceEvent.REGISTERED)
- {
- if (m_boundServicesRefs.contains(evt.getServiceReference()) == true)
- {
- // This is a duplicate
- Activator.trace("DependencyManager : ignoring REGISTERED ServiceEvent (already bound)", m_componentMetadata);
- }
- else
- {
- m_isValid = true;
- //setStateDependency(DependencyChangeEvent.DEPENDENCY_VALID);
-
- // If the InstanceManager is invalid, a call to validate is made
- // which will fix everything.
- if (ComponentManagerImpl.this.m_state != INSTANCE_VALID)
- {
- 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
- if (m_dependencyMetadata.isMultiple() || m_boundServicesRefs.size() == 0)
- {
- invokeBindMethod(m_implementationObject, evt.getServiceReference());
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * Implementation for the ComponentContext interface
- *
- */
- class ComponentContextImpl implements ComponentContext {
-
- private Bundle m_usingBundle;
-
- ComponentContextImpl(Bundle usingBundle)
- {
- m_usingBundle = usingBundle;
- }
-
- public Dictionary getProperties() {
- //TODO: 112.11.3.5 The Dictionary is read-only and cannot be modified
- return m_componentMetadata.getProperties();
- }
-
- public Object locateService(String name) {
- DependencyManager dm = getDependencyManager(name);
- if (dm == null || dm.m_boundServicesRefs.isEmpty())
- {
- return null;
- }
-
- ServiceReference selectedRef;
- if (dm.m_boundServicesRefs.size() == 1)
- {
- // short cut for single bound service
- selectedRef = (ServiceReference) dm.m_boundServicesRefs.iterator().next();
- }
- else
- {
- // is it correct to assume an ordered bound services set ?
- int maxRanking = Integer.MIN_VALUE;
- long minId = Long.MAX_VALUE;
- selectedRef = null;
-
- Iterator it = dm.m_boundServicesRefs.iterator();
- while (it.hasNext())
- {
- ServiceReference ref = (ServiceReference) it.next();
- Integer rank = (Integer) ref.getProperty(Constants.SERVICE_RANKING);
- int ranking = (rank == null) ? Integer.MIN_VALUE : rank.intValue();
- long id = ((Long) ref.getProperty(Constants.SERVICE_ID)).longValue();
- if (maxRanking < ranking || (maxRanking == ranking && id < minId))
- {
- maxRanking = ranking;
- minId = id;
- selectedRef = ref;
- }
- }
- }
-
- // this is not realistic, as at least one service is available
- // whose service id is smaller than Long.MAX_VALUE, still be sure
- if (selectedRef == null)
- {
- return null;
- }
-
- // return the service for the selected reference
- return getBundleContext().getService(selectedRef);
- }
-
- public Object locateService(String name, ServiceReference ref) {
- DependencyManager dm = getDependencyManager(name);
- if (dm == null || dm.m_boundServicesRefs.isEmpty())
- {
- return null;
- }
-
- // is it correct to assume an ordered bound services set ?
- Iterator it = dm.m_boundServicesRefs.iterator();
- while (it.hasNext())
- {
- if (it.next().equals(ref))
- {
- return getBundleContext().getService(ref);
- }
- }
-
- // no matching name and service reference found
- return null;
- }
-
- public Object[] locateServices(String name) {
- DependencyManager dm = getDependencyManager(name);
- if (dm == null || dm.m_boundServicesRefs.isEmpty())
- {
- return null;
- }
-
- Object[] services = new Object[dm.m_boundServicesRefs.size()];
- Iterator it = dm.m_boundServicesRefs.iterator();
- for (int i=0; i < services.length && it.hasNext(); i++)
- {
- ServiceReference ref = (ServiceReference) it.next();
- services[i] = getBundleContext().getService(ref);
- }
- return services;
- }
-
- private DependencyManager getDependencyManager(String name) {
- Iterator it = m_dependencyManagers.iterator();
- while (it.hasNext())
- {
- DependencyManager dm = (DependencyManager)it.next();
-
- // if any of the dependency managers is unable to bind (it is invalid), the component is deactivated
- if (name.equals(dm.m_dependencyMetadata.getName()))
- {
- return dm;
- }
- }
-
- // not found
- return null;
- }
-
- public BundleContext getBundleContext() {
- return m_activator.getBundleContext();
- }
-
- public Bundle getUsingBundle() {
- return m_usingBundle;
- }
-
- public ComponentInstance getComponentInstance() {
- return ComponentManagerImpl.this;
- }
-
- public void enableComponent(String name) {
- m_activator.enableComponent(name);
- }
-
- public void disableComponent(String name) {
- m_activator.disableComponent(name);
- }
-
- public ServiceReference getServiceReference() {
- if(m_serviceRegistration != null) {
- return m_serviceRegistration.getReference();
- }
- else {
- return null;
- }
- }
- }
-
- /**
- * This class is a ServiceFactory that is used when a delayed component is created.
- * This class returns the same service object instance for all bundles.
- *
- */
- class DelayedComponentServiceFactory implements ServiceFactory {
-
- public Object getService(Bundle bundle, ServiceRegistration registration) {
-
- Activator.trace("DelayedComponentServiceFactory.getService()", m_componentMetadata);
- // When the getServiceMethod is called, the implementation object must be created
- // unless another bundle has already retrievd it
-
- if (m_implementationObject == null) {
- m_componentContext = new ComponentContextImpl(null);
- m_implementationObject = createImplementationObject( m_componentContext );
- }
-
- return m_implementationObject;
- }
-
- public void ungetService(Bundle bundle, ServiceRegistration registration, Object object) {
- // nothing to do here, delayed components are deactivated when
- // the component is deactivated and not when any bundle releases
- // the service
- }
-
- 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 = m_activator.getBundleContext().getBundle().loadClass(m_componentMetadata.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)
- {
- // TODO: manage this exception when implementation object cannot be created
- Activator.exception("Error during instantiation of the implementation object",m_componentMetadata,ex);
- deactivate();
- //invalidate();
- return null;
- }
-
-
- // 3. Bind the target services
- Iterator it = m_dependencyManagers.iterator();
-
- while ( it.hasNext() )
- {
- DependencyManager dm = (DependencyManager)it.next();
- Iterator bound = dm.m_boundServicesRefs.iterator();
- while ( bound.hasNext() ) {
- ServiceReference nextRef = (ServiceReference) bound.next();
- dm.invokeBindMethod(implementationObject, nextRef);
- }
- }
-
- // 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", m_componentMetadata);
- }
- catch(IllegalAccessException ex) {
- // Ignored, but should it be logged?
- Activator.trace("activate() method cannot be called", m_componentMetadata);
- }
- catch(InvocationTargetException ex) {
- // TODO: 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", m_componentMetadata, ex);
- }
-
- return implementationObject;
- }
- }
-
- /**
- * This class is a ServiceFactory that is used when a delayed component is created
- * for a service factory service
- *
- */
- class DelayedServiceFactoryServiceFactory extends DelayedComponentServiceFactory
- {
-
- // 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();
-
- public Object getService( Bundle bundle, ServiceRegistration registration )
- {
-
- Activator.trace( "DelayedServiceFactoryServiceFactory.getService()", m_componentMetadata );
- // When the getServiceMethod is called, the implementation object must be created
-
- // private ComponentContext and implementation instances
- ComponentContext componentContext = new ComponentContextImpl( bundle );
- Object implementationObject = createImplementationObject( componentContext );
-
- // register the components component context
- componentContexts.put( implementationObject, componentContext );
-
- return implementationObject;
- }
-
- public void ungetService( Bundle bundle, ServiceRegistration registration, Object implementationObject )
- {
- Activator.trace( "DelayedServiceFactoryServiceFactory.ungetService()", m_componentMetadata );
- // When the ungetServiceMethod is called, the implementation object must be deactivated
-
- // private ComponentContext and implementation instances
- ComponentContext componentContext = ( ComponentContext ) componentContexts.remove( implementationObject );
- deactivateImplementationObject( implementationObject, componentContext );
- }
-
- 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", m_componentMetadata );
- }
- catch ( IllegalAccessException ex )
- {
- // Ignored, but should it be logged?
- Activator.trace( "deactivate() method cannot be called", m_componentMetadata );
- }
- catch ( InvocationTargetException ex )
- {
- // TODO: 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", m_componentMetadata, ex );
- }
-
- // 2. Unbind any bound services
- Iterator it = m_dependencyManagers.iterator();
-
- while ( it.hasNext() )
- {
- DependencyManager dm = ( DependencyManager ) it.next();
- Iterator bound = dm.m_boundServicesRefs.iterator();
- while ( bound.hasNext() )
- {
- ServiceReference nextRef = ( ServiceReference ) bound.next();
- dm.invokeUnbindMethod( implementationObject, nextRef );
- }
- }
-
- // 3. Release all references
- // nothing to do, we keep no references on per-Bundle services
- }
- }
-
- /**
- * Finds the named public or protected method in the given class or any
- * super class. If such a method is found, its accessibility is enfored by
- * calling the <code>Method.setAccessible</code> method if required and
- * the method is returned. Enforcing accessibility is required to support
- * invocation of protected methods.
- *
- * @param clazz The <code>Class</code> which provides the method.
- * @param name The name of the method.
- * @param parameterTypes The parameters to the method. Passing
- * <code>null</code> is equivalent to using an empty array.
- *
- * @return The named method with enforced accessibility
- *
- * @throws NoSuchMethodException If no public or protected method with
- * the given name can be found in the class or any of its super classes.
- */
- private Method getMethod(Class clazz, String name, Class[] parameterTypes)
- throws NoSuchMethodException
- {
- // try the default mechanism first, which only yields public methods
- try
- {
- return clazz.getMethod(name, parameterTypes);
- }
- catch (NoSuchMethodException nsme)
- {
- // it is ok to not find a public method, try to find a protected now
- }
-
- // now use method declarations, requiring walking up the class
- // hierarchy manually. this algorithm also returns protected methods
- // which is, what we need here
- for ( ; clazz != null; clazz = clazz.getSuperclass())
- {
- try
- {
- Method method = clazz.getDeclaredMethod(name, parameterTypes);
-
- // only accept a protected method, a public method should
- // have been found above and neither private nor package
- // protected methods are acceptable here
- if (Modifier.isProtected(method.getModifiers())) {
- method.setAccessible(true);
- return method;
- }
- }
- catch (NoSuchMethodException nsme)
- {
- // ignore for now
- }
- }
-
- // walked up the complete super class hierarchy and still not found
- // anything, sigh ...
- throw new NoSuchMethodException(name);
- }
-}
diff --git a/scr/src/main/java/org/apache/felix/scr/ComponentRegistry.java b/scr/src/main/java/org/apache/felix/scr/ComponentRegistry.java
new file mode 100644
index 0000000..9460390
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/ComponentRegistry.java
@@ -0,0 +1,141 @@
+/*
+ * 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.awt.Component;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.component.ComponentException;
+
+
+/**
+ * The <code>ComponentRegistry</code> TODO
+ *
+ * @author fmeschbe
+ */
+public class ComponentRegistry implements ConfigurationListener
+{
+
+ // Known and registered ComponentManager instances
+ private Map m_componentNames;
+
+ // component id counter
+ private long m_componentCounter;
+
+ // the service registration of the ConfigurationListener service
+ private ServiceRegistration registration;
+
+
+ ComponentRegistry( BundleContext context )
+ {
+ m_componentNames = new HashMap();
+ m_componentCounter = -1;
+
+ Dictionary props = new Hashtable();
+ props.put( Constants.SERVICE_DESCRIPTION, "Service Component Configuration Support" );
+ props.put( Constants.SERVICE_VENDOR, "Apache Software Foundation" );
+ registration = context.registerService( ConfigurationListener.class.getName(), this, props );
+ }
+
+
+ void dispose()
+ {
+ if ( registration != null )
+ {
+ registration.unregister();
+ registration = null;
+ }
+ }
+
+
+ //---------- ConfigurationListener ----------------------------------------
+
+ public void configurationEvent( ConfigurationEvent configEvent )
+ {
+ String pid = configEvent.getPid();
+ ComponentManager cm = getComponent( pid );
+ if ( cm != null )
+ {
+ cm.reconfigure();
+ }
+ }
+
+
+ //---------- ComponentManager registration support ------------------------
+
+ long createComponentId()
+ {
+ m_componentCounter++;
+ return m_componentCounter;
+ }
+
+
+ void checkComponentName( String name )
+ {
+ if ( m_componentNames.containsKey( name ) )
+ {
+ throw new ComponentException( "The component name '" + name + "' has already been registered." );
+ }
+
+ // reserve the name
+ m_componentNames.put( name, name );
+ }
+
+
+ void registerComponent( String name, ComponentManager component )
+ {
+ // only register the component if there is a registration for it !
+ if ( !name.equals( m_componentNames.get( name ) ) )
+ {
+ // this is not expected if all works ok
+ throw new ComponentException( "The component name '" + name + "' has already been registered." );
+ }
+
+ m_componentNames.put( name, component );
+ }
+
+
+ ComponentManager getComponent( String name )
+ {
+ Object entry = m_componentNames.get( name );
+
+ // only return the entry if non-null and not a reservation
+ if ( entry instanceof ComponentManager )
+ {
+ return ( ComponentManager ) entry;
+ }
+
+ return null;
+ }
+
+
+ void unregisterComponent( String name )
+ {
+ m_componentNames.remove( name );
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/DelayedComponentManager.java b/scr/src/main/java/org/apache/felix/scr/DelayedComponentManager.java
new file mode 100644
index 0000000..70f7e24
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/DelayedComponentManager.java
@@ -0,0 +1,84 @@
+/*
+ * 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 org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+
+/**
+ * The <code>DelayedComponentManager</code> TODO
+ *
+ * @author fmeschbe
+ * @version $Rev$, $Date$
+ */
+public class DelayedComponentManager extends ImmediateComponentManager implements ServiceFactory
+{
+
+ /**
+ * @param activator
+ * @param metadata
+ * @param componentId
+ */
+ public DelayedComponentManager( BundleComponentActivator activator, ComponentMetadata metadata, long componentId )
+ {
+ super( activator, metadata, componentId );
+ }
+
+ protected void createComponent()
+ {
+ // nothing to do here for a delayed component, will be done in the
+ // getService method for the first bundle acquiring the component
+ }
+
+ protected Object getService()
+ {
+ return this;
+ }
+
+ //---------- ServiceFactory interface -------------------------------------
+
+ public Object getService( Bundle arg0, ServiceRegistration arg1 )
+ {
+ Activator.trace("DelayedComponentServiceFactory.getService()", getComponentMetadata());
+ // When the getServiceMethod is called, the implementation object must be created
+ // unless another bundle has already retrievd it
+
+ if (getInstance() == null) {
+ super.createComponent();
+
+ // if component creation failed, we were deactivated and the state
+ // is not REGISTERED any more. Otherwise go to standard ACTIVE
+ // state now
+ if (getState() == STATE_REGISTERED)
+ {
+ setState( STATE_ACTIVE );
+ }
+ }
+
+ return getInstance();
+ }
+
+ public void ungetService( Bundle arg0, ServiceRegistration arg1, Object arg2 )
+ {
+ // nothing to do here
+ }
+
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/DependencyManager.java b/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
new file mode 100644
index 0000000..daf64c3
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/DependencyManager.java
@@ -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;
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java b/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java
new file mode 100644
index 0000000..48b739f
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/ImmediateComponentManager.java
@@ -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;
+ }
+
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/ManagerFactory.java b/scr/src/main/java/org/apache/felix/scr/ManagerFactory.java
index 1903781..f326a0f 100644
--- a/scr/src/main/java/org/apache/felix/scr/ManagerFactory.java
+++ b/scr/src/main/java/org/apache/felix/scr/ManagerFactory.java
@@ -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() );
+ }
}
\ No newline at end of file
diff --git a/scr/src/main/java/org/apache/felix/scr/ReadOnlyDictionary.java b/scr/src/main/java/org/apache/felix/scr/ReadOnlyDictionary.java
new file mode 100644
index 0000000..6350535
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/ReadOnlyDictionary.java
@@ -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();
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java b/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java
new file mode 100644
index 0000000..9e476dd
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/ServiceFactoryComponentManager.java
@@ -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();
+ }
+ }
+}