You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2008/06/03 09:53:30 UTC

svn commit: r662680 - in /felix/trunk/scr/src: main/java/org/apache/felix/scr/impl/ test/ test/java/ test/java/org/ test/java/org/apache/ test/java/org/apache/felix/ test/java/org/apache/felix/scr/ test/java/org/apache/felix/scr/impl/

Author: fmeschbe
Date: Tue Jun  3 00:53:29 2008
New Revision: 662680

URL: http://svn.apache.org/viewvc?rev=662680&view=rev
Log:
FELIX-593 change accepted and default values for immediate attribute
with respect to the factory attribute

Added:
    felix/trunk/scr/src/test/
    felix/trunk/scr/src/test/java/
    felix/trunk/scr/src/test/java/org/
    felix/trunk/scr/src/test/java/org/apache/
    felix/trunk/scr/src/test/java/org/apache/felix/
    felix/trunk/scr/src/test/java/org/apache/felix/scr/
    felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/
    felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java
Modified:
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/PropertyMetadata.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ReferenceMetadata.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ServiceMetadata.java

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java?rev=662680&r1=662679&r2=662680&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentFactoryImpl.java Tue Jun  3 00:53:29 2008
@@ -188,29 +188,20 @@
     private ComponentManager createComponentManager( Dictionary configuration, boolean synchronous )
     {
         long componentId = m_componentRegistry.createComponentId();
-        ComponentManager cm = ManagerFactory.createManager( getActivator(), getComponentMetadata(), componentId );
-
+        ImmediateComponentManager cm = new ImmediateComponentManager( 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 );
-        }
+        // inject configuration
+        cm.setFactoryProperties( configuration );
 
         // enable synchronously or asynchronously depending on the flag
-        if ( cm instanceof AbstractComponentManager )
-        {
-            ( ( AbstractComponentManager ) cm ).enable( synchronous );
-        }
-        else
-        {
-            cm.enable();
-        }
+        cm.enable( synchronous );
 
         return cm;
     }

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java?rev=662680&r1=662679&r2=662680&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ComponentMetadata.java Tue Jun  3 00:53:29 2008
@@ -201,9 +201,9 @@
      * This method may only be trusted after this instance has been validated
      * by the {@link #validate()} call. Else it will either return the value
      * of an explicitly set "immediate" attribute or return false if a service
-     * element is set or true otherwise. This latter default value deduction
-     * may be unsafe while the descriptor has not been completely read.
-     * 
+     * element or the factory attribute is set or true otherwise. This latter
+     * default value deduction may be unsafe while the descriptor has not been
+     * completely read.
      * 
      * @return a boolean that defines the activation policy
      */
@@ -213,8 +213,8 @@
             return m_immediate.booleanValue();
         }
 
-        // deduce default value from service element presence
-        return m_service == null;
+        // deduce default from service element and factory attribute presence 
+        return m_service == null && m_factory == null;
     }
     
     /**
@@ -265,60 +265,90 @@
     /**
      * Method used to verify if the semantics of this metadata are correct
      */
-    void validate() {
-    	
-        // First check if the properties are valid (and extract property values)
+    void validate()
+    {
+
+        // 112.10 The name of the component is required
+        if ( m_name == null )
+        {
+            throw new ComponentException( "The component name has not been set" );
+        }
+
+        // 112.10 There must be one implementation element and the class atribute is required
+        if ( m_implementationClassName == null )
+        {
+            throw validationFailure( "Implementation class name missing" );
+        }
+
+        // Next check if the properties are valid (and extract property values)
         Iterator propertyIterator = m_propertyMetaData.iterator();
-    	while ( propertyIterator.hasNext() ) {
-    	    PropertyMetadata propMeta = (PropertyMetadata) propertyIterator.next();
-            propMeta.validate();
-            m_properties.put(propMeta.getName(), propMeta.getValue());
-        }
-    	m_propertyMetaData.clear();
-    	
-    	// Check that the provided services are valid too
-    	if(m_service != null) {
-    		m_service.validate();
-    	}
-    	
-    	// Check that the references are ok
-    	Iterator referenceIterator = m_references.iterator();
-    	while ( referenceIterator.hasNext() ) {
-    		((ReferenceMetadata)referenceIterator.next()).validate();
-    	}
-    	    	
-    	// 112.10 The name of the component is required
-    	if( m_name == null ) {
-    		throw new ComponentException("The component name has not been set");
-    	}
-    	
-    	// 112.10 There must be one implementation element and the class atribute is required
-    	if ( m_implementationClassName == null ) {
-    		throw new ComponentException("The implementation class name has not been set for this component");
-    	}
-    	
-    	// 112.2.3 A delayed component specifies a service, is not specified to be a factory component
-    	// and does not have the immediate attribute of the component element set to true.
-    	if ( m_immediate != null && isImmediate() == false && m_service == null ) {
-            throw new ComponentException( "Component '" + m_name
-                + "' is specified as being delayed but does not provide any service." );
-        }    	
-    	
-    	if ( m_factory != null && isImmediate() == false) {
-    		throw new ComponentException("A factory cannot be a delayed component");
-    	}
-    	
-    	// 112.4.6 The serviceFactory attribute (of a provided service) must not be true if 
-    	// the component is a factory component or an immediate component
-    	if ( m_service != null ) {
-            if ( m_service.isServiceFactory() && ( isFactory() || isImmediate() ) ) {
-                throw new ComponentException( "A ServiceFactory service cannot be a factory or immediate component" );
+        while ( propertyIterator.hasNext() )
+        {
+            PropertyMetadata propMeta = ( PropertyMetadata ) propertyIterator.next();
+            propMeta.validate( this );
+            m_properties.put( propMeta.getName(), propMeta.getValue() );
+        }
+        m_propertyMetaData.clear();
+
+        // Check that the provided services are valid too
+        if ( m_service != null )
+        {
+            m_service.validate( this );
+        }
+
+        // Check that the references are ok
+        Iterator referenceIterator = m_references.iterator();
+        while ( referenceIterator.hasNext() )
+        {
+            ( ( ReferenceMetadata ) referenceIterator.next() ).validate( this );
+        }
+
+        // verify value of immediate attribute if set
+        if ( m_immediate != null )
+        {
+            if ( isImmediate() )
+            {
+                // FELIX-593: 112.4.3 clarification, immediate is false for factory
+                if ( isFactory() )
+                {
+                    throw validationFailure( "Factory cannot be immediate" );
+                }
+            }
+            else
+            {
+                // 112.2.3 A delayed component specifies a service, is not specified to be a factory component
+                // and does not have the immediate attribute of the component element set to true.
+                // FELIX-593: 112.4.3 clarification, immediate may be true for factory
+                if ( m_service == null && !isFactory() )
+                {
+                    throw validationFailure( "Delayed must provide a service or be a factory" );
+                }
+            }
+        }
+
+        // 112.4.6 The serviceFactory attribute (of a provided service) must not be true if 
+        // the component is a factory component or an immediate component
+        if ( m_service != null )
+        {
+            if ( m_service.isServiceFactory() && ( isFactory() || isImmediate() ) )
+            {
+                throw validationFailure( "ServiceFactory cannot be factory or immediate" );
             }
         }
 
-    	
-    	m_validated = true;
-    	// TODO: put a similar flag on the references and the services
+        m_validated = true;
+        // TODO: put a similar flag on the references and the services
     }
 
+
+    /**
+     * Returns a <code>ComponentException</code> for this compeonent with the
+     * given explanation for failure.
+     * 
+     * @param reason The explanation for failing to validate this component.
+     */
+    ComponentException validationFailure( String reason )
+    {
+        return new ComponentException( "Component " + getName() + " validation failed: " + reason );
+    }
 }

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/PropertyMetadata.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/PropertyMetadata.java?rev=662680&r1=662679&r2=662680&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/PropertyMetadata.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/PropertyMetadata.java Tue Jun  3 00:53:29 2008
@@ -195,11 +195,12 @@
     /**
      * Method used to verify if the semantics of this metadata are correct
      */
-    public void validate(){
-    	if(m_name == null)
-    	{
-    		throw new ComponentException("Property name attribute is mandatory");
-    	}
+    public void validate( ComponentMetadata componentMetadata )
+    {
+        if ( m_name == null )
+        {
+            throw componentMetadata.validationFailure( "Property name attribute is mandatory" );
+        }
     }
     
     private Object toType(String value) {

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ReferenceMetadata.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ReferenceMetadata.java?rev=662680&r1=662679&r2=662680&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ReferenceMetadata.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ReferenceMetadata.java Tue Jun  3 00:53:29 2008
@@ -330,16 +330,16 @@
      *  Method used to verify if the semantics of this metadata are correct
      *
      */
-    void validate()
+    void validate( ComponentMetadata componentMetadata )
     {
         if ( m_name == null )
         {
-            throw new ComponentException( "the name for the reference must be set" );
+            throw componentMetadata.validationFailure( "A name must be declared for the reference" );
         }
 
         if ( m_interface == null )
         {
-            throw new ComponentException( "the interface for the reference must be set" );
+            throw componentMetadata.validationFailure( "An interface must be declared for the reference" );
         }
     }
 

Modified: felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ServiceMetadata.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ServiceMetadata.java?rev=662680&r1=662679&r2=662680&view=diff
==============================================================================
--- felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ServiceMetadata.java (original)
+++ felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/ServiceMetadata.java Tue Jun  3 00:53:29 2008
@@ -1,103 +1,106 @@
-/* 
- * 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;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-import org.osgi.service.component.ComponentException;
-
-/**
- * This class contains the metadata associated to a service that is provided
- * by a component
- *
- */
-public class ServiceMetadata {
-	
-	// 112.4.6 Flag that indicates if the service is a ServiceFactory 
-	private boolean m_serviceFactory = false;
-	
-	// List of provided interfaces
-	private List m_provides = new ArrayList();
-	
-	// Flag that indicates if this metadata has been validated and has become immutable
-	private boolean m_validated = false;
-	
-	/**
-	 * Setter for the servicefactory attribute of the service element
-	 * 
-	 * @param serviceFactory
-	 */
-	public void setServiceFactory(boolean serviceFactory) {
-		if(m_validated) {
-			return;
-		}			
-		
-		m_serviceFactory = serviceFactory;
-	}
-	
-	/**
-	 * Add a provided interface to this service
-	 * 
-	 * @param provide a String containing the name of the provided interface
-	 */
-	public void addProvide(String provide) {
-		if(m_validated) {
-			return;
-		}			
-
-		m_provides.add(provide);
-	}
-	
-	/**
-	 * Return the flag that defines if it is a service factory or not
-	 * 
-	 * @return a boolean flag
-	 */
-	public boolean isServiceFactory() {
-		return m_serviceFactory; 
-	}
-	
-	/**
-     * Returns the implemented interfaces
-     *
-     * @return the implemented interfaces as a string array
-     */
-    public String [] getProvides() {
-        String provides[] = new String[m_provides.size()];
-        Iterator it = m_provides.iterator();
-        int count = 0;
-        while (it.hasNext())
-        {
-            provides[count++] = it.next().toString();
-        }
-        return provides;
-    }
-    
-    /**
-     * Verify if the semantics of this metadata are correct
-     *
-     */
-    void validate() {
-    	if(m_provides.size() == 0) {
-    		throw new ComponentException("At least one provided interface must be given");
-    	}
-    }
-}
+/* 
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.osgi.service.component.ComponentException;
+
+/**
+ * This class contains the metadata associated to a service that is provided
+ * by a component
+ *
+ */
+public class ServiceMetadata {
+	
+	// 112.4.6 Flag that indicates if the service is a ServiceFactory 
+	private boolean m_serviceFactory = false;
+	
+	// List of provided interfaces
+	private List m_provides = new ArrayList();
+	
+	// Flag that indicates if this metadata has been validated and has become immutable
+	private boolean m_validated = false;
+	
+	/**
+	 * Setter for the servicefactory attribute of the service element
+	 * 
+	 * @param serviceFactory
+	 */
+	public void setServiceFactory(boolean serviceFactory) {
+		if(m_validated) {
+			return;
+		}			
+		
+		m_serviceFactory = serviceFactory;
+	}
+	
+	/**
+	 * Add a provided interface to this service
+	 * 
+	 * @param provide a String containing the name of the provided interface
+	 */
+	public void addProvide(String provide) {
+		if(m_validated) {
+			return;
+		}			
+
+		m_provides.add(provide);
+	}
+	
+	/**
+	 * Return the flag that defines if it is a service factory or not
+	 * 
+	 * @return a boolean flag
+	 */
+	public boolean isServiceFactory() {
+		return m_serviceFactory; 
+	}
+	
+	/**
+     * Returns the implemented interfaces
+     *
+     * @return the implemented interfaces as a string array
+     */
+    public String [] getProvides() {
+        String provides[] = new String[m_provides.size()];
+        Iterator it = m_provides.iterator();
+        int count = 0;
+        while (it.hasNext())
+        {
+            provides[count++] = it.next().toString();
+        }
+        return provides;
+    }
+    
+    /**
+     * Verify if the semantics of this metadata are correct
+     *
+     */
+    void validate( ComponentMetadata componentMetadata )
+    {
+        if ( m_provides.size() == 0 )
+        {
+            throw componentMetadata
+                .validationFailure( "At least one provided interface must be declared in the service element" );
+        }
+    }
+}

Added: felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java?rev=662680&view=auto
==============================================================================
--- felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java (added)
+++ felix/trunk/scr/src/test/java/org/apache/felix/scr/impl/ComponentMetadataTest.java Tue Jun  3 00:53:29 2008
@@ -0,0 +1,270 @@
+/*
+ * 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;
+
+
+import junit.framework.TestCase;
+
+import org.osgi.service.component.ComponentException;
+
+
+public class ComponentMetadataTest extends TestCase
+{
+
+    // test various combinations of component metadata with respect to
+    //  -- immediate: true, false, unset
+    //  -- factory: set, unset
+    //  -- service: set, unset
+    //  -- servicefactory: true, false, unset
+
+    public void testImmediate()
+    {
+        // immediate is default true if no service element is defined
+        final ComponentMetadata cm0 = createComponentMetadata( null, null );
+        cm0.validate();
+        assertTrue( "Component without service must be immediate", cm0.isImmediate() );
+
+        // immediate is explicit true
+        final ComponentMetadata cm1 = createComponentMetadata( Boolean.TRUE, null );
+        cm1.validate();
+        assertTrue( "Component must be immediate", cm1.isImmediate() );
+
+        // immediate is explicit true
+        final ComponentMetadata cm2 = createComponentMetadata( Boolean.TRUE, null );
+        cm2.setService( createServiceMetadata( null ) );
+        cm2.validate();
+        assertTrue( "Component must be immediate", cm2.isImmediate() );
+
+        // immediate is explicit true
+        final ComponentMetadata cm3 = createComponentMetadata( Boolean.TRUE, null );
+        cm3.setService( createServiceMetadata( Boolean.FALSE ) );
+        cm3.validate();
+        assertTrue( "Component must be immediate", cm3.isImmediate() );
+
+        // validation failure of immediate with service factory
+        final ComponentMetadata cm4 = createComponentMetadata( Boolean.TRUE, null );
+        cm4.setService( createServiceMetadata( Boolean.TRUE ) );
+        try
+        {
+            cm4.validate();
+            fail( "Expect validation failure for immediate service factory" );
+        }
+        catch ( ComponentException ce )
+        {
+            // expect
+        }
+    }
+
+
+    public void testDelayed()
+    {
+        // immediate is default false if service element is defined
+        final ComponentMetadata cm0 = createComponentMetadata( null, null );
+        cm0.setService( createServiceMetadata( null ) );
+        cm0.validate();
+        assertFalse( "Component with service must be delayed", cm0.isImmediate() );
+
+        // immediate is default false if service element is defined
+        final ComponentMetadata cm1 = createComponentMetadata( null, null );
+        cm1.setService( createServiceMetadata( Boolean.TRUE ) );
+        cm1.validate();
+        assertFalse( "Component with service must be delayed", cm1.isImmediate() );
+
+        // immediate is default false if service element is defined
+        final ComponentMetadata cm2 = createComponentMetadata( null, null );
+        cm2.setService( createServiceMetadata( Boolean.FALSE ) );
+        cm2.validate();
+        assertFalse( "Component with service must be delayed", cm2.isImmediate() );
+
+        // immediate is false if service element is defined
+        final ComponentMetadata cm3 = createComponentMetadata( Boolean.FALSE, null );
+        cm3.setService( createServiceMetadata( null ) );
+        cm3.validate();
+        assertFalse( "Component with service must be delayed", cm3.isImmediate() );
+
+        // immediate is false if service element is defined
+        final ComponentMetadata cm4 = createComponentMetadata( Boolean.FALSE, null );
+        cm4.setService( createServiceMetadata( Boolean.TRUE ) );
+        cm4.validate();
+        assertFalse( "Component with service must be delayed", cm4.isImmediate() );
+
+        // immediate is false if service element is defined
+        final ComponentMetadata cm5 = createComponentMetadata( Boolean.FALSE, null );
+        cm5.setService( createServiceMetadata( Boolean.FALSE ) );
+        cm5.validate();
+        assertFalse( "Component with service must be delayed", cm5.isImmediate() );
+
+        // explicit delayed fails when there is no service
+        final ComponentMetadata cm6 = createComponentMetadata( Boolean.FALSE, null );
+        try
+        {
+            cm6.validate();
+            fail( "Expect validation failure for delayed component without service" );
+        }
+        catch ( ComponentException ce )
+        {
+            // expect
+        }
+    }
+
+
+    public void testFactory()
+    {
+        // immediate is default false if factory is defined
+        final ComponentMetadata cm0 = createComponentMetadata( null, "factory" );
+        cm0.validate();
+        assertFalse( "Component with factory must be delayed", cm0.isImmediate() );
+
+        // immediate is false if factory is defined
+        final ComponentMetadata cm1 = createComponentMetadata( Boolean.FALSE, "factory" );
+        cm1.validate();
+        assertFalse( "Component with factory must be delayed", cm1.isImmediate() );
+
+        // immediate is default false if factory is defined
+        final ComponentMetadata cm2 = createComponentMetadata( Boolean.TRUE, "factory" );
+        try
+        {
+            cm2.validate();
+            fail( "Expect validation failure for immediate factory component" );
+        }
+        catch ( ComponentException ce )
+        {
+            // expect
+        }
+
+        // immediate is default false if factory is defined
+        final ComponentMetadata cm10 = createComponentMetadata( null, "factory" );
+        cm10.setService( createServiceMetadata( null ) );
+        cm10.validate();
+        assertFalse( "Component with factory must be delayed", cm10.isImmediate() );
+
+        // immediate is false if factory is defined
+        final ComponentMetadata cm11 = createComponentMetadata( Boolean.FALSE, "factory" );
+        cm11.setService( createServiceMetadata( null ) );
+        cm11.validate();
+        assertFalse( "Component with factory must be delayed", cm11.isImmediate() );
+
+        // immediate is default false if factory is defined
+        final ComponentMetadata cm12 = createComponentMetadata( Boolean.TRUE, "factory" );
+        cm12.setService( createServiceMetadata( null ) );
+        try
+        {
+            cm12.validate();
+            fail( "Expect validation failure for immediate factory component" );
+        }
+        catch ( ComponentException ce )
+        {
+            // expect
+        }
+
+        // immediate is default false if factory is defined
+        final ComponentMetadata cm20 = createComponentMetadata( null, "factory" );
+        cm20.setService( createServiceMetadata( Boolean.FALSE ) );
+        cm20.validate();
+        assertFalse( "Component with factory must be delayed", cm20.isImmediate() );
+
+        // immediate is false if factory is defined
+        final ComponentMetadata cm21 = createComponentMetadata( Boolean.FALSE, "factory" );
+        cm21.setService( createServiceMetadata( Boolean.FALSE ) );
+        cm21.validate();
+        assertFalse( "Component with factory must be delayed", cm21.isImmediate() );
+
+        // immediate is default false if factory is defined
+        final ComponentMetadata cm22 = createComponentMetadata( Boolean.TRUE, "factory" );
+        cm22.setService( createServiceMetadata( Boolean.FALSE ) );
+        try
+        {
+            cm22.validate();
+            fail( "Expect validation failure for immediate factory component" );
+        }
+        catch ( ComponentException ce )
+        {
+            // expect
+        }
+
+        // immediate is default false if factory is defined
+        final ComponentMetadata cm30 = createComponentMetadata( null, "factory" );
+        cm30.setService( createServiceMetadata( Boolean.TRUE ) );
+        try
+        {
+            cm30.validate();
+            fail( "Expect validation failure for factory component with service factory" );
+        }
+        catch ( ComponentException ce )
+        {
+            // expect
+        }
+
+        // immediate is false if factory is defined
+        final ComponentMetadata cm31 = createComponentMetadata( Boolean.FALSE, "factory" );
+        cm31.setService( createServiceMetadata( Boolean.TRUE ) );
+        try
+        {
+            cm31.validate();
+            fail( "Expect validation failure for factory component with service factory" );
+        }
+        catch ( ComponentException ce )
+        {
+            // expect
+        }
+
+        // immediate is default false if factory is defined
+        final ComponentMetadata cm32 = createComponentMetadata( Boolean.TRUE, "factory" );
+        cm32.setService( createServiceMetadata( Boolean.TRUE ) );
+        try
+        {
+            cm32.validate();
+            fail( "Expect validation failure for immediate factory component with service factory" );
+        }
+        catch ( ComponentException ce )
+        {
+            // expect
+        }
+
+    }
+
+
+    private ComponentMetadata createComponentMetadata( Boolean immediate, String factory )
+    {
+        ComponentMetadata meta = new ComponentMetadata();
+        meta.setName( "place.holder" );
+        meta.setImplementationClassName( "place.holder.implementation" );
+        if ( immediate != null )
+        {
+            meta.setImmediate( immediate.booleanValue() );
+        }
+        if ( factory != null )
+        {
+            meta.setFactoryIdentifier( factory );
+        }
+        return meta;
+    }
+
+
+    private ServiceMetadata createServiceMetadata( Boolean serviceFactory )
+    {
+        ServiceMetadata meta = new ServiceMetadata();
+        meta.addProvide( "place.holder.service" );
+        if ( serviceFactory != null )
+        {
+            meta.setServiceFactory( serviceFactory.booleanValue() );
+        }
+        return meta;
+    }
+}