Fix issue FELIX-1965
When a validate callback throws an exception, the service is still published (a small amount of time). This 'door' allows a consumer to use a non initialized service.
The fix avoids that and test it.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@895971 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java
index ae80448..16f8e09 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/lifecycle/callback/LifecycleCallbackHandler.java
@@ -168,7 +168,7 @@
                     throw new IllegalStateException(e.getMessage());
                 } catch (InvocationTargetException e) {
                     error("[" + getInstanceManager().getInstanceName() + "] The callback method " + m_callbacks[i].getMethod() + " has thrown an exception : " + e.getTargetException().getMessage(), e.getTargetException());
-                    getInstanceManager().setState(ComponentInstance.INVALID);
+                    throw new IllegalStateException(e.getTargetException().getMessage());
                 }
             }
         }
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
index 6152eff..78ad910 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
@@ -276,14 +276,19 @@
     }
 
     /**
-     * Return a service object for the dependency.
+     * Returns a service object for the dependency.
      * @see org.osgi.framework.ServiceFactory#getService(org.osgi.framework.Bundle, org.osgi.framework.ServiceRegistration)
      * @param bundle : the bundle
-     * @param registration : the service registration of the registred service
-     * @return : a new service object or a already created service object (in the case of singleton)
+     * @param registration : the service registration of the registered service
+     * @return a new service object or a already created service object (in the case of singleton) or <code>null</code>
+     * if the instance is no more valid.
      */
     public Object getService(Bundle bundle, ServiceRegistration registration) {
-        return m_strategy.getService(bundle, registration);
+        if (getInstanceManager().getState() == InstanceManager.VALID) {
+            return m_strategy.getService(bundle, registration);
+        } else {
+            return null;
+        }
     }
 
     /**
diff --git a/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/component/CallbackWithErrorCheckService.java b/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/component/CallbackWithErrorCheckService.java
new file mode 100644
index 0000000..a33af51
--- /dev/null
+++ b/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/component/CallbackWithErrorCheckService.java
@@ -0,0 +1,44 @@
+/* 

+ * 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.ipojo.test.scenarios.component;

+

+import java.util.Properties;

+

+import org.apache.felix.ipojo.test.scenarios.lifecycle.callback.service.CheckService;

+

+public class CallbackWithErrorCheckService extends ParentClass implements CheckService {

+

+

+    public void start() {

+        throw new NullPointerException();

+    }

+

+    public void stop() {

+    }

+

+    public boolean check() {

+        return true;

+    }

+

+    public Properties getProps() {

+        Properties p = new Properties();

+        return p;

+    }

+

+}

diff --git a/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/CallbackTestCase.java b/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/CallbackTestCase.java
index 2c1bed2..0d54e5e 100644
--- a/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/CallbackTestCase.java
+++ b/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/CallbackTestCase.java
@@ -29,87 +29,87 @@
 import org.osgi.framework.ServiceReference;

 

 public class CallbackTestCase extends OSGiTestCase {

-	

-	ComponentInstance instance; // Instance under test

-	ComponentInstance fooProvider;

+    

+    ComponentInstance instance; // Instance under test

+    ComponentInstance fooProvider;

 

-	public void setUp() {

-		Properties p2 = new Properties();

-		p2.put("instance.name","fooProvider");

-		fooProvider = Utils.getComponentInstance(getContext(), "LFCB-FooProviderType-1", p2);

-		fooProvider.stop();

-		

-		Properties p1 = new Properties();

-		p1.put("instance.name","callback");

-		instance = Utils.getComponentInstance(getContext(), "LFCB-CallbackCheckService", p1);

-		

-	}

-	

-	public void tearDown() {

-		instance.dispose();

-		fooProvider.dispose();

-		instance= null;

-		fooProvider = null;

-	}

-	

-	public void testCallback() {

-		// Check instance is invalid

-		ServiceReference arch_ref = Utils.getServiceReferenceByName(getContext(), Architecture.class.getName(), instance.getInstanceName());

-		assertNotNull("Check architecture availability", arch_ref);

-		PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();

-		assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);

-		assertEquals("Check pojo count - 1", id_dep.getCreatedObjects().length, 0);

-		

-		// Start fooprovider

-		fooProvider.start();

-		

-		// Check instance validity

-		//id_dep = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();

-		assertTrue("Check instance validity - 1", id_dep.getState() == ComponentInstance.VALID);

-		

-		// Check service providing

-		ServiceReference cs_ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), instance.getInstanceName());

-		assertNotNull("Check CheckService availability", cs_ref);

-		CheckService cs = (CheckService) getContext().getService(cs_ref);

-		assertTrue("check CheckService invocation", cs.check());

-		

-		// Check int property

-		Integer index = (Integer) (cs.getProps().get("int"));

-		assertEquals("Check int property - 1", index.intValue(), 1);

-		

-		assertEquals("Check pojo count - 2", id_dep.getCreatedObjects().length, 1);

-		

-		fooProvider.stop();

-		

-		//id_dep = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();

-		assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);

-		

-		assertEquals("Check pojo count - 3", id_dep.getCreatedObjects().length, 1);

-		

-		fooProvider.start();

-		

-		// Check instance validity

-		//id_dep = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();

-		assertTrue("Check instance validity - 2", id_dep.getState() == ComponentInstance.VALID);

-		

-		// Check service providing

-		cs_ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), instance.getInstanceName());

-		assertNotNull("Check CheckService availability", cs_ref);

-		cs = (CheckService) getContext().getService(cs_ref);

-		assertTrue("check CheckService invocation", cs.check());

-		

-		// Check int property

-		index = (Integer) (cs.getProps().get("int"));

-		assertEquals("Check int property - 2 ("+index.intValue()+")", index.intValue(), 3);

-		

-		assertEquals("Check pojo count - 4 ", id_dep.getCreatedObjects().length, 1);

-		

-		// Clean up

-		getContext().ungetService(arch_ref);

-		getContext().ungetService(cs_ref);

-		cs = null;

-		id_dep = null;

-	}

-		

+    public void setUp() {

+        Properties p2 = new Properties();

+        p2.put("instance.name","fooProvider");

+        fooProvider = Utils.getComponentInstance(getContext(), "LFCB-FooProviderType-1", p2);

+        fooProvider.stop();

+        

+        Properties p1 = new Properties();

+        p1.put("instance.name","callback");

+        instance = Utils.getComponentInstance(getContext(), "LFCB-CallbackCheckService", p1);

+        

+    }

+    

+    public void tearDown() {

+        instance.dispose();

+        fooProvider.dispose();

+        instance= null;

+        fooProvider = null;

+    }

+    

+    public void testCallback() {

+        // Check instance is invalid

+        ServiceReference arch_ref = Utils.getServiceReferenceByName(getContext(), Architecture.class.getName(), instance.getInstanceName());

+        assertNotNull("Check architecture availability", arch_ref);

+        PrimitiveInstanceDescription id_dep = (PrimitiveInstanceDescription) ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();

+        assertTrue("Check instance invalidity - 1", id_dep.getState() == ComponentInstance.INVALID);

+        assertEquals("Check pojo count - 1", id_dep.getCreatedObjects().length, 0);

+        

+        // Start fooprovider

+        fooProvider.start();

+        

+        // Check instance validity

+        //id_dep = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();

+        assertTrue("Check instance validity - 1", id_dep.getState() == ComponentInstance.VALID);

+        

+        // Check service providing

+        ServiceReference cs_ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), instance.getInstanceName());

+        assertNotNull("Check CheckService availability", cs_ref);

+        CheckService cs = (CheckService) getContext().getService(cs_ref);

+        assertTrue("check CheckService invocation", cs.check());

+        

+        // Check int property

+        Integer index = (Integer) (cs.getProps().get("int"));

+        assertEquals("Check int property - 1", index.intValue(), 1);

+        

+        assertEquals("Check pojo count - 2", id_dep.getCreatedObjects().length, 1);

+        

+        fooProvider.stop();

+        

+        //id_dep = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();

+        assertTrue("Check instance invalidity - 2", id_dep.getState() == ComponentInstance.INVALID);

+        

+        assertEquals("Check pojo count - 3", id_dep.getCreatedObjects().length, 1);

+        

+        fooProvider.start();

+        

+        // Check instance validity

+        //id_dep = ((Architecture) getContext().getService(arch_ref)).getInstanceDescription();

+        assertTrue("Check instance validity - 2", id_dep.getState() == ComponentInstance.VALID);

+        

+        // Check service providing

+        cs_ref = Utils.getServiceReferenceByName(getContext(), CheckService.class.getName(), instance.getInstanceName());

+        assertNotNull("Check CheckService availability", cs_ref);

+        cs = (CheckService) getContext().getService(cs_ref);

+        assertTrue("check CheckService invocation", cs.check());

+        

+        // Check int property

+        index = (Integer) (cs.getProps().get("int"));

+        assertEquals("Check int property - 2 ("+index.intValue()+")", index.intValue(), 3);

+        

+        assertEquals("Check pojo count - 4 ", id_dep.getCreatedObjects().length, 1);

+        

+        // Clean up

+        getContext().ungetService(arch_ref);

+        getContext().ungetService(cs_ref);

+        cs = null;

+        id_dep = null;

+    }

+        

 

 }

diff --git a/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/ErrorCallbackTestCase.java b/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/ErrorCallbackTestCase.java
new file mode 100644
index 0000000..8625527
--- /dev/null
+++ b/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/ErrorCallbackTestCase.java
@@ -0,0 +1,56 @@
+/* 

+ * 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.ipojo.test.scenarios.lifecycle.callback;

+

+import java.util.Properties;

+

+import org.apache.felix.ipojo.ComponentInstance;

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

+import org.apache.felix.ipojo.test.scenarios.lifecycle.callback.service.CheckService;

+import org.apache.felix.ipojo.test.scenarios.util.Utils;

+import org.osgi.framework.ServiceReference;

+

+/**

+ * Test the fix for FELIX-1965.

+ * When a validate callback throws an exception, the service is still provided.

+ */

+public class ErrorCallbackTestCase extends OSGiTestCase {

+    

+    ComponentInstance instance; // Instance under test

+    

+    public void tearDown() {

+        if (instance != null) {

+            instance.dispose();

+            instance= null;

+        }

+    }

+    

+    public void testErrorInValidateCallback() {

+        Properties p2 = new Properties();

+        p2.put("instance.name","error");

+        instance = Utils.getComponentInstance(getContext(), "LFCB-CallbackWithError", p2);

+        

+        // The service should not be provided as the start method has thrown an exception

+        ServiceReference ref = getServiceReference(CheckService.class.getName(), "(instance.name=" + instance.getInstanceName() +")");

+        assertNull(ref);

+        

+    }

+        

+

+}

diff --git a/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/LifeCycleCallbackTest.java b/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/LifeCycleCallbackTest.java
index ed5a6bc..feccc8a 100644
--- a/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/LifeCycleCallbackTest.java
+++ b/ipojo/tests/core/lifecycle-callback/src/main/java/org/apache/felix/ipojo/test/scenarios/lifecycle/callback/LifeCycleCallbackTest.java
@@ -25,17 +25,18 @@
 import org.osgi.framework.BundleContext;

 

 public class LifeCycleCallbackTest extends TestSuite {

-	

+    

 

-	public static Test suite(BundleContext bc) {

-		OSGiTestSuite ots = new OSGiTestSuite("Lifecycle callbacks Test Suite", bc);

-		ots.addTestSuite(CallbackTestCase.class);

-		ots.addTestSuite(ParentCallbackTestCase.class);

+    public static Test suite(BundleContext bc) {

+        OSGiTestSuite ots = new OSGiTestSuite("Lifecycle callbacks Test Suite", bc);

+        ots.addTestSuite(CallbackTestCase.class);

+        ots.addTestSuite(ParentCallbackTestCase.class);

         ots.addTestSuite(ImmediateCallbackTest.class);

         ots.addTestSuite(ImmediateCallbackSingletonFactoryTest.class);

         ots.addTestSuite(ImmediateCallbackSeveralFactoryTest.class);

-		return ots;

-	}

+        ots.addTestSuite(ErrorCallbackTestCase.class);

+        return ots;

+    }

 

 }

 

diff --git a/ipojo/tests/core/lifecycle-callback/src/main/resources/metadata.xml b/ipojo/tests/core/lifecycle-callback/src/main/resources/metadata.xml
index 47c17a2..7dd3607 100644
--- a/ipojo/tests/core/lifecycle-callback/src/main/resources/metadata.xml
+++ b/ipojo/tests/core/lifecycle-callback/src/main/resources/metadata.xml
@@ -3,54 +3,63 @@
     xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"

     xmlns="org.apache.felix.ipojo"

 >

-	<component

-		classname="org.apache.felix.ipojo.test.scenarios.component.FooProviderType1"

-		name="LFCB-FooProviderType-1" architecture="true">

-		<provides />

-	</component>

-	

-	<!-- Lifecycle Callback -->

-	<component

-		classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

-		name="LFCB-CallbackCheckService" architecture="true">

-		<requires field="fs" />

-		<provides />

-		<callback transition="validate" method="start" />

-		<callback transition="invalidate" method="stop" />

-	</component>

-	<component

-		classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

-		name="LFCB-ParentCallbackCheckService" architecture="true">

-		<requires field="fs" />

-		<provides />

-		<callback transition="validate" method="parentStart" />

-		<callback transition="invalidate" method="parentStop" />

-	</component>

-	<component

-		classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

-		immediate="true" name="LFCB-ImmediateCallbackCheckService"

-		architecture="true">

-		<requires field="fs" />

-		<provides />

-		<callback transition="validate" method="start" />

-		<callback transition="invalidate" method="stop" />

-	</component>

-	<component

-		classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

-		immediate="true" name="LFCB-ImmediateCallbackCheckServiceSingleton"

-		factory-method="singleton" architecture="true">

-		<requires field="fs" />

-		<provides />

-		<callback transition="validate" method="start" />

-		<callback transition="invalidate" method="stop" />

-	</component>

-	<component

-		classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

-		immediate="true" name="LFCB-ImmediateCallbackCheckServiceSeveral"

-		factory-method="several" architecture="true">

-		<requires field="fs" />

-		<provides />

-		<callback transition="validate" method="start" />

-		<callback transition="invalidate" method="stop" />

-	</component>

+  <component

+    classname="org.apache.felix.ipojo.test.scenarios.component.FooProviderType1"

+    name="LFCB-FooProviderType-1" architecture="true">

+    <provides />

+  </component>

+  

+  <!-- Lifecycle Callback -->

+  <component

+    classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

+    name="LFCB-CallbackCheckService" architecture="true">

+    <requires field="fs" />

+    <provides />

+    <callback transition="validate" method="start" />

+    <callback transition="invalidate" method="stop" />

+  </component>

+  <component

+    classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

+    name="LFCB-ParentCallbackCheckService" architecture="true">

+    <requires field="fs" />

+    <provides />

+    <callback transition="validate" method="parentStart" />

+    <callback transition="invalidate" method="parentStop" />

+  </component>

+  <component

+    classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

+    immediate="true" name="LFCB-ImmediateCallbackCheckService"

+    architecture="true">

+    <requires field="fs" />

+    <provides />

+    <callback transition="validate" method="start" />

+    <callback transition="invalidate" method="stop" />

+  </component>

+  <component

+    classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

+    immediate="true" name="LFCB-ImmediateCallbackCheckServiceSingleton"

+    factory-method="singleton" architecture="true">

+    <requires field="fs" />

+    <provides />

+    <callback transition="validate" method="start" />

+    <callback transition="invalidate" method="stop" />

+  </component>

+  <component

+    classname="org.apache.felix.ipojo.test.scenarios.component.CallbackCheckService"

+    immediate="true" name="LFCB-ImmediateCallbackCheckServiceSeveral"

+    factory-method="several" architecture="true">

+    <requires field="fs" />

+    <provides />

+    <callback transition="validate" method="start" />

+    <callback transition="invalidate" method="stop" />

+  </component>

+  

+  <!--  Test initialization error -->

+  <component

+    classname="org.apache.felix.ipojo.test.scenarios.component.CallbackWithErrorCheckService"

+    name="LFCB-CallbackWithError">

+    <provides />

+    <callback transition="validate" method="start" />

+    <callback transition="invalidate" method="stop" />

+  </component>

 </ipojo>