Fix FELIX-4240 and FELIX-4242:
FELIX-4240 Support the 'exception' attribute in service dependencies
FELIX-4242 Support the 'timeout' attribute in service dependencies
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1526626 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Requires.java b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Requires.java
index 864a5a7..e6dd227 100644
--- a/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Requires.java
+++ b/ipojo/manipulator/annotations/src/main/java/org/apache/felix/ipojo/annotations/Requires.java
@@ -64,6 +64,13 @@
Class defaultimplementation() default Class.class;
/**
+ * Set the exception to throw when the service is not available. This attribute can only be used for optional
+ * dependencies. It must be a subclass of {@link RuntimeException}.
+ * Default: no exception.
+ */
+ Class<? extends RuntimeException> exception() default RuntimeException.class;
+
+ /**
* Set the binding policy.
* Acceptable policy are dynamic, static and dynamic-priority.
* Default: dynamic.
@@ -93,4 +100,13 @@
* Default: true
*/
boolean proxy() default true;
+
+
+ /**
+ * Set the time to wait before applying the 'no service available' action.
+ * This attribute is only valid for optional dependencies.
+ * The time is set in milliseconds.
+ * Default: no timeout
+ */
+ int timeout() default -1;
}
diff --git a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/core.xsd b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/core.xsd
index 6f7320a..3e8f0fe 100644
--- a/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/core.xsd
+++ b/ipojo/manipulator/ipojo-ant-task/src/main/resources/META-INF/xsd/core.xsd
@@ -299,6 +299,26 @@
</xs:annotation>
</xs:attribute>
+ <xs:attribute name="exception" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the exception to throw for an optional service
+ dependency. If no providers are found, iPOJO creates an instance of the
+ exception (with either no parameter or a String parameter as constructor argument), and
+ throws it. The given class name must extends RuntimeException.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="timeout" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the timeout after which the 'no service policy' is executed
+ (nullable, null, empty collection, exception...). The value is the time in millisecond to
+ wait. -1 is used to indicate an infinite wait, 0 executes the no service policy
+ immediately.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
<xs:attribute name="from" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Specific service provider. The dependency can only be fulfilled by the
diff --git a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java
index 73ae8a0..db55218 100644
--- a/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java
+++ b/ipojo/manipulator/manipulator/src/main/java/org/apache/felix/ipojo/manipulator/metadata/annotation/visitor/RequiresVisitor.java
@@ -72,6 +72,11 @@
private String m_defaultImplementation;
/**
+ * Exception attribute.
+ */
+ private String m_exception;
+
+ /**
* Enable or Disable Nullable pattern.
*/
private String m_nullable;
@@ -92,6 +97,11 @@
private String m_proxy;
/**
+ * Timeout attribute.
+ */
+ private String m_timeout;
+
+ /**
* Constructor.
* @param name : field name.
*/
@@ -128,6 +138,11 @@
m_defaultImplementation = type.getClassName();
return;
}
+ if (name.equals("exception")) {
+ Type type = Type.getType(value.toString());
+ m_exception = type.getClassName();
+ return;
+ }
if (name.equals("specification")) {
m_specification = value.toString();
return;
@@ -148,6 +163,9 @@
if (name.equals("proxy")) {
m_proxy = value.toString();
}
+ if (name.equals("timeout")) {
+ m_timeout = value.toString();
+ }
}
/**
@@ -183,6 +201,9 @@
if (m_defaultImplementation != null) {
requires.addAttribute(new Attribute("default-implementation", m_defaultImplementation));
}
+ if (m_exception != null) {
+ requires.addAttribute(new Attribute("exception", m_exception));
+ }
if (m_policy != null) {
requires.addAttribute(new Attribute("policy", m_policy));
}
@@ -198,6 +219,9 @@
if (m_proxy != null) {
requires.addAttribute(new Attribute("proxy", m_proxy));
}
+ if (m_timeout != null) {
+ requires.addAttribute(new Attribute("timeout", m_timeout));
+ }
if (m_id != null) {
workbench.getIds().put(m_id, requires);
diff --git a/ipojo/manipulator/manipulator/src/main/resources/xsd/core.xsd b/ipojo/manipulator/manipulator/src/main/resources/xsd/core.xsd
index 6f7320a..3e8f0fe 100644
--- a/ipojo/manipulator/manipulator/src/main/resources/xsd/core.xsd
+++ b/ipojo/manipulator/manipulator/src/main/resources/xsd/core.xsd
@@ -299,6 +299,26 @@
</xs:annotation>
</xs:attribute>
+ <xs:attribute name="exception" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the exception to throw for an optional service
+ dependency. If no providers are found, iPOJO creates an instance of the
+ exception (with either no parameter or a String parameter as constructor argument), and
+ throws it. The given class name must extends RuntimeException.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="timeout" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the timeout after which the 'no service policy' is executed
+ (nullable, null, empty collection, exception...). The value is the time in millisecond to
+ wait. -1 is used to indicate an infinite wait, 0 executes the no service policy
+ immediately.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
<xs:attribute name="from" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Specific service provider. The dependency can only be fulfilled by the
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java
new file mode 100644
index 0000000..55ed5f0
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/ExceptionAwareCheckServiceProvider.java
@@ -0,0 +1,73 @@
+/*
+ * 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.runtime.core.test.components.exceptions;
+
+import org.apache.felix.ipojo.annotations.Bind;
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.annotations.Requires;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+
+import java.util.Properties;
+
+/**
+ * A component supporting exception when no services are available.
+ */
+@Component
+@Provides
+public class ExceptionAwareCheckServiceProvider implements CheckService {
+
+ @Requires(id="foo", optional = true, exception = NoServiceException.class)
+ private FooService fs;
+ private int bind;
+ private int unbind;
+
+ @Bind(id = "foo")
+ public void bindFoo(FooService fs) {
+ if (fs != null) {
+ bind++;
+ }
+ }
+
+ public void unbindFoo(FooService fs) {
+ if (fs != null) {
+ unbind++;
+ }
+ }
+
+ @Override
+ public boolean check() {
+ try {
+ fs.foo();
+ return true; // always return true, to detect the exception case.
+ } catch (NoServiceException e) {
+ return true;
+ }
+ }
+
+ @Override
+ public Properties getProps() {
+ Properties properties = new Properties();
+ properties.put("bind", bind);
+ properties.put("unbind", unbind);
+ return properties;
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/NoServiceException.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/NoServiceException.java
new file mode 100644
index 0000000..d21d215
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/exceptions/NoServiceException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.runtime.core.test.components.exceptions;
+
+/**
+ * Class used to test the 'exception' attribute.
+ */
+public class NoServiceException extends RuntimeException {
+
+ public NoServiceException(String message) {
+ super(message);
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/exceptions/TestDependenciesWithExceptions.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/exceptions/TestDependenciesWithExceptions.java
new file mode 100644
index 0000000..e0e4be7
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-optional-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/dependencies/exceptions/TestDependenciesWithExceptions.java
@@ -0,0 +1,95 @@
+/*
+ * 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.runtime.core.test.dependencies.exceptions;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.core.test.dependencies.Common;
+import org.apache.felix.ipojo.runtime.core.test.services.CheckService;
+import org.apache.felix.ipojo.runtime.core.test.services.FooService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Checks the behavior of the exception attribute.
+ */
+public class TestDependenciesWithExceptions extends Common {
+
+ ComponentInstance consumer;
+ ComponentInstance provider;
+
+ @Before
+ public void setUp() {
+ try {
+ Properties prov = new Properties();
+ prov.put("instance.name", "FooProvider");
+ provider = ipojoHelper.getFactory("FooProviderType-1").createComponentInstance(prov);
+ provider.stop();
+
+ Properties i1 = new Properties();
+ i1.put("instance.name", "Consumer");
+ consumer = ipojoHelper
+ .getFactory("org.apache.felix.ipojo.runtime.core.test.components.exceptions.ExceptionAwareCheckServiceProvider")
+ .createComponentInstance(i1);
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @After
+ public void tearDown() {
+ consumer.dispose();
+ provider.dispose();
+ consumer = null;
+ provider = null;
+ }
+
+ /**
+ * A simple test checking that the exception is thrown.
+ */
+ @Test
+ public void testExceptionWhenServiceUnavailable() {
+ assertNull(osgiHelper.getServiceObject(FooService.class));
+ osgiHelper.waitForService(CheckService.class, "(instance.name=" + consumer.getInstanceName() + ")", 1000);
+ CheckService cs = osgiHelper.getServiceObject(CheckService.class,
+ "(instance.name=" + consumer.getInstanceName()+")");
+ assertNotNull(cs);
+
+ // the exception is caught by the implementation, and false is returned.
+ assertFalse(cs.check());
+
+ // we start the provider.
+ provider.start();
+ assertNotNull(osgiHelper.getServiceObject(FooService.class));
+
+ // This time everything is fine.
+ assertTrue(cs.check());
+ }
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/pom.xml
new file mode 100644
index 0000000..61056fd
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>ipojo-core-service-dependency-timeout-test</artifactId>
+ <version>1.10.2-SNAPSHOT</version>
+ <name>${project.artifactId}</name>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CheckServiceProvider.java
new file mode 100644
index 0000000..7f6f979
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CheckServiceProvider.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.runtime.test.dependencies.timeout.components;
+
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+
+import java.util.Properties;
+
+public class CheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private FooService fs;
+
+ public boolean check() {
+ return fs != null && fs.foo();
+ }
+
+ public Properties getProps() {
+ if (fs != null) {
+ return fs.fooProps();
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CollectionCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CollectionCheckServiceProvider.java
new file mode 100644
index 0000000..e410197
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/CollectionCheckServiceProvider.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.runtime.test.dependencies.timeout.components;
+
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Properties;
+
+public class CollectionCheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private Collection<FooService> fs;
+
+ public boolean check() {
+ boolean result = true;
+ //Use a local variable to avoid to wait at each access.
+ Collection<FooService> col = fs;
+ if (col != null) {
+ for (FooService svc : col) {
+ result = result && svc.foo();
+ }
+ }
+ return result;
+ }
+
+ public Properties getProps() {
+ Iterator<FooService> it = fs.iterator();
+ if (it.hasNext()) {
+ FooService svc = it.next();
+ return svc.fooProps();
+ }
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/FooProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/FooProvider.java
new file mode 100644
index 0000000..44ac92f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/FooProvider.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.runtime.test.dependencies.timeout.components;
+
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService;
+
+import java.util.Properties;
+
+public class FooProvider implements FooService {
+
+ public boolean foo() {
+ return true;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return 0;
+ }
+
+ public int getInt() {
+ return 0;
+ }
+
+ public long getLong() {
+ return 0;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/MultipleCheckServiceProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/MultipleCheckServiceProvider.java
new file mode 100644
index 0000000..92fc795
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/MultipleCheckServiceProvider.java
@@ -0,0 +1,48 @@
+/*
+ * 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.runtime.test.dependencies.timeout.components;
+
+
+import java.util.Properties;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+
+public class MultipleCheckServiceProvider implements CheckService {
+
+ /**
+ * Temporal dependency.
+ */
+ private FooService[] fs;
+
+ public boolean check() {
+ boolean result = true;
+ //Use a local variable to avoid to wait at each access.
+ FooService[] array = fs;
+ for (int i = 0; array != null && i < array.length; i++) {
+ result = result && array[i].foo();
+ System.out.println("Result : " + result);
+ }
+ return result;
+ }
+
+ public Properties getProps() {
+ return fs[0].fooProps();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/NullableFooProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/NullableFooProvider.java
new file mode 100644
index 0000000..01f7f79
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/components/NullableFooProvider.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.runtime.test.dependencies.timeout.components;
+
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+
+import java.util.Properties;
+
+public class NullableFooProvider implements FooService {
+
+ public boolean foo() {
+ return false;
+ }
+
+ public Properties fooProps() {
+ return null;
+ }
+
+ public boolean getBoolean() {
+ return false;
+ }
+
+ public double getDouble() {
+ return -1;
+ }
+
+ public int getInt() {
+ return -1;
+ }
+
+ public long getLong() {
+ return -1;
+ }
+
+ public Boolean getObject() {
+ return null;
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/CheckService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/CheckService.java
new file mode 100644
index 0000000..af98aca
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/CheckService.java
@@ -0,0 +1,30 @@
+/*
+ * 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.runtime.test.dependencies.timeout.services;
+
+import java.util.Properties;
+
+public interface CheckService {
+
+ public boolean check();
+
+ public Properties getProps();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/FooService.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/FooService.java
new file mode 100644
index 0000000..9c1550a
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/services/FooService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.runtime.test.dependencies.timeout.services;
+
+import java.util.Properties;
+
+public interface FooService {
+
+ boolean foo();
+
+ Properties fooProps();
+
+ Boolean getObject();
+
+ boolean getBoolean();
+
+ int getInt();
+
+ long getLong();
+
+ double getDouble();
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/resources/metadata.xml b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/resources/metadata.xml
new file mode 100644
index 0000000..8c10d12
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/main/resources/metadata.xml
@@ -0,0 +1,142 @@
+<!--
+ ~ 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.
+ -->
+
+<ipojo
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="org.apache.felix.ipojo">
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="CheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"/>
+ <provides/>
+ </component>
+
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.FooProvider"
+ name="FooProvider">
+ <provides/>
+ </component>
+
+ <!-- Dependencies using nullables (scalar dependency only) -->
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="NullableCheckServiceProvider">
+ <requires field="fs" optional="true"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="NullableCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"/>
+ <provides/>
+ </component>
+
+
+ <!-- Dependencies using default implementation (scalar dependency only)-->
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="DICheckServiceProvider">
+ <requires field="fs" optional="true"
+ default-implementation="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="DICheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"
+ default-implementation="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.NullableFooProvider"/>
+ <provides/>
+ </component>
+
+
+ <!-- Dependencies using null (nullable = false, scalar dependency only) -->
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="NullCheckServiceProvider">
+ <requires field="fs" optional="true" nullable="false"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="NullCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300" nullable="false"/>
+ <provides/>
+ </component>
+
+ <!-- Dependencies using empty arrays or collections (aggregate dependency only), it's the default policy. -->
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.MultipleCheckServiceProvider"
+ name="EmptyMultipleCheckServiceProvider">
+ <requires field="fs" optional="true"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CollectionCheckServiceProvider"
+ name="EmptyColCheckServiceProvider">
+ <requires field="fs" optional="true"
+ specification="org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.MultipleCheckServiceProvider"
+ name="EmptyMultipleCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CollectionCheckServiceProvider"
+ name="EmptyColCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300"
+ specification="org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService"/>
+ <provides/>
+ </component>
+
+ <!-- Dependencies using exceptions (aggregate and scalar) -->
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="ExceptionCheckServiceProvider">
+ <requires field="fs" optional="true" exception="java.lang.RuntimeException"/>
+ <provides/>
+ </component>
+
+ <component classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CheckServiceProvider"
+ name="ExceptionCheckServiceProviderTimeout">
+ <requires field="fs" optional="true" timeout="300" exception="java.lang.RuntimeException"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CollectionCheckServiceProvider"
+ name="ExceptionColCheckServiceProvider">
+ <requires field="fs" optional="true"
+ exception="java.lang.RuntimeException"
+ specification="org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService"/>
+ <provides/>
+ </component>
+
+ <component
+ classname="org.apache.felix.ipojo.runtime.test.dependencies.timeout.components.CollectionCheckServiceProvider"
+ name="ExceptionColCheckServiceProviderTimeout">
+ <requires field="fs" optional="true"
+ exception="java.lang.RuntimeException"
+ timeout="300"
+ specification="org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService"/>
+ <provides/>
+ </component>
+
+</ipojo>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/Common.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/Common.java
new file mode 100644
index 0000000..bef5281
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/Common.java
@@ -0,0 +1,31 @@
+/*
+ * 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.runtime.test.dependencies.timeout;
+
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+
+
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DefaultImplementationTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DefaultImplementationTest.java
new file mode 100644
index 0000000..20ed842
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DefaultImplementationTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.runtime.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class DefaultImplementationTest extends Common {
+
+ @Test
+ public void testDefaultImplementationTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("DICheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("DICheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayTest.java
new file mode 100644
index 0000000..c9d8add
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayTest.java
@@ -0,0 +1,211 @@
+/*
+ * 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.runtime.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class DelayTest extends Common {
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("CheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+
+
+ @Test
+ public void testTimeoutWithException() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("ExceptionCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+
+ @Test
+ public void testDelayOnMultipleDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("EmptyMultipleCheckServiceProviderTimeout",
+ un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("EmptyColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.stop();
+ provider2.stop();
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayedProvider.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayedProvider.java
new file mode 100644
index 0000000..dde2297
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/DelayedProvider.java
@@ -0,0 +1,72 @@
+/*
+ * 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.runtime.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+
+public class DelayedProvider implements Runnable {
+
+
+ public static final long DELAY = 1000;
+ ComponentInstance instance;
+ long delay = DELAY;
+ Thread thread;
+
+ public DelayedProvider(ComponentInstance ci) {
+ instance =ci;
+ }
+
+ public DelayedProvider(ComponentInstance ci, long time) {
+ instance =ci;
+ delay = time;
+ }
+
+ public void start() {
+ thread = new Thread(this);
+ thread.start();
+ }
+
+ public void stop() {
+ if (thread != null) {
+ thread.interrupt();
+ }
+ }
+
+ public void run() {
+ System.out.println("Start sleeping for " + delay);
+ long begin = System.currentTimeMillis();
+ try {
+ Thread.sleep(delay);
+ long end = System.currentTimeMillis();
+ if (end - begin < delay) {
+ // Wait for the remaining time
+ Thread.sleep(delay - (end - begin));
+ }
+ } catch (InterruptedException e) {
+ System.out.println("Interrupted ...");
+ return;
+ }
+ System.out.println("Wakeup");
+ thread = null;
+ instance.start();
+ System.out.println(instance.getInstanceName() + " started");
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/EmptyTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/EmptyTest.java
new file mode 100755
index 0000000..b812073
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/EmptyTest.java
@@ -0,0 +1,212 @@
+/*
+ * 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.runtime.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.*;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class EmptyTest extends Common {
+
+ @Test
+ public void testEmptyArrayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper
+ .createComponentInstance("EmptyMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("An empty array was expected ...");
+ }
+ assertTrue("Check empty array", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testEmptyCollectionTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper
+ .createComponentInstance("EmptyColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("An empty array was expected ...");
+ }
+ assertTrue("Check empty array", res);
+
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnMultipleDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("EmptyMultipleCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+ @Test
+ public void testDelayOnCollectionDependency() {
+ String prov = "provider";
+ ComponentInstance provider1 = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String prov2 = "provider2";
+ ComponentInstance provider2 = ipojoHelper.createComponentInstance("FooProvider", prov2);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("EmptyColCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the providers.
+ provider1.stop();
+ provider2.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider1, 1500);
+ DelayedProvider dp2 = new DelayedProvider(provider2, 100);
+ dp.start();
+ dp2.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+ System.out.println("delay = " + (end - begin));
+ assertTrue("Assert min delay", (end - begin) >= 100);
+ assertTrue("Assert max delay", (end - begin) <= 1000);
+ dp.stop();
+ dp2.stop();
+
+ provider1.stop();
+ provider2.stop();
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider1.dispose();
+ provider2.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullTest.java
new file mode 100644
index 0000000..c7cdc7f
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.runtime.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.CheckService;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class NullTest extends Common {
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("NullCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullableTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullableTest.java
new file mode 100644
index 0000000..ca6725e
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/NullableTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.runtime.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.CheckService;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class NullableTest extends Common {
+
+ @Test
+ public void testNullableTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("NullableCheckServiceProvider", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ boolean res = false;
+ try {
+ res = cs.check();
+ } catch (RuntimeException e) {
+ fail("A nullable was expected ...");
+ }
+ assertFalse("Check nullable", res);
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ @Test
+ public void testDelayTimeout() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("NullableCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/TimeoutTest.java b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/TimeoutTest.java
new file mode 100644
index 0000000..2332424
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-service-dependency-timeout-test/src/test/java/org/apache/felix/ipojo/runtime/test/dependencies/timeout/TimeoutTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.runtime.test.dependencies.timeout;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.CheckService;
+import org.apache.felix.ipojo.runtime.test.dependencies.timeout.services.FooService;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.*;
+
+public class TimeoutTest extends Common {
+
+ @Test
+ public void testDelay() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("CheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ assertNull("No FooService", osgiHelper.getServiceReference(FooService.class.getName(), null));
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ long begin = System.currentTimeMillis();
+ DelayedProvider dp = new DelayedProvider(provider, 200);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+
+ assertTrue("Check invocation - 2", cs.check());
+ long end = System.currentTimeMillis();
+
+ assertTrue("Assert delay (" + (end - begin) + ")", (end - begin) >= 200);
+
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 3", ref_cs);
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation - 3", cs.check());
+
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ }
+
+
+ @Test
+ public void testTimeoutWithException() {
+ String prov = "provider";
+ ComponentInstance provider = ipojoHelper.createComponentInstance("FooProvider", prov);
+ String un = "under-1";
+ ComponentInstance under = ipojoHelper.createComponentInstance("ExceptionCheckServiceProviderTimeout", un);
+
+ ServiceReference ref_fs = ipojoHelper.getServiceReferenceByName(FooService.class.getName(), prov);
+ assertNotNull("Check foo availability", ref_fs);
+
+ ServiceReference ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability", ref_cs);
+
+ CheckService cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ assertTrue("Check invocation", cs.check());
+
+ // Stop the provider.
+ provider.stop();
+ ref_cs = ipojoHelper.getServiceReferenceByName(CheckService.class.getName(), un);
+ assertNotNull("Check cs availability - 2", ref_cs);
+ DelayedProvider dp = new DelayedProvider(provider, 400);
+ dp.start();
+ cs = (CheckService) osgiHelper.getServiceObject(ref_cs);
+ try {
+ cs.check();
+ } catch (RuntimeException e) {
+ // OK
+ dp.stop();
+ provider.stop();
+ provider.dispose();
+ under.stop();
+ under.dispose();
+ return;
+ }
+
+ fail("Timeout expected");
+ }
+}
diff --git a/ipojo/runtime/core-it/pom.xml b/ipojo/runtime/core-it/pom.xml
index 8b453df..4773244 100644
--- a/ipojo/runtime/core-it/pom.xml
+++ b/ipojo/runtime/core-it/pom.xml
@@ -63,6 +63,7 @@
<module>ipojo-core-service-dependency-policies</module>
<module>ipojo-core-service-dependency-proxies</module>
<module>ipojo-core-service-dependency-test</module>
+ <module>ipojo-core-service-dependency-timeout-test</module>
<module>ipojo-core-service-dependency-interceptor-test</module>
<module>ipojo-core-service-providing-test</module>
<module>ipojo-api-test</module>
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
index 570471a..e5ca4b1 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/Dependency.java
@@ -18,140 +18,117 @@
*/
package org.apache.felix.ipojo.handlers.dependency;
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
-
-import org.apache.felix.ipojo.ConfigurationException;
-import org.apache.felix.ipojo.ConstructorInjector;
-import org.apache.felix.ipojo.FieldInterceptor;
-import org.apache.felix.ipojo.InstanceManager;
-import org.apache.felix.ipojo.MethodInterceptor;
-import org.apache.felix.ipojo.Nullable;
-import org.apache.felix.ipojo.PolicyServiceContext;
+import org.apache.felix.ipojo.*;
import org.apache.felix.ipojo.handlers.dependency.ServiceUsage.Usage;
import org.apache.felix.ipojo.util.DependencyModel;
+import org.apache.felix.ipojo.util.Log;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
+import java.lang.reflect.*;
+import java.util.*;
+
/**
* Represent a service dependency of the component instance.
+ *
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class Dependency extends DependencyModel implements FieldInterceptor, MethodInterceptor,
- ConstructorInjector {
+ ConstructorInjector {
/**
* Reference on the Dependency Handler.
*/
private final DependencyHandler m_handler;
-
/**
* Field of the dependency.
*/
private final String m_field;
-
+ /**
+ * Default-Implementation.
+ */
+ private final String m_di;
+ /**
+ * Exception to throw when no providers are available.
+ */
+ private final String m_exception;
+ /**
+ * Is the Nullable pattern enable?
+ */
+ private final boolean m_supportNullable;
/**
* List of dependency callback.
* Immutable once set.
*/
private DependencyCallback[] m_callbacks;
-
/**
* Is the dependency a service level dependency.
* Immutable once set.
*/
private boolean m_isServiceLevelRequirement;
-
/**
* Is the provider set frozen ?
*/
private boolean m_isFrozen;
-
/**
* Is the dependency started ?
*/
private boolean m_isStarted;
-
/**
* Thread Local.
*/
private ServiceUsage m_usage;
-
/**
* Type of the object to inject.
* Cannot change once set.
*/
private int m_type;
-
/**
* Nullable object.
* Immutable once set.
*/
private Object m_nullable;
-
- /**
- * Default-Implementation.
- */
- private final String m_di;
-
- /**
- * Is the Nullable pattern enable?
- */
- private final boolean m_supportNullable;
-
/**
* Id of the dependency.
* Immutable once set.
*/
private String m_id;
-
/**
* Do we have to inject proxy?
*/
private boolean m_isProxy;
-
/**
* Proxy Object.
*/
private Object m_proxyObject;
-
/**
- * Constructor paramter index.
+ * Constructor parameter index.
* -1 if not used.
*/
private int m_index = -1;
+ private int m_timeout;
/**
* Dependency constructor. After the creation the dependency is not started.
*
- * @param handler : the dependency handler managing this dependency
- * @param field : field of the dependency
- * @param spec : required specification
- * @param filter : LDAP filter of the dependency
- * @param isOptional : is the dependency an optional dependency ?
- * @param isAggregate : is the dependency an aggregate dependency
- * @param nullable : describe if the nullable ability is enable or disable
- * @param isProxy : is the proxied dependency
- * @param identity : id of the dependency, may be null
- * @param context : bundle context (or service context) to use.
- * @param policy : resolution policy
- * @param cmp : comparator to sort references
- * @param defaultImplem : default-implementation class
+ * @param handler : the dependency handler managing this dependency
+ * @param field : field of the dependency
+ * @param spec : required specification
+ * @param filter : LDAP filter of the dependency
+ * @param isOptional : is the dependency an optional dependency ?
+ * @param isAggregate : is the dependency an aggregate dependency
+ * @param nullable : describe if the nullable ability is enable or disable
+ * @param isProxy : is the proxied dependency
+ * @param identity : id of the dependency, may be null
+ * @param context : bundle context (or service context) to use.
+ * @param policy : resolution policy
+ * @param cmp : comparator to sort references
+ * @param defaultImplementation : default-implementation class
*/
- public Dependency(DependencyHandler handler, String field, Class spec, Filter filter, boolean isOptional, boolean isAggregate, boolean nullable, boolean isProxy, String identity, BundleContext context, int policy, Comparator cmp, String defaultImplem) {
+ public Dependency(DependencyHandler handler, String field, Class spec, Filter filter, boolean isOptional,
+ boolean isAggregate, boolean nullable, boolean isProxy, String identity, BundleContext context,
+ int policy, Comparator cmp, String defaultImplementation, String exception) {
super(spec, isAggregate, isOptional, filter, cmp, policy, context, handler, handler.getInstanceManager());
m_handler = handler;
m_field = field;
@@ -164,7 +141,8 @@
}
m_supportNullable = nullable;
- m_di = defaultImplem;
+ m_di = defaultImplementation;
+ m_exception = exception;
if (identity == null) {
if (spec != null) {
@@ -182,6 +160,7 @@
* In order to store the id of the dependency, this
* method is override. This method is called during the
* configuration.
+ *
* @param spec : request service Class
* @see org.apache.felix.ipojo.util.DependencyModel#setSpecification(java.lang.Class)
*/
@@ -199,11 +178,12 @@
/**
* Add a callback to the dependency.
* This method is called during the configuration.
+ *
* @param callback : callback to add
*/
protected void addDependencyCallback(DependencyCallback callback) {
if (m_callbacks == null) {
- m_callbacks = new DependencyCallback[] { callback };
+ m_callbacks = new DependencyCallback[]{callback};
} else {
DependencyCallback[] newCallbacks = new DependencyCallback[m_callbacks.length + 1];
System.arraycopy(m_callbacks, 0, newCallbacks, 0, m_callbacks.length);
@@ -212,7 +192,6 @@
}
}
-
protected void addConstructorInjection(int index) throws ConfigurationException {
m_index = index;
m_usage = new ServiceUsage();
@@ -221,6 +200,7 @@
/**
* Stop the current dependency.
+ *
* @see org.apache.felix.ipojo.util.DependencyModel#stop()
*/
public synchronized void stop() {
@@ -238,6 +218,7 @@
/**
* Unfreeze the dependency.
+ *
* @see org.apache.felix.ipojo.util.DependencyModel#unfreeze()
*/
public synchronized void unfreeze() {
@@ -246,13 +227,16 @@
/**
* Call the bind method.
+ *
* @param pojo : pojo instance on which calling the bind method.
*/
protected void onObjectCreation(Object pojo) {
ServiceReference[] refs;
synchronized (this) {
- if (!m_isStarted) { return; }
+ if (!m_isStarted) {
+ return;
+ }
// We are notified of an instance creation, we have to freeze when the static policy is used
if (getBindingPolicy() == STATIC_BINDING_POLICY) {
@@ -260,7 +244,9 @@
}
// Check optional case : nullable object case : do not call bind on nullable object
- if (isOptional() && getSize() == 0) { return; }
+ if (isOptional() && getSize() == 0) {
+ return;
+ }
refs = getServiceReferences(); // Stack confinement.
}
@@ -303,6 +289,7 @@
/**
* Call unbind callback method.
+ *
* @param ref : reference to send (if accepted) to the method
*/
private void callUnbindMethod(ServiceReference ref) {
@@ -317,10 +304,11 @@
/**
* Helper method calling the given callback.
- * @param callback : callback to call.
- * @param ref : service reference.
+ *
+ * @param callback : callback to call.
+ * @param ref : service reference.
* @param svcObject : the service object
- * @param pojo : pojo on which calling the callback, if null call on each created pojo objects.
+ * @param pojo : pojo on which calling the callback, if null call on each created pojo objects.
*/
private void invokeCallback(DependencyCallback callback, ServiceReference ref, Object svcObject, Object pojo) {
try {
@@ -342,10 +330,11 @@
}
- /**
- * Call 'modify' method with the service reference in parameter (if accepted).
- * @param ref : the service reference of the modified service
- */
+ /**
+ * Call 'modify' method with the service reference in parameter (if accepted).
+ *
+ * @param ref : the service reference of the modified service
+ */
private void callModifyMethod(ServiceReference ref) {
if (m_handler.getInstanceManager().getState() > InstanceManager.STOPPED && m_handler.getInstanceManager().getPojoObjects() != null) {
for (int i = 0; m_callbacks != null && i < m_callbacks.length; i++) {
@@ -356,9 +345,9 @@
}
}
-
/**
* Call method with the service reference in parameter (if accepted).
+ *
* @param ref : the service reference of the new service
*/
private void callBindMethod(ServiceReference ref) {
@@ -381,8 +370,32 @@
}
}
+ private RuntimeException createExceptionToThrow() {
+ final String message = "No service available for " + DependencyHandler.getDependencyIdentifier(this);
+ if (m_exception == null) {
+ // Should never happen, but let's see.
+ return new RuntimeException(message);
+ }
+ try {
+ Class<RuntimeException> exceptionClass = (Class<RuntimeException>) getBundleContext()
+ .getBundle().loadClass(m_exception);
+ // Check constructor
+ final Constructor<RuntimeException> constructor = exceptionClass.getConstructor(new Class[]{String.class});
+ if (constructor != null) {
+ return constructor.newInstance(message);
+ } else {
+ return exceptionClass.newInstance();
+ }
+ } catch (Exception e) {
+ m_handler.getLogger().log(Log.ERROR, "Cannot create the exception object for dependency " +
+ DependencyHandler.getDependencyIdentifier(this) + " : " + e.getMessage(), e);
+ }
+
+ return new RuntimeException(message);
+ }
+
private Object createNullableObject() {
- // To load the proxy we use the POJO class loader. Indeed, this classloader imports iPOJO (so can access to Nullable) and has
+ // To load the proxy we use the POJO class loader. Indeed, this classloader imports iPOJO (so can access to Nullable) and has
// access to the service specification.
try {
ClassLoader cl = new NullableClassLoader(
@@ -390,8 +403,8 @@
getSpecification().getClassLoader());
m_nullable =
- Proxy.newProxyInstance(cl, new Class[] {
- getSpecification(), Nullable.class }, new NullableObject()); // NOPMD
+ Proxy.newProxyInstance(cl, new Class[]{
+ getSpecification(), Nullable.class}, new NullableObject()); // NOPMD
} catch (NoClassDefFoundError e) {
// A NoClassDefFoundError is thrown if the specification uses a class not accessible by the actual instance.
@@ -410,12 +423,12 @@
public void start() {
if (isOptional() && !isAggregate()) {
- if (m_di == null) {
+ if (m_di == null && m_exception == null) {
// If nullable are supported, create the nullable object.
if (m_supportNullable) {
createNullableObject();
}
- } else {
+ } else if (m_di != null) {
// Create the default-implementation object.
try {
Class clazz = getHandler().getInstanceManager().getContext().getBundle().loadClass(m_di);
@@ -494,9 +507,9 @@
return m_isServiceLevelRequirement;
}
-
/**
* A new service has to be injected.
+ *
* @param reference : the new matching service reference.
* @see org.apache.felix.ipojo.util.DependencyModel#onServiceArrival(org.osgi.framework.ServiceReference)
*/
@@ -507,6 +520,7 @@
/**
* An already injected service is modified.
+ *
* @param reference : the modified service reference.
* @see org.apache.felix.ipojo.util.DependencyModel#onServiceModification(org.osgi.framework.ServiceReference)
*/
@@ -516,6 +530,7 @@
/**
* A used (already injected) service disappears.
+ *
* @param ref : leaving service reference.
* @see org.apache.felix.ipojo.util.DependencyModel#onServiceDeparture(org.osgi.framework.ServiceReference)
*/
@@ -527,7 +542,8 @@
* The dependency has been reconfigured.
* Call unbind method and then bind methods. If the dependency cache is not reset,
* the thread continues to get older services.
- * @param departs : no more matching services.
+ *
+ * @param departs : no more matching services.
* @param arrivals : new services
* @see org.apache.felix.ipojo.util.DependencyModel#onDependencyReconfiguration(org.osgi.framework.ServiceReference[], org.osgi.framework.ServiceReference[])
*/
@@ -555,6 +571,7 @@
/**
* Get the used service references list.
+ *
* @return the used service reference or null if no service reference are available.
*/
public List<ServiceReference> getServiceReferencesAsList() {
@@ -569,12 +586,13 @@
/**
* Called by the proxy to get service objects to delegate a method.
* On aggregate dependencies, it returns a list.
+ *
* @return a service object or a nullable/default-implementation object.
- * For aggregate dependencies it returns a list or an empty list.
+ * For aggregate dependencies it returns a list or an empty list.
*/
public Object getService() {
// Check that we're in proxy mode.
- if (! m_isProxy) {
+ if (!m_isProxy) {
throw new IllegalStateException("The dependency is not a proxied dependency");
}
@@ -587,7 +605,7 @@
usage.inc(); // Start the caching, so set the stack level to 1
m_usage.set(usage);
if (isAggregate()) {
- Object obj = usage.m_object;
+ Object obj = usage.m_object;
if (obj instanceof Set) {
List list = new ArrayList();
list.addAll((Set) obj);
@@ -628,7 +646,7 @@
// Use the copy.
// if the copy is a set, transform to a list
if (isAggregate()) {
- Object obj = usage.m_object;
+ Object obj = usage.m_object;
if (obj instanceof Set) {
List list = new ArrayList();
list.addAll((Set) obj);
@@ -647,9 +665,10 @@
/**
* This method is called by the replaced code in the component
* implementation class. Construct the service object list is necessary.
- * @param pojo : POJO object.
+ *
+ * @param pojo : POJO object.
* @param fieldName : field
- * @param value : last value.
+ * @param value : last value.
* @return the service object or a nullable / default implementation if defined.
* @see org.apache.felix.ipojo.FieldInterceptor#onGet(java.lang.Object, java.lang.String, java.lang.Object)
*/
@@ -662,7 +681,7 @@
usage.inc(); // Start the caching, so set the stack level to 1
m_usage.set(usage);
}
- if (! m_isProxy) {
+ if (!m_isProxy) {
return usage.m_object;
} else {
return m_proxyObject;
@@ -670,21 +689,34 @@
}
-
/**
* Creates the object to store in the given Thread Local.
* This object will be injected inside the POJO field.
+ *
* @param usage : Thread Local to populate.
*/
private void createServiceObject(Usage usage) {
ServiceReference[] refs = getServiceReferences();
- if (! isAggregate()) {
+
+ // manage timeout
+ if (refs == null) {
+ waitForServiceUntilTimeout();
+ }
+
+ refs = getServiceReferences();
+
+ if (!isAggregate()) {
if (refs == null) {
+ if (m_exception != null) {
+ // Throw the exception.
+ throw createExceptionToThrow();
+ }
+
if (m_nullable == null && m_supportNullable) {
m_handler.warn("[" + m_handler.getInstanceManager().getInstanceName() + "] The dependency is not optional, however no service object can be injected in " + m_field + " -> " + getSpecification().getName());
createNullableObject();
}
- usage.m_object = m_nullable; // Add null if the Nullable pattern is disable.
+ usage.m_object = m_nullable; // Add null if the Nullable pattern is disabled.
} else {
ServiceReference ref = getServiceReference();
usage.m_object = getService(ref);
@@ -711,7 +743,7 @@
if (refs == null) {
usage.m_object = new ArrayList(0); // Create an empty list.
} else {
- // Use a list to store service objects
+ // Use a list to store service objects
List objs = new ArrayList(refs.length);
for (int i = 0; refs != null && i < refs.length; i++) {
ServiceReference ref = refs[i];
@@ -723,7 +755,7 @@
if (refs == null) {
usage.m_object = new Vector(0); // Create an empty vector.
} else {
- // Use a vector to store service objects
+ // Use a vector to store service objects
Vector objs = new Vector(refs.length);
for (int i = 0; refs != null && i < refs.length; i++) {
ServiceReference ref = refs[i];
@@ -735,7 +767,7 @@
if (refs == null) {
usage.m_object = new HashSet(0); // Create an empty vector.
} else {
- // Use a vector to store service objects
+ // Use a vector to store service objects
Set objs = new HashSet(refs.length);
for (int i = 0; refs != null && i < refs.length; i++) {
ServiceReference ref = refs[i];
@@ -748,11 +780,34 @@
}
/**
+ * Waits a service providers. The wait stops when the timeout is reached.
+ */
+ private void waitForServiceUntilTimeout() {
+ // Begin to wait ...
+ long enter = System.currentTimeMillis();
+ boolean exhausted = false;
+ synchronized (this) {
+ while (getServiceReference() == null && !exhausted) {
+ try {
+ wait(1);
+ } catch (InterruptedException e) {
+ // We was interrupted ....
+ } finally {
+ long end = System.currentTimeMillis();
+ exhausted = (end - enter) > m_timeout;
+ }
+ }
+ }
+ // When this method exit, the check will be done...
+ }
+
+ /**
* The field was set.
* This method should not be call if the POJO is written correctly.
- * @param pojo : POJO object
+ *
+ * @param pojo : POJO object
* @param fieldName : field name
- * @param value : set value.
+ * @param value : set value.
* @see org.apache.felix.ipojo.FieldInterceptor#onSet(java.lang.Object, java.lang.String, java.lang.Object)
*/
public void onSet(Object pojo, String fieldName, Object value) {
@@ -761,9 +816,10 @@
/**
* A POJO method will be invoked.
- * @param pojo : Pojo object
+ *
+ * @param pojo : Pojo object
* @param method : called method
- * @param args : arguments
+ * @param args : arguments
* @see org.apache.felix.ipojo.MethodInterceptor#onEntry(java.lang.Object, java.lang.reflect.Member, java.lang.Object[])
*/
public void onEntry(Object pojo, Member method, Object[] args) {
@@ -780,8 +836,9 @@
/**
* A POJO method has thrown an error.
* This method does nothing and wait for the finally.
- * @param pojo : POJO object.
- * @param method : Method object.
+ *
+ * @param pojo : POJO object.
+ * @param method : Method object.
* @param throwable : thrown error
* @see org.apache.felix.ipojo.MethodInterceptor#onError(java.lang.Object, java.lang.reflect.Member, java.lang.Throwable)
*/
@@ -791,8 +848,9 @@
/**
* A POJO method has returned.
- * @param pojo : POJO object.
- * @param method : Method object.
+ *
+ * @param pojo : POJO object.
+ * @param method : Method object.
* @param returnedObj : returned object (null for void method)
* @see org.apache.felix.ipojo.MethodInterceptor#onExit(java.lang.Object, java.lang.reflect.Member, java.lang.Object)
*/
@@ -802,7 +860,8 @@
/**
* A POJO method is finished.
- * @param pojo : POJO object.
+ *
+ * @param pojo : POJO object.
* @param method : Method object.
* @see org.apache.felix.ipojo.MethodInterceptor#onFinally(java.lang.Object, java.lang.reflect.Member)
*/
@@ -822,6 +881,7 @@
/**
* Gets true if the dependency use Nullable objects.
+ *
* @return true if the dependency is optional and supports nullable objects.
*/
public boolean supportsNullable() {
@@ -843,6 +903,7 @@
/**
* Set the type to inject.
* This method set the dependency as aggregate.
+ *
* @param type either list of vector
*/
protected void setType(int type) {
@@ -851,22 +912,84 @@
}
/**
+ * Sets the dependency timeout.
+ *
+ * @param timeout the timeout in ms.
+ */
+ public void setTimeout(int timeout) {
+ m_timeout = timeout;
+ }
+
+ /**
+ * Gets the constructor parameter.
+ *
+ * @return the index of the constructor parameter,
+ * or <code>-1</code> if not set.
+ */
+ public int getConstructorParameterIndex() {
+ return m_index;
+ }
+
+ /**
+ * Gets the object to inject in the constructor parameter.
+ *
+ * @param index the index of the parameter
+ * @return the created proxy object
+ * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameter(int)
+ */
+ public Object getConstructorParameter(int index) {
+ if (m_index == index && m_proxyObject != null) {
+ return m_proxyObject;
+ }
+ return null;
+ }
+
+ /**
+ * Gets the type of the constructor parameter.
+ *
+ * @param index the parameter index
+ * @return the class of the object. For scalar dependency, it's the
+ * specification, for aggregate it depends of the container object:
+ * {@link List} or {@link Set}.
+ * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameterType(int)
+ */
+ public Class getConstructorParameterType(int index) {
+ if (m_index == index && m_proxyObject != null) {
+ if (isAggregate()) {
+ switch (m_type) {
+ case DependencyHandler.LIST:
+ return List.class;
+ case DependencyHandler.SET:
+ return Set.class;
+ //TODO We should also manage the Collection type.
+ default:
+ return null; // Should never happen, it was checked before.
+ }
+ } else {
+ return getSpecification();
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Classloader for nullable objects.
*/
private static class NullableClassLoader extends ClassLoader {
- /**
- * Component classloader.
- */
+ /**
+ * Component classloader.
+ */
private ClassLoader m_component;
-
- /**
- * Specification classloader.
- */
+ /**
+ * Specification classloader.
+ */
private ClassLoader m_specification;
/**
* Creates a NullableClassLoader.
- * @param cmp the component class loader.
+ *
+ * @param cmp the component class loader.
* @param spec the specification class loader.
*/
public NullableClassLoader(ClassLoader cmp, ClassLoader spec) {
@@ -878,6 +1001,7 @@
* Loads the given class.
* This method uses the classloader of the component class
* and (if not found) the specification classloader.
+ *
* @param name the class name
* @return the class object
* @throws ClassNotFoundException if the class is not found by the two classloaders.
@@ -906,6 +1030,7 @@
/**
* Creates the proxy classloader.
+ *
* @param parent the handler classloader.
*/
public SmartProxyFactory(ClassLoader parent) {
@@ -915,6 +1040,7 @@
/**
* Loads a proxy class generated for the given (interface) class.
+ *
* @param clazz the service specification to proxy
* @return the Class object of the proxy.
*/
@@ -931,8 +1057,9 @@
/**
* Create a proxy object for the given specification. The proxy
* uses the given dependency to get the service object.
+ *
* @param spec the service specification (interface)
- * @param dep the dependency used to get the service
+ * @param dep the dependency used to get the service
* @return the proxy object.
*/
public Object getProxy(Class spec, Dependency dep) {
@@ -940,7 +1067,7 @@
Class clazz = getProxyClass(getSpecification());
Constructor constructor = clazz.getConstructor(
new Class[]{clazz.getClassLoader().loadClass(Dependency.class.getName())});
- return constructor.newInstance(new Object[] {dep});
+ return constructor.newInstance(new Object[]{dep});
} catch (Throwable e) {
m_handler.error("Cannot create the proxy object", e);
m_handler.getInstanceManager().stop();
@@ -952,6 +1079,7 @@
* Loads the given class.
* This method uses the classloader of the specification class
* or the handler class loader.
+ *
* @param name the class name
* @return the class object
* @throws ClassNotFoundException if the class is not found by the two classloaders.
@@ -975,12 +1103,10 @@
* HashCode method.
*/
private Method m_hashCodeMethod;
-
/**
* Equals method.
*/
private Method m_equalsMethod;
-
/**
* toStirng method.
*/
@@ -993,7 +1119,7 @@
try {
m_hashCodeMethod = Object.class.getMethod("hashCode", null);
m_equalsMethod = Object.class
- .getMethod("equals", new Class[] { Object.class });
+ .getMethod("equals", new Class[]{Object.class});
m_toStringMethod = Object.class.getMethod("toString", null);
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
@@ -1003,22 +1129,24 @@
/**
* Creates a proxy object for the given specification. The proxy
* uses the given dependency to get the service object.
+ *
* @param spec the service specification (interface)
* @return the proxy object.
*/
public Object getProxy(Class spec) {
return java.lang.reflect.Proxy.newProxyInstance(
getHandler().getInstanceManager().getClazz().getClassLoader(),
- new Class[] {spec},
+ new Class[]{spec},
this);
}
/**
* Invocation Handler delegating invocation on the
* service object.
- * @param proxy the proxy object
+ *
+ * @param proxy the proxy object
* @param method the method
- * @param args the arguments
+ * @param args the arguments
* @return a proxy object.
* @throws Exception if the invocation throws an exception
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
@@ -1044,51 +1172,4 @@
}
- /**
- * Gets the constructor parameter.
- * @return the index of the constructor parameter,
- * or <code>-1</code> if not set.
- */
- public int getConstructorParameterIndex() {
- return m_index;
- }
-
- /**
- * Gets the object to inject in the constructor parameter.
- * @param index the index of the parameter
- * @return the created proxy object
- * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameter(int)
- */
- public Object getConstructorParameter(int index) {
- if (m_index == index && m_proxyObject != null) {
- return m_proxyObject;
- }
- return null;
- }
-
- /**
- * Gets the type of the constructor parameter.
- * @param index the parameter index
- * @return the class of the object. For scalar dependency, it's the
- * specification, for aggregate it depends of the container object:
- * {@link List} or {@link Set}.
- * @see org.apache.felix.ipojo.ConstructorInjector#getConstructorParameterType(int)
- */
- public Class getConstructorParameterType(int index) {
- if (m_index == index && m_proxyObject != null) {
- if (isAggregate()) {
- switch (m_type) {
- case DependencyHandler.LIST: return List.class;
- case DependencyHandler.SET : return Set.class;
- //TODO We should also manage the Collection type.
- default: return null; // Should never happen, it was checked before.
- }
- } else {
- return getSpecification();
- }
- } else {
- return null;
- }
- }
-
}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
index 84225b4..9af82c4 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/handlers/dependency/DependencyHandler.java
@@ -453,6 +453,12 @@
String opt = dependencyElement.getAttribute("optional");
boolean optional = opt != null && opt.equalsIgnoreCase("true");
String defaultImpl = dependencyElement.getAttribute("default-implementation");
+ String exception = dependencyElement.getAttribute("exception");
+ String to = dependencyElement.getAttribute("timeout");
+ int timeout = 0;
+ if (to != null) {
+ timeout = Integer.parseInt(to);
+ }
String agg = dependencyElement.getAttribute("aggregate");
boolean aggregate = agg != null && agg.equalsIgnoreCase("true");
@@ -477,7 +483,9 @@
int policy = DependencyMetadataHelper.getPolicy(dependencyElement);
Comparator cmp = DependencyMetadataHelper.getComparator(dependencyElement, getInstanceManager().getGlobalContext());
- Dependency dep = new Dependency(this, field, spec, fil, optional, aggregate, nullable, isProxy, identity, context, policy, cmp, defaultImpl);
+ Dependency dep = new Dependency(this, field, spec, fil, optional, aggregate, nullable, isProxy, identity,
+ context, policy, cmp, defaultImpl, exception);
+ dep.setTimeout(timeout);
// Look for dependency callback :
addCallbacksToDependency(dependencyElement, dep);
diff --git a/ipojo/runtime/core/src/main/resources/core.xsd b/ipojo/runtime/core/src/main/resources/core.xsd
index 6f7320a..3e8f0fe 100644
--- a/ipojo/runtime/core/src/main/resources/core.xsd
+++ b/ipojo/runtime/core/src/main/resources/core.xsd
@@ -299,6 +299,26 @@
</xs:annotation>
</xs:attribute>
+ <xs:attribute name="exception" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the exception to throw for an optional service
+ dependency. If no providers are found, iPOJO creates an instance of the
+ exception (with either no parameter or a String parameter as constructor argument), and
+ throws it. The given class name must extends RuntimeException.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="timeout" type="xs:int" use="optional">
+ <xs:annotation>
+ <xs:documentation>Specifies the timeout after which the 'no service policy' is executed
+ (nullable, null, empty collection, exception...). The value is the time in millisecond to
+ wait. -1 is used to indicate an infinite wait, 0 executes the no service policy
+ immediately.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
<xs:attribute name="from" type="xs:string" use="optional">
<xs:annotation>
<xs:documentation>Specific service provider. The dependency can only be fulfilled by the
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/SmartProxyTest.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/SmartProxyTest.java
index 5d269b5..927317d 100644
--- a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/SmartProxyTest.java
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/handlers/dependency/SmartProxyTest.java
@@ -63,7 +63,7 @@
Mockito.when(handler.getLogger()).thenReturn(logger);
Dependency dependency = new Dependency(handler, "a_field", ArrayList.class, null, false, false, false,
- true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null);
+ true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
dependency.start();
// No service
@@ -73,7 +73,7 @@
// Try with an Object.
dependency = new Dependency(handler, "a_field", Object.class, null, false, false, false,
- true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null);
+ true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
dependency.start();
// OK
Assert.assertNull(dependency.onGet(new Object(), "a_field", null));
@@ -111,7 +111,7 @@
// Try with java.List
Dependency dependency = new Dependency(handler, "a_field", List.class, null, false, false, false,
- true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null);
+ true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
dependency.start();
// OK
@@ -122,7 +122,7 @@
// Try with javax.sql.CommonDataSource
dependency = new Dependency(handler, "a_field", javax.sql.DataSource.class, null, false, false, false,
- true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null);
+ true, "dep", context, Dependency.DYNAMIC_BINDING_POLICY, null, null, null);
dependency.start();
// OK
Assert.assertNotNull(dependency.onGet(new Object(), "a_field", null));