FELIX-1416 Implement new ComponentHolder abstraction and adapt uses.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@798531 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
index 5d15d49..00e2bbc 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/Activator.java
@@ -26,6 +26,7 @@
import java.util.Iterator;
import java.util.Map;
+import org.apache.felix.scr.impl.config.ConfigurationComponentRegistry;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
@@ -78,7 +79,7 @@
{
m_context = context;
m_componentBundles = new HashMap();
- m_componentRegistry = new ComponentRegistry( m_context );
+ m_componentRegistry = createComponentRegistry( context);
// require the log service
m_logService = new ServiceTracker( context, LOGSERVICE_CLASS, null );
@@ -135,7 +136,7 @@
// 112.8.2 dispose off all active components
disposeAllComponents();
- // dispose off the component registry
+ // dispose component registry
m_componentRegistry.dispose();
// terminate the actor thread and wait for it for a limited time
@@ -293,6 +294,22 @@
}
+ public static ComponentRegistry createComponentRegistry( BundleContext bundleContext )
+ {
+ try
+ {
+ return new ConfigurationComponentRegistry( bundleContext );
+ }
+ catch ( Throwable t )
+ {
+ log( LogService.LOG_INFO, bundleContext.getBundle(),
+ "ConfigurationAdmin supporting ComponentRegistry not available, not using ConfigurationAdmin", t );
+ }
+
+ return new ComponentRegistry( bundleContext );
+ }
+
+
/**
* Returns the <code>BundleContext</code> of the bundle.
* <p>
@@ -426,7 +443,7 @@
* @param ex An optional <code>Throwable</code> whose stack trace is written,
* or <code>null</code> to not log a stack trace.
*/
- static void log( int level, Bundle bundle, String message, Throwable ex )
+ public static void log( int level, Bundle bundle, String message, Throwable ex )
{
if ( m_logLevel >= level )
{
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
index 3d4eed8..b18e56f 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/BundleComponentActivator.java
@@ -29,17 +29,13 @@
import java.util.List;
import java.util.StringTokenizer;
+import org.apache.felix.scr.impl.config.ComponentHolder;
import org.apache.felix.scr.impl.helper.Logger;
import org.apache.felix.scr.impl.manager.AbstractComponentManager;
-import org.apache.felix.scr.impl.manager.ComponentFactoryImpl;
-import org.apache.felix.scr.impl.manager.DelayedComponentManager;
-import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
-import org.apache.felix.scr.impl.manager.ServiceFactoryComponentManager;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.apache.felix.scr.impl.metadata.XmlHandler;
import org.apache.felix.scr.impl.parser.KXml2SAXParser;
import org.osgi.framework.BundleContext;
-import org.osgi.service.cm.ConfigurationAdmin;
import org.osgi.service.component.ComponentException;
import org.osgi.service.log.LogService;
import org.osgi.util.tracker.ServiceTracker;
@@ -62,9 +58,6 @@
private List m_managers = new ArrayList();
// The Configuration Admin tracker providing configuration for components
- private ServiceTracker m_configurationAdmin;
-
- // The Configuration Admin tracker providing configuration for components
private ServiceTracker m_logService;
// thread acting upon configurations
@@ -88,8 +81,8 @@
*
* @throws ComponentException if any error occurrs initializing this class
*/
- BundleComponentActivator( ComponentRegistry componentRegistry, ComponentActorThread componentActor,
- BundleContext context, int logLevel ) throws ComponentException
+ BundleComponentActivator( ComponentRegistry componentRegistry,
+ ComponentActorThread componentActor, BundleContext context, int logLevel ) throws ComponentException
{
// keep the parameters for later
m_componentRegistry = componentRegistry;
@@ -99,10 +92,6 @@
// mark this instance active
m_active = true;
- // have the Configuration Admin Service handy (if available)
- m_configurationAdmin = new ServiceTracker( context, ConfigurationAdmin.class.getName(), null );
- m_configurationAdmin.open();
-
// have the LogService handy (if available)
m_logService = new ServiceTracker( context, Activator.LOGSERVICE_CLASS, null );
m_logService.open();
@@ -176,46 +165,18 @@
metadata.validate( this );
// Request creation of the component manager
- AbstractComponentManager 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 if ( metadata.isImmediate() )
- {
- manager = new ImmediateComponentManager( this, metadata, m_componentRegistry );
- }
- else if ( metadata.getServiceMetadata() != null )
- {
- if ( metadata.getServiceMetadata().isServiceFactory() )
- {
- manager = new ServiceFactoryComponentManager( this, metadata, m_componentRegistry );
- }
- else
- {
- manager = new DelayedComponentManager( this, metadata, m_componentRegistry );
- }
- }
- else
- {
- // if we get here, which is not expected after all, we fail
- throw new IllegalArgumentException( "Cannot create a component manager for "
- + metadata.getName() );
- }
+ ComponentHolder holder = m_componentRegistry.createComponentHolder( this, metadata );
// register the component after validation
- m_componentRegistry.registerComponent( metadata.getName(), manager );
- m_managers.add( manager );
+ m_componentRegistry.registerComponent( metadata.getName(), holder );
+ m_managers.add( holder );
// enable the component
if ( metadata.isEnabled() )
{
- manager.enable();
+ holder.enableComponents();
}
- }
+ }
catch ( Throwable t )
{
// There is a problem with this particular component, we'll log the error
@@ -275,30 +236,24 @@
while ( m_managers.size() != 0 )
{
- AbstractComponentManager manager = ( AbstractComponentManager ) m_managers.get( 0 );
+ ComponentHolder holder = ( ComponentHolder ) m_managers.get( 0 );
try
{
- m_managers.remove( manager );
- manager.dispose( reason );
+ m_managers.remove( holder );
+ holder.disposeComponents( reason );
}
catch ( Exception e )
{
- log( LogService.LOG_ERROR, "BundleComponentActivator : Exception invalidating", manager
+ log( LogService.LOG_ERROR, "BundleComponentActivator : Exception invalidating", holder
.getComponentMetadata(), e );
}
finally
{
- m_componentRegistry.unregisterComponent( manager.getComponentMetadata().getName() );
+ m_componentRegistry.unregisterComponent( holder.getComponentMetadata().getName() );
}
}
- // close the Configuration Admin tracker
- if ( m_configurationAdmin != null )
- {
- m_configurationAdmin.close();
- }
-
log( LogService.LOG_DEBUG, "BundleComponentActivator : Bundle [" + m_context.getBundle().getBundleId()
+ "] STOPPED", null, null );
@@ -319,17 +274,6 @@
/**
- * Returns the list of instance references currently associated to this activator
- *
- * @return the list of instance references
- */
- public List getInstanceReferences()
- {
- return m_managers;
- }
-
-
- /**
* Returns the BundleContext
*
* @return the BundleContext
@@ -341,18 +285,6 @@
/**
- * 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.
@@ -365,21 +297,21 @@
*/
public void enableComponent( String name )
{
- final AbstractComponentManager[] cm = getSelectedComponents( name );
- if ( cm == null )
+ final ComponentHolder[] holder = getSelectedComponents( name );
+ if ( holder == null )
{
return;
}
- for ( int i = 0; i < cm.length; i++ )
+ for ( int i = 0; i < holder.length; i++ )
{
try
{
- cm[i].enable();
+ holder[i].enableComponents();
}
catch ( Throwable t )
{
- log( LogService.LOG_ERROR, "Cannot enable component", cm[i].getComponentMetadata(), t );
+ log( LogService.LOG_ERROR, "Cannot enable component", holder[i].getComponentMetadata(), t );
}
}
}
@@ -398,22 +330,22 @@
*/
public void disableComponent( String name )
{
- final AbstractComponentManager[] cm = getSelectedComponents( name );
- if ( cm == null )
+ final ComponentHolder[] holder = getSelectedComponents( name );
+ if ( holder == null )
{
return;
}
- for ( int i = 0; i < cm.length; i++ )
+ for ( int i = 0; i < holder.length; i++ )
{
try
{
- log( LogService.LOG_DEBUG, "Disabling Component", cm[i].getComponentMetadata(), null );
- cm[i].disable();
+ log( LogService.LOG_DEBUG, "Disabling Component", holder[i].getComponentMetadata(), null );
+ holder[i].disableComponents();
}
catch ( Throwable t )
{
- log( LogService.LOG_ERROR, "Cannot disable component", cm[i].getComponentMetadata(), t );
+ log( LogService.LOG_ERROR, "Cannot disable component", holder[i].getComponentMetadata(), t );
}
}
}
@@ -434,12 +366,12 @@
* to the <code>name</code> parameter or <code>null</code> if no
* component manager with the given name is currently registered.
*/
- private AbstractComponentManager[] getSelectedComponents( String name )
+ private ComponentHolder[] getSelectedComponents( String name )
{
// if all components are selected
if ( name == null )
{
- return (org.apache.felix.scr.impl.manager.AbstractComponentManager[] ) m_managers.toArray( new AbstractComponentManager[m_managers.size()] );
+ return ( ComponentHolder[] ) m_managers.toArray( new ComponentHolder[m_managers.size()] );
}
if ( m_componentRegistry.getComponent( name ) != null )
@@ -448,10 +380,10 @@
Iterator it = m_managers.iterator();
while ( it.hasNext() )
{
- AbstractComponentManager cm = ( AbstractComponentManager ) it.next();
+ ComponentHolder cm = ( ComponentHolder ) it.next();
if ( name.equals( cm.getComponentMetadata().getName() ) )
{
- return new AbstractComponentManager[]
+ return new ComponentHolder[]
{ cm };
}
}
@@ -462,6 +394,16 @@
}
+ //---------- Component ID support
+
+ public long registerComponentId(AbstractComponentManager componentManager) {
+ return m_componentRegistry.registerComponentId(componentManager);
+ }
+
+ public void unregisterComponentId(AbstractComponentManager componentManager) {
+ m_componentRegistry.unregisterComponentId(componentManager.getId());
+ }
+
//---------- Asynchronous Component Handling ------------------------------
/**
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
index 03cee8f..31771c6 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/ComponentRegistry.java
@@ -19,7 +19,6 @@
package org.apache.felix.scr.impl;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashMap;
@@ -29,44 +28,69 @@
import org.apache.felix.scr.Component;
import org.apache.felix.scr.ScrService;
+import org.apache.felix.scr.impl.config.ComponentHolder;
+import org.apache.felix.scr.impl.config.UnconfiguredComponentHolder;
import org.apache.felix.scr.impl.manager.AbstractComponentManager;
import org.apache.felix.scr.impl.manager.ComponentFactoryImpl;
-import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
-import org.osgi.framework.InvalidSyntaxException;
-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.cm.ConfigurationEvent;
-import org.osgi.service.cm.ConfigurationListener;
import org.osgi.service.component.ComponentException;
/**
- * The <code>ComponentRegistry</code> TODO
- *
- * @author fmeschbe
+ * The <code>ComponentRegistry</code> class acts as the global registry for
+ * components by name and by component ID. As such the component registry also
+ * registers itself as the {@link ScrService} to support access to the
+ * registered components.
*/
-public class ComponentRegistry implements ScrService, ConfigurationListener
+public class ComponentRegistry implements ScrService
{
- // Known and registered ComponentManager instances
+ /**
+ * The map of known components indexed by component name. The values are
+ * either the component names (for name reservations) or implementations
+ * of the {@link ComponentHolder} interface.
+ * <p>
+ * The {@link #checkComponentName(String)} will first add an entry to this
+ * map being the name of the component to reserve the name. After setting up
+ * the component, the {@link #registerComponent(String, ComponentHolder)}
+ * method replaces the value of the named entry with the actual
+ * {@link ComponentHolder}.
+ *
+ * @see #checkComponentName(String)
+ * @see #registerComponent(String, ComponentHolder)
+ * @see #unregisterComponent(String)
+ */
private Map m_componentsByName;
- // components registered by their component ID
+ /**
+ * Map of components by component ID. This map indexed by the component
+ * ID number (<code>java.lang.Long</code>) contains the actual
+ * {@link AbstractComponentManager} instances existing in the system.
+ *
+ * @see #registerComponentId(AbstractComponentManager)
+ * @see #unregisterComponentId(long)
+ */
private Map m_componentsById;
- // component id counter
- private long m_componentCounter;
+ /**
+ * Counter to setup the component IDs as issued by the
+ * {@link #registerComponentId(AbstractComponentManager)} method. This
+ * counter is only incremented.
+ */
+ private volatile long m_componentCounter;
- // the service m_registration of the ConfigurationListener service
+ /**
+ * The OSGi service registration for the ScrService provided by this
+ * instance.
+ */
private ServiceRegistration m_registration;
- ComponentRegistry( BundleContext context )
+ protected ComponentRegistry( BundleContext context )
{
m_componentsByName = new HashMap();
m_componentsById = new HashMap();
@@ -77,11 +101,11 @@
props.put( Constants.SERVICE_DESCRIPTION, "Declarative Services Management Agent" );
props.put( Constants.SERVICE_VENDOR, "The Apache Software Foundation" );
m_registration = context.registerService( new String[]
- { ScrService.class.getName(), ConfigurationListener.class.getName() }, this, props );
+ { ScrService.class.getName(), }, this, props );
}
- void dispose()
+ public void dispose()
{
if ( m_registration != null )
{
@@ -142,157 +166,80 @@
}
- //---------- ConfigurationListener
+ //---------- ComponentManager registration by component Id
- public void configurationEvent( ConfigurationEvent event )
+ /**
+ * Assigns a unique ID to the component, internally registers the
+ * component under that ID and returns the assigned component ID.
+ *
+ * @param componentManager The {@link AbstractComponentManager} for which
+ * to assign a component ID and which is to be internally registered
+ *
+ * @return the assigned component ID
+ */
+ final long registerComponentId( final AbstractComponentManager componentManager )
{
- final String pid = event.getPid();
- final String factoryPid = event.getFactoryPid();
-
- final AbstractComponentManager cm;
- if ( factoryPid == null )
+ long componentId;
+ synchronized ( this )
{
- cm = getComponent( pid );
- }
- else
- {
- cm = getComponent( factoryPid );
+ m_componentCounter++;
+ componentId = m_componentCounter;
}
- if (cm == null) {
- // this configuration is not for a SCR component
- return;
- }
+ m_componentsById.put( new Long( componentId ), componentManager );
- switch ( event.getType() )
- {
- case ConfigurationEvent.CM_DELETED:
- if ( cm instanceof ImmediateComponentManager )
- {
- ( ( ImmediateComponentManager ) cm ).reconfigure( null );
- }
- else if ( cm instanceof ComponentFactoryImpl )
- {
- ( ( ComponentFactoryImpl ) cm ).deleted( pid );
- }
- break;
- case ConfigurationEvent.CM_UPDATED:
- BundleContext ctx = cm.getActivator().getBundleContext();
- Dictionary dict = getConfiguration( event.getReference(), ctx, pid );
- if ( dict != null )
- {
- if ( cm instanceof ImmediateComponentManager )
- {
- ( ( ImmediateComponentManager ) cm ).reconfigure( dict );
- }
- else if ( cm instanceof ComponentFactoryImpl )
- {
- ( ( ComponentFactoryImpl ) cm ).updated( pid, dict );
- }
- }
- break;
- }
-
+ return componentId;
}
- private Dictionary getConfiguration( final ServiceReference cfgAdmin, final BundleContext ctx, final String pid )
+ /**
+ * Unregisters the component with the given component ID from the internal
+ * registry. After unregistration, the component ID should be considered
+ * invalid.
+ *
+ * @param componentId The ID of the component to be removed from the
+ * internal component registry.
+ */
+ final void unregisterComponentId( final long componentId )
{
- final ConfigurationAdmin ca = ( ConfigurationAdmin ) ctx.getService( cfgAdmin );
- if ( ca != null )
- {
- try
- {
- final Configuration cfg = ca.getConfiguration( pid );
- if ( ctx.getBundle().getLocation().equals( cfg.getBundleLocation() ) )
- {
- return cfg.getProperties();
- }
- }
- catch ( IOException ioe )
- {
- // TODO: log
- }
- finally
- {
- ctx.ungetService( cfgAdmin );
- }
- }
-
- return null;
+ m_componentsById.remove( new Long( componentId ) );
}
- public Configuration getConfiguration( final BundleContext ctx, final String pid )
- {
- final String filter = "(service.pid=" + pid + ")";
- Configuration[] cfg = getConfigurationInternal( ctx, filter );
- return ( cfg == null || cfg.length == 0 ) ? null : cfg[0];
- }
+ //---------- ComponentHolder registration by component name
-
- public Configuration[] getConfigurations( final BundleContext ctx, final String factoryPid )
- {
- final String filter = "(service.factoryPid=" + factoryPid + ")";
- return getConfigurationInternal( ctx, filter );
- }
-
-
- private Configuration[] getConfigurationInternal( final BundleContext ctx, final String filter )
- {
- final ServiceReference cfgAdmin = ctx.getServiceReference( ConfigurationAdmin.class.getName() );
- final ConfigurationAdmin ca = ( ConfigurationAdmin ) ctx.getService( cfgAdmin );
- if ( ca != null )
- {
- try
- {
- return ca.listConfigurations( filter );
- }
- catch ( IOException ioe )
- {
- // TODO: log
- }
- catch ( InvalidSyntaxException ise )
- {
- // TODO: log
- }
- finally
- {
- ctx.ungetService( cfgAdmin );
- }
- }
-
- return null;
- }
-
-
- //---------- ComponentManager registration support
-
- public long createComponentId()
- {
- m_componentCounter++;
- return m_componentCounter;
- }
-
-
- public void checkComponentName( String name )
+ /**
+ * Checks whether the component name is "globally" unique or not. If it is
+ * unique, it is reserved until the actual component is registered with
+ * {@link #registerComponent(String, AbstractComponentManager)} or until
+ * it is unreserved by calling {@link #unregisterComponent(String)}.
+ * If a component with the same name has already been reserved or registered
+ * a ComponentException is thrown with a descriptive message.
+ *
+ * @param name the component name to check and reserve
+ * @throws ComponentException if the name is already in use by another
+ * component.
+ */
+ final void checkComponentName( String name )
{
if ( m_componentsByName.containsKey( name ) )
{
String message = "The component name '" + name + "' has already been registered";
Object co = m_componentsByName.get( name );
- if ( co instanceof AbstractComponentManager )
+ if ( co instanceof ComponentHolder )
{
- AbstractComponentManager c = ( AbstractComponentManager ) co;
+ ComponentHolder c = ( ComponentHolder ) co;
+ Bundle cBundle = c.getActivator().getBundleContext().getBundle();
+ ComponentMetadata cMeta = c.getComponentMetadata();
+
StringBuffer buf = new StringBuffer( message );
- buf.append( " by Bundle " ).append( c.getBundle().getBundleId() );
- if ( c.getBundle().getSymbolicName() != null )
+ buf.append( " by Bundle " ).append( cBundle.getBundleId() );
+ if ( cBundle.getSymbolicName() != null )
{
- buf.append( " (" ).append( c.getBundle().getSymbolicName() ).append( ")" );
+ buf.append( " (" ).append( cBundle.getSymbolicName() ).append( ")" );
}
- buf.append( " as Component " ).append( c.getId() );
- buf.append( " of Class " ).append( c.getClassName() );
+ buf.append( " as Component of Class " ).append( cMeta.getImplementationClassName() );
message = buf.toString();
}
@@ -304,7 +251,18 @@
}
- void registerComponent( String name, AbstractComponentManager component )
+ /**
+ * Registers the given component under the given name. If the name has not
+ * already been reserved calling {@link #checkComponentName(String)} this
+ * method throws a {@link ComponentException}.
+ *
+ * @param name The name to register the component under
+ * @param component The component to register
+ *
+ * @throws ComponentException if the name has not been reserved through
+ * {@link #checkComponentName(String)} yet.
+ */
+ final void registerComponent( String name, ComponentHolder component )
{
// only register the component if there is a m_registration for it !
if ( !name.equals( m_componentsByName.get( name ) ) )
@@ -314,31 +272,56 @@
}
m_componentsByName.put( name, component );
- m_componentsById.put( new Long( component.getId() ), component );
}
- AbstractComponentManager getComponent( String name )
+ /**
+ * Returns the component registered under the given name or <code>null</code>
+ * if no component is registered yet.
+ */
+ public final ComponentHolder getComponent( String name )
{
Object entry = m_componentsByName.get( name );
// only return the entry if non-null and not a reservation
- if ( entry instanceof AbstractComponentManager )
+ if ( entry instanceof ComponentHolder )
{
- return ( AbstractComponentManager ) entry;
+ return ( ComponentHolder ) entry;
}
return null;
}
- void unregisterComponent( String name )
+ /**
+ * Removes the component registered under that name. If no component is
+ * yet registered but the name is reserved, it is unreserved.
+ * <p>
+ * After calling this method, the name can be reused by other components.
+ */
+ final void unregisterComponent( String name )
{
- Object entry = m_componentsByName.remove( name );
- if ( entry instanceof AbstractComponentManager )
- {
- Long id = new Long( ( ( AbstractComponentManager ) entry ).getId() );
- m_componentsById.remove( id );
- }
+ m_componentsByName.remove( name );
}
+
+
+ //---------- base configuration support
+
+ /**
+ * Factory method to issue {@link ComponentHolder} instances to manage
+ * components described by the given component <code>metadata</code>.
+ */
+ public ComponentHolder createComponentHolder( BundleComponentActivator activator, ComponentMetadata metadata )
+ {
+ 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
+ return new ComponentFactoryImpl( activator, metadata );
+ }
+
+ return new UnconfiguredComponentHolder( activator, metadata );
+ }
+
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/AbstractComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/AbstractComponentHolder.java
new file mode 100644
index 0000000..cb06c2f
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/AbstractComponentHolder.java
@@ -0,0 +1,94 @@
+/*
+ * 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.impl.config;
+
+
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.manager.DelayedComponentManager;
+import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
+import org.apache.felix.scr.impl.manager.ServiceFactoryComponentManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+
+
+abstract class AbstractComponentHolder implements ComponentHolder
+{
+
+ private final BundleComponentActivator m_activator;
+
+ private final ComponentMetadata m_componentMetadata;
+
+
+ public AbstractComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
+ {
+ this.m_activator = activator;
+ this.m_componentMetadata = metadata;
+ }
+
+
+ protected ImmediateComponentManager createComponentManager()
+ {
+
+ ImmediateComponentManager manager;
+ if ( m_componentMetadata.isFactory() )
+ {
+ throw new IllegalArgumentException( "Cannot create component factory for " + m_componentMetadata.getName() );
+ }
+ else if ( m_componentMetadata.isImmediate() )
+ {
+ manager = new ImmediateComponentManager( m_activator, m_componentMetadata );
+ }
+ else if ( m_componentMetadata.getServiceMetadata() != null )
+ {
+ if ( m_componentMetadata.getServiceMetadata().isServiceFactory() )
+ {
+ manager = new ServiceFactoryComponentManager( m_activator, m_componentMetadata );
+ }
+ else
+ {
+ manager = new DelayedComponentManager( m_activator, m_componentMetadata );
+ }
+ }
+ else
+ {
+ // if we get here, which is not expected after all, we fail
+ throw new IllegalArgumentException( "Cannot create a component manager for "
+ + m_componentMetadata.getName() );
+ }
+
+ return manager;
+ }
+
+
+ public final BundleComponentActivator getActivator()
+ {
+ return m_activator;
+ }
+
+
+ public final ComponentMetadata getComponentMetadata()
+ {
+ return m_componentMetadata;
+ }
+
+
+ protected final String getComponentName()
+ {
+ return getComponentMetadata().getName();
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
new file mode 100644
index 0000000..5532a1d
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ComponentHolder.java
@@ -0,0 +1,89 @@
+/*
+ * 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.impl.config;
+
+
+import java.util.Dictionary;
+
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+
+
+/**
+ * The <code>ComponentHolder</code> interface provides the API for supporting
+ * component instances configured through either singleton configurations (or
+ * no configuration at all) and factory configurations.
+ * <p>
+ * Instances of this interface are managed by the {@link ConfigurationSupport}
+ * class on behalf of the
+ * {@link org.apache.felix.scr.impl.BundleComponentActivator} and the
+ * {@link org.apache.felix.scr.impl.ComponentRegistry}.
+ */
+public interface ComponentHolder
+{
+
+ /**
+ * Returns the {@link BundleComponentActivator} owning this component
+ * holder.
+ */
+ BundleComponentActivator getActivator();
+
+
+ /**
+ * Returns the {@link ComponentMetadata} describing and declaring this
+ * component.
+ */
+ ComponentMetadata getComponentMetadata();
+
+
+ /**
+ * The configuration with the given PID has been deleted from the
+ * Configuration Admin service.
+ *
+ * @param pid The PID of the deleted configuration
+ */
+ void configurationDeleted( String pid );
+
+
+ /**
+ * Configure a component with configuration from the given PID.
+ *
+ * @param pid The PID of the configuration used to configure the component
+ */
+ void configurationUpdated( String pid, Dictionary props );
+
+
+ /**
+ * Enables all components of this holder.
+ */
+ void enableComponents();
+
+
+ /**
+ * Disables all components of this holder.
+ */
+ void disableComponents();
+
+
+ /**
+ * Disposes off all components of this holder.
+ * @param reason
+ */
+ void disposeComponents( int reason );
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationComponentRegistry.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationComponentRegistry.java
new file mode 100644
index 0000000..4f076a8
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfigurationComponentRegistry.java
@@ -0,0 +1,263 @@
+/*
+ * 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.impl.config;
+
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.scr.impl.Activator;
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.ComponentRegistry;
+import org.apache.felix.scr.impl.manager.ComponentFactoryImpl;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+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.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+import org.osgi.service.log.LogService;
+
+
+public class ConfigurationComponentRegistry extends ComponentRegistry implements ConfigurationListener
+{
+
+ // the service m_registration of the ConfigurationListener service
+ private ServiceRegistration m_registration;
+
+
+ public ConfigurationComponentRegistry( final BundleContext context )
+ {
+ super( context );
+
+ // register as ScrService
+ Dictionary props = new Hashtable();
+ props.put( Constants.SERVICE_DESCRIPTION, "Declarative Services Configuration Support Listener" );
+ props.put( Constants.SERVICE_VENDOR, "The Apache Software Foundation" );
+ m_registration = context.registerService( new String[]
+ { ConfigurationListener.class.getName() }, this, props );
+ }
+
+
+ public void dispose()
+ {
+ if ( m_registration != null )
+ {
+ m_registration.unregister();
+ m_registration = null;
+ }
+
+ super.dispose();
+ }
+
+
+ //---------- BaseConfigurationSupport overwrites
+
+ public ComponentHolder createComponentHolder( final BundleComponentActivator activator,
+ final ComponentMetadata metadata )
+ {
+ // 112.7 configure unless configuration not required
+ if ( metadata.isConfigurationIgnored() )
+ {
+ return super.createComponentHolder( activator, metadata );
+ }
+
+ // prepare the configuration holder
+ final ComponentHolder holder;
+ if ( metadata.isFactory() )
+ {
+ holder = new ComponentFactoryImpl( activator, metadata );
+ }
+ else
+ {
+ holder = new ConfiguredComponentHolder( activator, metadata );
+ }
+
+ final BundleContext bundleContext = activator.getBundleContext();
+ final String bundleLocation = bundleContext.getBundle().getLocation();
+ final String name = metadata.getName();
+
+ final ServiceReference caRef = bundleContext.getServiceReference( ConfigurationAdmin.class.getName() );
+ if ( caRef != null )
+ {
+ final ConfigurationAdmin ca = ( ConfigurationAdmin ) bundleContext.getService( caRef );
+ if ( ca != null )
+ {
+ final Configuration[] factory = findFactoryConfigurations( ca, name );
+ if ( factory != null )
+ {
+ for ( int i = 0; i < factory.length; i++ )
+ {
+ final String pid = factory[i].getPid();
+ final Dictionary props = getConfiguration( ca, pid, bundleLocation );
+ holder.configurationUpdated( pid, props );
+ }
+ }
+ else
+ {
+ // check for configuration and configure the holder
+ final Configuration singleton = findSingletonConfiguration( ca, name );
+ if ( singleton != null )
+ {
+ final Dictionary props = getConfiguration( ca, name, bundleLocation );
+ holder.configurationUpdated( name, props );
+ }
+ }
+ }
+ }
+
+ return holder;
+ }
+
+
+ //---------- ConfigurationListener
+
+ public void configurationEvent( ConfigurationEvent event )
+ {
+ final String pid = event.getPid();
+ final String factoryPid = event.getFactoryPid();
+
+ final ComponentHolder cm;
+ if ( factoryPid == null )
+ {
+ cm = getComponent( pid );
+ }
+ else
+ {
+ cm = getComponent( factoryPid );
+ }
+
+ if ( cm != null && !cm.getComponentMetadata().isConfigurationIgnored() )
+ {
+ switch ( event.getType() )
+ {
+ case ConfigurationEvent.CM_DELETED:
+ cm.configurationDeleted( pid );
+ break;
+
+ case ConfigurationEvent.CM_UPDATED:
+ final BundleContext bundleContext = cm.getActivator().getBundleContext();
+ final ServiceReference caRef = bundleContext.getServiceReference( ConfigurationAdmin.class
+ .getName() );
+ if ( caRef != null )
+ {
+ final ConfigurationAdmin ca = ( ConfigurationAdmin ) bundleContext.getService( caRef );
+ if ( ca != null )
+ {
+ try
+ {
+ final Dictionary dict = getConfiguration( ca, pid, bundleContext.getBundle().getLocation() );
+ if ( dict != null )
+ {
+ cm.configurationUpdated( pid, dict );
+ }
+ }
+ finally
+ {
+ bundleContext.ungetService( caRef );
+ }
+ }
+ }
+ break;
+
+ default:
+ Activator.log( LogService.LOG_WARNING, null, "Unknown ConfigurationEvent type " + event.getType(),
+ null );
+ }
+ }
+ }
+
+
+ private Dictionary getConfiguration( final ConfigurationAdmin ca, final String pid, final String bundleLocation )
+ {
+ try
+ {
+ final Configuration cfg = ca.getConfiguration( pid );
+ if ( bundleLocation.equals( cfg.getBundleLocation() ) )
+ {
+ return cfg.getProperties();
+ }
+
+ // configuration belongs to another bundle, cannot be used here
+ Activator.log( LogService.LOG_ERROR, null, "Cannot use configuration pid=" + pid + " for bundle "
+ + bundleLocation + " because it belongs to bundle " + cfg.getBundleLocation(), null );
+ }
+ catch ( IOException ioe )
+ {
+ Activator.log( LogService.LOG_WARNING, null, "Failed reading configuration for pid=" + pid, ioe );
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Returns the configuration whose PID equals the given pid. If no such
+ * configuration exists, <code>null</code> is returned.
+ * @param ctx
+ * @param pid
+ * @return
+ */
+ public Configuration findSingletonConfiguration( final ConfigurationAdmin ca, final String pid )
+ {
+ final String filter = "(service.pid=" + pid + ")";
+ final Configuration[] cfg = findConfigurations( ca, filter );
+ return ( cfg == null || cfg.length == 0 ) ? null : cfg[0];
+ }
+
+
+ /**
+ * Returns all configurations whose factory PID equals the given factory PID
+ * or <code>null</code> if no such configurations exist
+ * @param ctx
+ * @param factoryPid
+ * @return
+ */
+ public Configuration[] findFactoryConfigurations( final ConfigurationAdmin ca, final String factoryPid )
+ {
+ final String filter = "(service.factoryPid=" + factoryPid + ")";
+ return findConfigurations( ca, filter );
+ }
+
+
+ private Configuration[] findConfigurations( final ConfigurationAdmin ca, final String filter )
+ {
+ try
+ {
+ return ca.listConfigurations( filter );
+ }
+ catch ( IOException ioe )
+ {
+ Activator
+ .log( LogService.LOG_WARNING, null, "Problem listing configurations for filter=" + filter, ioe );
+ }
+ catch ( InvalidSyntaxException ise )
+ {
+ Activator.log( LogService.LOG_ERROR, null, "Invalid Configuration selection filter " + filter, ise );
+ }
+
+ // no factories in case of problems
+ return null;
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java
new file mode 100644
index 0000000..cb9fc4e
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/ConfiguredComponentHolder.java
@@ -0,0 +1,336 @@
+/*
+ * 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.impl.config;
+
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+import org.osgi.service.component.ComponentConstants;
+
+
+/**
+ * The <code>ConfiguredComponentHolder</code> class is a
+ * {@link ComponentHolder} for one or more components instances configured by
+ * singleton or factory configuration objects received from the Configuration
+ * Admin service.
+ * <p>
+ * This holder is used only for components configured (optionally or required)
+ * by the Configuration Admin service. It is not used for components declared
+ * as ignoring configuration or if no Configuration Admin service is available.
+ * <p>
+ * The holder copes with three situations:
+ * <ul>
+ * <li>No configuration is available for the held component. That is there is
+ * no configuration whose <code>service.pid</code> or
+ * <code>service.factoryPid</code> equals the component name.</li>
+ * <li>A singleton configuration is available whose <code>service.pid</code>
+ * equals the component name.</li>
+ * <li>One or more factory configurations exist whose
+ * <code>service.factoryPid</code> equals the component name.</li>
+ * </ul>
+ */
+public class ConfiguredComponentHolder extends AbstractComponentHolder
+{
+
+ /**
+ * A map of components configured with factory configuration. The indices
+ * are the PIDs (<code>service.pid</code>) of the configuration objects.
+ * The values are the {@link ImmediateComponentManager component instances}
+ * created on behalf of the configurations.
+ */
+ private final Map m_components;
+
+ /**
+ * The special component used if there is no configuration or a singleton
+ * configuration. This field is always non-<code>null</code> and is first
+ * created in the constructor. As factory configurations are provided this
+ * instance may be configured or "deconfigured".
+ * <p>
+ * Expected invariants:
+ * <ul>
+ * <li>This field is never <code>null</code></li>
+ * <li>The {@link #m_components} map is empty or the component pointed to
+ * by this field is also contained in the map</li>
+ * <ul>
+ */
+ private ImmediateComponentManager m_singleComponent;
+
+ /**
+ * Whether components have already been enabled by calling the
+ * {@link #enableComponents()} method. If this field is <code>true</code>
+ * component instances created per configuration by the
+ * {@link #configurationUpdated(String, Dictionary)} method are also
+ * enabled. Otherwise they are not enabled immediately.
+ */
+ private boolean m_enabled;
+
+
+ ConfiguredComponentHolder( final BundleComponentActivator activator, final ComponentMetadata metadata )
+ {
+ super( activator, metadata );
+
+ this.m_components = new HashMap();
+ this.m_singleComponent = createComponentManager();
+ this.m_enabled = false;
+ }
+
+
+ /**
+ * The configuration with the given <code>pid</code>
+ * (<code>service.pid</code> of the configuration object) is deleted.
+ * <p>
+ * The following situations are supported:
+ * <ul>
+ * <li>The configuration was a singleton configuration (pid equals the
+ * component name). In this case the internal component map is empty and
+ * the single component has been configured by the singleton configuration
+ * and is no "deconfigured".</li>
+ * <li>A factory configuration object has been deleted and the configured
+ * object is set as the single component. If the single component held the
+ * last factory configuration object, it is deconfigured. Otherwise the
+ * single component is disposed off and replaced by another component in
+ * the map of existing components.</li>
+ * <li>A factory configuration object has been deleted and the configured
+ * object is not set as the single component. In this case the component is
+ * simply disposed off and removed from the internal map.</li>
+ * </ul>
+ */
+ public void configurationDeleted( final String pid )
+ {
+ if ( pid.equals( getComponentName() ) )
+ {
+ // singleton configuration deleted
+ m_singleComponent.reconfigure( null );
+ }
+ else
+ {
+ // remove the component configured with the deleted configuration
+ ImmediateComponentManager icm = removeComponentManager( pid );
+ if ( icm != null )
+ {
+ // special casing if the single component is deconfigured
+ if ( m_singleComponent == icm )
+ {
+
+ // if the single component is the last remaining, deconfi
+ if ( m_components.isEmpty() )
+ {
+
+ // if the single component is the last remaining
+ // deconfigure it
+ icm.reconfigure( null );
+ icm = null;
+
+ }
+ else
+ {
+
+ // replace the single component field with another
+ // entry from the map
+ m_singleComponent = ( ImmediateComponentManager ) m_components.values().iterator().next();
+
+ }
+ }
+
+ // icm may be null if the last configuration deleted was the
+ // single component's configuration. Otherwise the component
+ // is not the "last" and has to be disposed off
+ if ( icm != null )
+ {
+ icm.dispose( ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED );
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Configures a component with the given configuration. This configuration
+ * update may happen in various situations:
+ * <ul>
+ * <li>The <code>pid</code> equals the component name. Hence we have a
+ * singleton configuration for the single component held by this holder</li>
+ * <li>The configuration is a factory configuration and is the first
+ * configuration provided. In this case the single component is provided
+ * with the configuration and also stored in the map.</li>
+ * <li>The configuration is a factory configuration but not the first. In
+ * this case a new component is created, configured and stored in the map</li>
+ * </ul>
+ */
+ public void configurationUpdated( final String pid, final Dictionary props )
+ {
+ if ( pid.equals( getComponentName() ) )
+ {
+ // singleton configuration has pid equal to component name
+ m_singleComponent.reconfigure( props );
+ }
+ else
+ {
+ // factory configuration update or created
+ final ImmediateComponentManager icm = getComponentManager( pid );
+ if ( icm != null )
+ {
+ // factory configuration updated for existing component instance
+ icm.reconfigure( props );
+ }
+ else
+ {
+ // factory configuration created
+ final ImmediateComponentManager newIcm;
+ if ( !m_singleComponent.hasConfiguration() )
+ {
+ // configure the single instance if this is not configured
+ newIcm = m_singleComponent;
+ }
+ else
+ {
+ // otherwise create a new instance to provide the config to
+ newIcm = createComponentManager();
+ }
+
+ // configure the component
+ newIcm.reconfigure( props );
+
+ // enable the component if it is initially enabled
+ if ( m_enabled && getComponentMetadata().isEnabled() )
+ {
+ newIcm.enable();
+ }
+
+ // store the component in the map
+ putComponentManager( pid, newIcm );
+ }
+ }
+ }
+
+
+ public void enableComponents()
+ {
+ final ImmediateComponentManager[] cms = getComponentManagers( false );
+ if ( cms == null )
+ {
+ m_singleComponent.enable();
+ }
+ else
+ {
+ for ( int i = 0; i < cms.length; i++ )
+ {
+ cms[i].enable();
+ }
+ }
+
+ m_enabled = true;
+ }
+
+
+ public void disableComponents()
+ {
+ final ImmediateComponentManager[] cms = getComponentManagers( false );
+ if ( cms == null )
+ {
+ m_singleComponent.disable();
+ }
+ else
+ {
+ for ( int i = 0; i < cms.length; i++ )
+ {
+ cms[i].disable();
+ }
+ }
+ }
+
+
+ public void disposeComponents( final int reason )
+ {
+ final ImmediateComponentManager[] cms = getComponentManagers( true );
+ if ( cms == null )
+ {
+ m_singleComponent.dispose( reason );
+ }
+ else
+ {
+ for ( int i = 0; i < cms.length; i++ )
+ {
+ cms[i].dispose( reason );
+ }
+ }
+ }
+
+
+ //---------- internal
+
+ private ImmediateComponentManager getComponentManager( String pid )
+ {
+ synchronized ( m_components )
+ {
+ return ( ImmediateComponentManager ) m_components.get( pid );
+ }
+ }
+
+
+ private ImmediateComponentManager removeComponentManager( String pid )
+ {
+ synchronized ( m_components )
+ {
+ return ( ImmediateComponentManager ) m_components.remove( pid );
+ }
+ }
+
+
+ private void putComponentManager( String pid, ImmediateComponentManager componentManager )
+ {
+ synchronized ( m_components )
+ {
+ m_components.put( pid, componentManager );
+ }
+ }
+
+
+ /**
+ * Returns all components from the map, optionally also removing them
+ * from the map. If there are no components in the map, <code>null</code>
+ * is returned.
+ */
+ private ImmediateComponentManager[] getComponentManagers( final boolean clear )
+ {
+ synchronized ( m_components )
+ {
+ // fast exit if there is no component in the map
+ if ( m_components.isEmpty() )
+ {
+ return null;
+ }
+
+ final ImmediateComponentManager[] cm = new ImmediateComponentManager[m_components.size()];
+ m_components.values().toArray( cm );
+
+ if ( clear )
+ {
+ m_components.clear();
+ }
+
+ return cm;
+ }
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/config/UnconfiguredComponentHolder.java b/scr/src/main/java/org/apache/felix/scr/impl/config/UnconfiguredComponentHolder.java
new file mode 100644
index 0000000..b20209f
--- /dev/null
+++ b/scr/src/main/java/org/apache/felix/scr/impl/config/UnconfiguredComponentHolder.java
@@ -0,0 +1,74 @@
+/*
+ * 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.impl.config;
+
+
+import java.util.Dictionary;
+
+import org.apache.felix.scr.impl.BundleComponentActivator;
+import org.apache.felix.scr.impl.manager.ImmediateComponentManager;
+import org.apache.felix.scr.impl.metadata.ComponentMetadata;
+
+
+/**
+ * The <code>SingletonHolder</code> class is {@link ComponentHolder} for a
+ * component configured by a singleton configuration or no configuration
+ * at all.
+ */
+public class UnconfiguredComponentHolder extends AbstractComponentHolder
+{
+
+ private final ImmediateComponentManager m_component;
+
+
+ public UnconfiguredComponentHolder( BundleComponentActivator activator, ComponentMetadata metadata )
+ {
+ super( activator, metadata );
+
+ m_component = createComponentManager();
+ }
+
+
+ public void configurationDeleted( String pid )
+ {
+ }
+
+
+ public void configurationUpdated( String pid, Dictionary props )
+ {
+ }
+
+
+ public void enableComponents()
+ {
+ m_component.enable();
+ }
+
+
+ public void disableComponents()
+ {
+ m_component.disable();
+ }
+
+
+ public void disposeComponents( int reason )
+ {
+ m_component.dispose( reason );
+ }
+}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
index 5ade813..2804f2b 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/AbstractComponentManager.java
@@ -29,7 +29,6 @@
import org.apache.felix.scr.Reference;
import org.apache.felix.scr.impl.BundleComponentActivator;
import org.apache.felix.scr.impl.ComponentActivatorTask;
-import org.apache.felix.scr.impl.ComponentRegistry;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.apache.felix.scr.impl.metadata.ReferenceMetadata;
import org.osgi.framework.Bundle;
@@ -273,6 +272,16 @@
acm.log( LogService.LOG_DEBUG, "Activating component", componentMetadata, null );
// Before creating the implementation object, we are going to
+ // test if we have configuration if such is required
+ if ( !acm.hasConfiguration() && acm.getComponentMetadata().isConfigurationRequired() )
+ {
+ acm.log( LogService.LOG_INFO, "Missing required configuration, cannot activate", componentMetadata,
+ null );
+ acm.changeState( Unsatisfied.getInstance() );
+ return;
+ }
+
+ // Before creating the implementation object, we are going to
// test if all the mandatory dependencies are satisfied
if ( !acm.verifyDependencyManagers( acm.getProperties()) )
{
@@ -458,14 +467,14 @@
*
* @param activator
* @param metadata
- * @param componentId
*/
- protected AbstractComponentManager( BundleComponentActivator activator, ComponentMetadata metadata,
- ComponentRegistry componentRegistry )
+ protected AbstractComponentManager( BundleComponentActivator activator, ComponentMetadata metadata )
{
m_activator = activator;
m_componentMetadata = metadata;
- m_componentId = componentRegistry.createComponentId();
+
+ // for some testing, the activator may be null
+ m_componentId = ( activator != null ) ? activator.registerComponentId( this ) : -1;
m_state = Disabled.getInstance();
loadDependencyManagers( metadata );
@@ -753,12 +762,20 @@
return m_serviceRegistration;
}
+
void clear()
{
- m_activator = null;
+ // for some testing, the activator may be null
+ if ( m_activator != null )
+ {
+ m_activator.unregisterComponentId( this );
+ m_activator = null;
+ }
+
m_dependencyManagers.clear();
}
+
void log( int level, String message, ComponentMetadata metadata, Throwable ex )
{
BundleComponentActivator activator = getActivator();
@@ -785,17 +802,6 @@
}
/**
- * Reconfigures this component by deactivating and activating it. During
- * activation the new configuration data is retrieved from the Configuration
- * Admin Service.
- */
- public final void reconfigure( final int reason )
- {
- log( LogService.LOG_DEBUG, "Deactivating and Activating to reconfigure", m_componentMetadata, null );
- reactivate( reason );
- }
-
- /**
* Cycles this component by deactivating it and - if still satisfied -
* activating it again asynchronously.
* <p>
@@ -851,7 +857,7 @@
}
}
- private boolean verifyDependencyManagers( Dictionary properties )
+ protected boolean verifyDependencyManagers( Dictionary properties )
{
// indicates whether all dependencies are satisfied
boolean satisfied = true;
@@ -914,6 +920,8 @@
*/
public abstract Object getInstance();
+ public abstract boolean hasConfiguration();
+
public abstract Dictionary getProperties();
/**
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentContextImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentContextImpl.java
index 4806cb8..06dd92c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentContextImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentContextImpl.java
@@ -50,7 +50,7 @@
return m_componentManager;
}
- public Dictionary getProperties()
+ public final Dictionary getProperties()
{
// 112.11.3.5 The Dictionary is read-only and cannot be modified
return new ReadOnlyDictionary( m_componentManager.getProperties() );
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
index f2ac918..bc5966c 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ComponentFactoryImpl.java
@@ -25,11 +25,10 @@
import java.util.Map;
import org.apache.felix.scr.impl.BundleComponentActivator;
-import org.apache.felix.scr.impl.ComponentRegistry;
+import org.apache.felix.scr.impl.config.ComponentHolder;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.cm.Configuration;
import org.osgi.service.component.ComponentConstants;
import org.osgi.service.component.ComponentFactory;
import org.osgi.service.component.ComponentInstance;
@@ -38,12 +37,9 @@
/**
* The <code>ComponentFactoryImpl</code> TODO
*/
-public class ComponentFactoryImpl extends AbstractComponentManager implements ComponentFactory
+public class ComponentFactoryImpl extends AbstractComponentManager implements ComponentFactory, ComponentHolder
{
- // The component registry used to retrieve component IDs
- private ComponentRegistry m_componentRegistry;
-
// The map of components created from Configuration objects
// maps PID to ImmediateComponentManager for configuration updating
// this map is lazily created
@@ -53,13 +49,20 @@
// no IdentityHashSet and HashSet internally uses a HashMap anyway
private final Map m_createdComponents;
+ // configuration of the component factory
+ private Dictionary m_configuration;
- public ComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata,
- ComponentRegistry componentRegistry )
+ // whether this instance supports creating component instances for factory
+ // configuration instances. This is backwards compatibility behaviour and
+ // contradicts the specification (Section 112.7)
+ private final boolean m_isConfigurationFactory;
+
+
+ public ComponentFactoryImpl( BundleComponentActivator activator, ComponentMetadata metadata )
{
- super( activator, metadata, componentRegistry );
- m_componentRegistry = componentRegistry;
+ super( activator, metadata );
m_createdComponents = new IdentityHashMap();
+ m_isConfigurationFactory = "true".equals( activator.getBundleContext().getProperty( "ds.factory.enabled" ) );
}
@@ -94,16 +97,6 @@
{
log( LogService.LOG_DEBUG, "registering component factory", getComponentMetadata(), null );
- Configuration[] cfg = m_componentRegistry.getConfigurations( getActivator().getBundleContext(),
- getComponentMetadata().getName() );
- if ( cfg != null )
- {
- for ( int i = 0; i < cfg.length; i++ )
- {
- updated( cfg[i].getPid(), cfg[i].getProperties() );
- }
- }
-
Dictionary serviceProperties = getProperties();
return getActivator().getBundleContext().registerService( new String[]
{ ComponentFactory.class.getName() }, getService(), serviceProperties );
@@ -117,6 +110,12 @@
}
+ public boolean hasConfiguration()
+ {
+ return true;
+ }
+
+
public Dictionary getProperties()
{
Dictionary props = new Hashtable();
@@ -143,63 +142,129 @@
}
- //---------- ManagedServiceFactory interface ------------------------------
-
- public void updated( String pid, Dictionary configuration )
- {
- if ( getState() == STATE_FACTORY )
- {
- ImmediateComponentManager cm;
- if ( m_configuredServices != null )
- {
- cm = ( ImmediateComponentManager ) 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, false );
-
- // keep a reference for future updates
- m_configuredServices.put( pid, cm );
- }
- else
- {
- // update the configuration as if called as ManagedService
- cm.reconfigure( configuration );
- }
- }
- }
-
- public void deleted( String pid )
- {
- if ( getState() == STATE_FACTORY && m_configuredServices != null )
- {
- ImmediateComponentManager cm = ( ImmediateComponentManager ) m_configuredServices.remove( pid );
- if ( cm != null )
- {
- log( LogService.LOG_DEBUG, "Disposing component after configuration deletion", getComponentMetadata(),
- null );
-
- disposeComponentManager( cm, ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED );
- }
- }
-
- }
-
-
public String getName()
{
return "Component Factory " + getComponentMetadata().getName();
}
- //---------- internal -----------------------------------------------------
+ //---------- ComponentHolder interface
+
+ public void configurationDeleted( String pid )
+ {
+ if ( pid.equals( getComponentMetadata().getName() ) )
+ {
+ m_configuration = null;
+ reconfigureComponents( null );
+ }
+ else if ( m_isConfigurationFactory && getState() == STATE_FACTORY && m_configuredServices != null )
+ {
+ ImmediateComponentManager cm = ( ImmediateComponentManager ) m_configuredServices.remove( pid );
+ if ( cm != null )
+ {
+ log( LogService.LOG_DEBUG, "Disposing component after configuration deletion", getComponentMetadata(),
+ null );
+
+ disposeComponentManager( cm, ComponentConstants.DEACTIVATION_REASON_CONFIGURATION_DELETED );
+ }
+ }
+ }
+
+
+ public void configurationUpdated( String pid, Dictionary configuration )
+ {
+ if ( pid.equals( getComponentMetadata().getName() ) )
+ {
+ m_configuration = configuration;
+ reconfigureComponents( configuration );
+ }
+ else if ( m_isConfigurationFactory )
+ {
+ if ( getState() == STATE_FACTORY )
+ {
+ // configuration for factory configuration instances
+
+ ImmediateComponentManager cm;
+ if ( m_configuredServices != null )
+ {
+ cm = ( ImmediateComponentManager ) 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, false );
+
+ // keep a reference for future updates
+ m_configuredServices.put( pid, cm );
+ }
+ else
+ {
+ // update the configuration as if called as ManagedService
+ cm.reconfigure( configuration );
+ }
+ }
+ }
+ else
+ {
+ // 112.7 Factory Configuration not allowed for factory component
+ getActivator().log( LogService.LOG_ERROR,
+ "Component Factory cannot be configured by factory configuration", getComponentMetadata(), null );
+ }
+ }
+
+
+ // TODO: correct ???
+ public void enableComponents()
+ {
+ ImmediateComponentManager[] cms = getComponentManagers( false );
+ for ( int i = 0; i < cms.length; i++ )
+ {
+ cms[i].enable();
+ }
+ }
+
+
+ // update components with this configuration
+ private void reconfigureComponents( Dictionary configuration )
+ {
+ ImmediateComponentManager[] cms = getComponentManagers( false );
+ for ( int i = 0; i < cms.length; i++ )
+ {
+ cms[i].reconfigure( configuration );
+ }
+ }
+
+
+ // TODO: correct ???
+ public void disableComponents()
+ {
+ ImmediateComponentManager[] cms = getComponentManagers( false );
+ for ( int i = 0; i < cms.length; i++ )
+ {
+ cms[i].disable();
+ }
+ }
+
+
+ // TODO: correct ???
+ public void disposeComponents( int reason )
+ {
+ ImmediateComponentManager[] cms = getComponentManagers( true );
+ for ( int i = 0; i < cms.length; i++ )
+ {
+ cms[i].dispose( reason );
+ }
+ }
+
+
+ //---------- internal
+
/**
* ComponentManager instances created by this method are not registered
* with the ComponentRegistry. Therefore, any configuration update to these
@@ -218,11 +283,7 @@
*/
private ImmediateComponentManager createComponentManager( Dictionary configuration, boolean isNewInstance )
{
- ImmediateComponentManager cm = new ImmediateComponentManager( getActivator(), getComponentMetadata(),
- m_componentRegistry );
-
- // add the new component to the activators instances
- getActivator().getInstanceReferences().add( cm );
+ ImmediateComponentManager cm = new ImmediateComponentManager( getActivator(), getComponentMetadata() );
// register with the internal set of created components
m_createdComponents.put( cm, cm );
@@ -231,6 +292,7 @@
if ( isNewInstance )
{
cm.setFactoryProperties( configuration );
+ cm.reconfigure( m_configuration );
// enable synchronously
cm.enableInternal();
cm.activateInternal();
@@ -252,10 +314,24 @@
// remove from created components
m_createdComponents.remove( cm );
- // remove from activators list
- getActivator().getInstanceReferences().remove( cm );
-
// finally dispose it
cm.dispose( reason );
}
+
+
+ private ImmediateComponentManager[] getComponentManagers( boolean clear )
+ {
+ synchronized ( m_createdComponents )
+ {
+ ImmediateComponentManager[] cm = new ImmediateComponentManager[m_createdComponents.size()];
+ m_createdComponents.keySet().toArray( cm );
+
+ if ( clear )
+ {
+ m_createdComponents.clear();
+ }
+
+ return cm;
+ }
+ }
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java
index b5462db..4c3f925 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/DelayedComponentManager.java
@@ -20,7 +20,6 @@
import org.apache.felix.scr.impl.BundleComponentActivator;
-import org.apache.felix.scr.impl.ComponentRegistry;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceFactory;
@@ -36,12 +35,10 @@
/**
* @param activator
* @param metadata
- * @param componentId
*/
- public DelayedComponentManager( BundleComponentActivator activator, ComponentMetadata metadata,
- ComponentRegistry componentRegistry )
+ public DelayedComponentManager( BundleComponentActivator activator, ComponentMetadata metadata )
{
- super( activator, metadata, componentRegistry );
+ super( activator, metadata );
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
index 3ea4b7a..db8b773 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/manager/ServiceFactoryComponentManager.java
@@ -22,7 +22,6 @@
import java.util.IdentityHashMap;
import org.apache.felix.scr.impl.BundleComponentActivator;
-import org.apache.felix.scr.impl.ComponentRegistry;
import org.apache.felix.scr.impl.metadata.ComponentMetadata;
import org.osgi.framework.Bundle;
import org.osgi.framework.ServiceFactory;
@@ -47,12 +46,10 @@
/**
* @param activator
* @param metadata
- * @param componentId
*/
- public ServiceFactoryComponentManager( BundleComponentActivator activator, ComponentMetadata metadata,
- ComponentRegistry componentRegistry )
+ public ServiceFactoryComponentManager( BundleComponentActivator activator, ComponentMetadata metadata )
{
- super( activator, metadata, componentRegistry );
+ super( activator, metadata );
}
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
index 9d4b11c..cb24da7 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/metadata/ComponentMetadata.java
@@ -494,6 +494,36 @@
/**
+ * Returns <code>true</code> if the configuration policy is configured to
+ * {@link #CONFIGURATION_POLICY_REQUIRE}.
+ */
+ public boolean isConfigurationRequired()
+ {
+ return CONFIGURATION_POLICY_REQUIRE.equals( m_configurationPolicy );
+ }
+
+
+ /**
+ * Returns <code>true</code> if the configuration policy is configured to
+ * {@link #CONFIGURATION_POLICY_IGNORE}.
+ */
+ public boolean isConfigurationIgnored()
+ {
+ return CONFIGURATION_POLICY_IGNORE.equals( m_configurationPolicy );
+ }
+
+
+ /**
+ * Returns <code>true</code> if the configuration policy is configured to
+ * {@link #CONFIGURATION_POLICY_OPTIONAL}.
+ */
+ public boolean isConfigurationOptional()
+ {
+ return CONFIGURATION_POLICY_OPTIONAL.equals( m_configurationPolicy );
+ }
+
+
+ /**
* Method used to verify if the semantics of this metadata are correct
*/
public void validate( Logger logger )