* Fix issue Felix-803:
  The core xml schema accepted the 'interface' attribute in service dependencies. This attribute were replaced by 'specification' to be consistent with other service dependencies.
  The 'interface' attribute is now prohibited.

* Fix issue Felix-805:
  Instances were not created when the targeted factory becomes valid later.

* Add a mechanism to avoid that setter methods are called twice if two threads try to invoke the callback with the same value.


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@711559 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
index 2f25cde..988b1f0 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/InstanceCreator.java
@@ -72,22 +72,26 @@
      * @param bundle the bundle id declaring the instance
      */
     synchronized void addInstance(Dictionary instance, long bundle) {
+        m_logger.log(Logger.DEBUG, "New instance to managed, looking for " + instance.get("component"));
         ManagedInstance managed = new ManagedInstance(instance, bundle);
         for (int i = 0; i < m_factories.size(); i++) {
             IPojoFactory factory = (IPojoFactory) m_factories.get(i);
-            if (factory.getState() == Factory.VALID && managed.match(factory)) {
-                managed.create(factory);
-                List list = (List) m_attached.get(factory);
-                if (list == null) {
-                    list = new ArrayList();
-                    list.add(managed);
-                    m_attached.put(factory, list);
-                    // Subscribe to the factory state change
-                    factory.addFactoryStateListener(this);
-                } else {
-                    list.add(managed);
+            if (managed.matchName(factory)) {
+                // Subscribe to the factory state change
+                m_logger.log(Logger.DEBUG, "Listen factory " + factory.getName() + " events");
+                factory.addFactoryStateListener(this);
+                if (factory.getState() == Factory.VALID && managed.match(factory)) {
+                    managed.create(factory);
+                    List list = (List) m_attached.get(factory);
+                    if (list == null) {
+                        list = new ArrayList();
+                        list.add(managed);
+                        m_attached.put(factory, list);  
+                    } else {
+                        list.add(managed);
+                    }
+                    return;
                 }
-                return;
             }
         }
         // If there is no matching factory, add the instance to the idle list
@@ -144,13 +148,14 @@
      */
     public synchronized void addFactory(IPojoFactory factory) {
         List createdInstances = new ArrayList(1);
+        m_logger.log(Logger.DEBUG, "Add the factory " + factory.getName());
         m_factories.add(factory);
         for (int i = 0; i < m_idle.size(); i++) {
             ManagedInstance managed = (ManagedInstance) m_idle.get(i);
-            if (managed.match(factory)) {
+            if (managed.matchName(factory)) {
                 // We have to subscribe to the factory.
                 factory.addFactoryStateListener(this);
-                if (factory.getState() == Factory.VALID) {
+                if (factory.getState() == Factory.VALID && managed.match(factory)) {
                     managed.create(factory);
                     List list = (List) m_attached.get(factory);
                     if (list == null) {
@@ -229,8 +234,10 @@
      */
     public void stateChanged(Factory factory, int newState) {
         if (newState == Factory.VALID) {
+            m_logger.log(Logger.DEBUG, "A factory is becoming valid : " + factory.getName());
             onValidation((IPojoFactory) factory);
         } else {
+            m_logger.log(Logger.DEBUG, "A factory is bocoming invalid : " + factory.getName());
             onInvalidation((IPojoFactory) factory);
         }
     }
@@ -286,6 +293,19 @@
         ComponentInstance getInstance() {
             return m_instance;
         }
+        
+        
+        /**
+         * Checks if the required factory name match with the given factory.
+         * This methods checks only the name, and not the configuration.
+         * @param factory the factory to test
+         * @return <code>true</code> if the factory name matches, <code>false</code>
+         * otherwise.
+         */
+        public boolean matchName(IPojoFactory factory) {
+            String component = (String) m_configuration.get("component");
+            return factory.getName().equals(component) || factory.getClassName().equalsIgnoreCase(component);
+        }
 
         /**
          * Checks if the given factory match with the factory 
@@ -298,8 +318,7 @@
          */
         public boolean match(IPojoFactory factory) {
             // Test factory name (and classname)
-            String component = (String) m_configuration.get("component");
-            if (factory.getName().equals(component) || factory.getClassName().equalsIgnoreCase(component)) {
+            if (matchName(factory)) {
                 // Test factory accessibility
                 if (factory.m_isPublic || factory.getBundleContext().getBundle().getBundleId() == m_bundleId) {
                     // Test the configuration validity.
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Logger.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
index 68fed56..ea44b1e 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Logger.java
@@ -123,13 +123,17 @@
      * @param msg the message to log
      */
     private void dispatch(int level, String msg) {
-        
-        ServiceReference ref = m_context.getServiceReference(LogService.class.getName());
         LogService log = null;
-        if (ref != null) {
-            log = (LogService) m_context.getService(ref);
+        ServiceReference ref = null;
+        try {
+            ref = m_context.getServiceReference(LogService.class.getName());
+            if (ref != null) {
+                log = (LogService) m_context.getService(ref);
+            }
+        } catch (IllegalStateException e) {
+            // Handle the case where the iPOJO bundle is stopping
         }
-        
+
         String message = null;
         switch (level) {
             case DEBUG:
@@ -182,11 +186,15 @@
      * @param exception the exception attached to the message
      */
     private void dispatch(int level, String msg, Throwable exception) {
-        
-        ServiceReference ref = m_context.getServiceReference(LogService.class.getName());
         LogService log = null;
-        if (ref != null) {
-            log = (LogService) m_context.getService(ref);
+        ServiceReference ref = null;
+        try {
+            ref = m_context.getServiceReference(LogService.class.getName());
+            if (ref != null) {
+                log = (LogService) m_context.getService(ref);
+            }
+        } catch (IllegalStateException e) {
+            // Handle the case where the iPOJO bundle is stopping
         }
         
         String message = null;
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java
index 643f41a..a022d71 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/Property.java
@@ -454,11 +454,10 @@
         try {

             if (instance == null) {

                 m_method.call(new Object[] { m_value });

-                m_invoked = true;

             } else {

                 m_method.call(instance, new Object[] { m_value });

-                m_invoked = true;

             }

+            m_invoked = true;

         } catch (NoSuchMethodException e) {

             m_handler.error("The method " + m_method + " does not exist in the implementation class " + m_manager.getClassName());

             m_manager.stop();

diff --git a/ipojo/core/src/main/resources/core.xsd b/ipojo/core/src/main/resources/core.xsd
index c89b193..9cdbfcf 100644
--- a/ipojo/core/src/main/resources/core.xsd
+++ b/ipojo/core/src/main/resources/core.xsd
@@ -218,12 +218,12 @@
 				</xs:sequence>
 				
 				<xs:attribute name="interface" type="xs:string"
-				    use="optional">
+				    use="prohibited">
                     <xs:annotation>
-                    	<xs:documentation>The interface describing the required service type. This attribute is needed only when using aggregate dependencies with field injection and when the type of this field is a list, vector, collection and set. This attribute is deprecated.</xs:documentation>
+                    	<xs:documentation>The interface describing the required service type. This attribute is needed only when using aggregate dependencies with field injection and when the type of this field is a list, vector, collection and set. This attribute is deprecated, use 'specification'.</xs:documentation>
                     </xs:annotation>
 				</xs:attribute>
-
+				
 				<xs:attribute name="field" type="xs:string"
 					use="optional">
                     <xs:annotation>
diff --git a/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForServices.java b/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForServices.java
index 14f1485..867f66f 100644
--- a/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForServices.java
+++ b/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceFactoryTestForServices.java
@@ -249,7 +249,7 @@
         architecture = (Architecture) Utils.getServiceObject(context, Architecture.class.getName(), "(architecture.instance="+pid+")");
         
         assertEquals("Assert Message", "message2", mes);
-       // assertEquals("Assert count", 2, count);
+        assertEquals("Assert count", 2, count);
         assertEquals("Check 1 object", 1, architecture.getInstanceDescription().getCreatedObjects().length);
         
         try {
diff --git a/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceTestForImmediate.java b/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceTestForImmediate.java
index ab207f5..1027afc 100644
--- a/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceTestForImmediate.java
+++ b/ipojo/tests/core/configadmin/src/main/java/org/apache/felix/ipojo/test/scenarios/configadmin/ManagedServiceTestForImmediate.java
@@ -217,10 +217,11 @@
         FooService fs = (FooService) context.getService(ref);
         Properties p = fs.fooProps();
         String mes = p.getProperty("message");
-        //int count = ((Integer) p.get("count")).intValue();
+      //  int count1 = ((Integer) p.get("count")).intValue();
         assertEquals("Check 1 object", 1, instance.getInstanceDescription().getCreatedObjects().length);
         assertEquals("Check message - 1 (" + mes +")", "message2", mes); // Already reconfigured.
-       // assertEquals("Check count", 2, count); // Two : 1) "message" on immediate, "message2" on the reconfiguration
+       // assertEquals("Check count", 2, count); // Two : 1) "message" on immediate, "message2" on the reconfiguration, 
+                                                // not necessary as the property can be set before the immediate instance creation
         
         instance.dispose();
         
@@ -256,10 +257,10 @@
         fs = (FooService) context.getService(ref);
         p = fs.fooProps();
         mes = p.getProperty("message");
-        //count = ((Integer) p.get("count")).intValue();
+       // int count = ((Integer) p.get("count")).intValue();
         assertEquals("Check 1 object", 1, instance.getInstanceDescription().getCreatedObjects().length);
         assertEquals("Check message already reconfigured", "message3", mes); // Already reconfigured.
-        //assertEquals("Check count", 2, count); // message before the reconfiguration, message3 after the reconfiguration
+        //assertEquals("Check count", count1 + 1, count); // message before the reconfiguration, message3 after the reconfiguration
         
         instance.dispose();
         
diff --git a/ipojo/tests/core/external-handlers/src/main/java/org/apache/felix/ipojo/test/scenarios/eh/HandlerTest.java b/ipojo/tests/core/external-handlers/src/main/java/org/apache/felix/ipojo/test/scenarios/eh/HandlerTest.java
index b1e0a03..09066ed 100644
--- a/ipojo/tests/core/external-handlers/src/main/java/org/apache/felix/ipojo/test/scenarios/eh/HandlerTest.java
+++ b/ipojo/tests/core/external-handlers/src/main/java/org/apache/felix/ipojo/test/scenarios/eh/HandlerTest.java
@@ -21,7 +21,6 @@
 import java.util.Properties;

 

 import org.apache.felix.ipojo.ComponentInstance;

-import org.apache.felix.ipojo.HandlerFactory;

 import org.apache.felix.ipojo.HandlerManagerFactory;

 import org.apache.felix.ipojo.architecture.Architecture;

 import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;

diff --git a/ipojo/tests/core/service-dependency-bindingpolicy/src/main/resources/metadata.xml b/ipojo/tests/core/service-dependency-bindingpolicy/src/main/resources/metadata.xml
index e4c0460..33f79ce 100644
--- a/ipojo/tests/core/service-dependency-bindingpolicy/src/main/resources/metadata.xml
+++ b/ipojo/tests/core/service-dependency-bindingpolicy/src/main/resources/metadata.xml
@@ -60,7 +60,7 @@
 		classname="org.apache.felix.ipojo.test.scenarios.service.dependency.policies.MethodCheckServiceProvider"

 		name="StaticMRefCheckServiceProvider" architecture="true">

 		<requires

-			interface="org.apache.felix.ipojo.test.scenarios.service.dependency.service.FooService"

+			specification="org.apache.felix.ipojo.test.scenarios.service.dependency.service.FooService"

 			policy="static">

 			<callback type="bind" method="refBind" />

 			<callback type="unbind" method="refUnbind" />

@@ -139,7 +139,7 @@
 		name="StaticMRefOptionalCheckServiceProvider"

 		architecture="true">

 		<requires

-			interface="org.apache.felix.ipojo.test.scenarios.service.dependency.service.FooService"

+			specification="org.apache.felix.ipojo.test.scenarios.service.dependency.service.FooService"

 			optional="true" policy="static">

 			<callback type="bind" method="refBind" />

 			<callback type="unbind" method="refUnbind" />

@@ -151,7 +151,7 @@
 		name="StaticMBothOptionalCheckServiceProvider"

 		architecture="true">

 		<requires

-			interface="org.apache.felix.ipojo.test.scenarios.service.dependency.service.FooService"

+			specification="org.apache.felix.ipojo.test.scenarios.service.dependency.service.FooService"

 			optional="true" policy="static">

 			<callback type="bind" method="bothBind" />

 			<callback type="unbind" method="bothUnbind" />

@@ -220,7 +220,7 @@
 		name="StaticMRefMultipleCheckServiceProvider"

 		architecture="true">

 		<requires

-			interface="org.apache.felix.ipojo.test.scenarios.service.dependency.service.FooService"

+			specification="org.apache.felix.ipojo.test.scenarios.service.dependency.service.FooService"

 			aggregate="true" policy="static">

 			<callback type="bind" method="refBind" />

 			<callback type="unbind" method="refUnbind" />