FELIX-3645: Tests which reproduces the "Could not obtain lock in 5000 milliseconds" Exception.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1379968 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentConcurrencyTest.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConcurrencyTest.java
new file mode 100644
index 0000000..90667eb
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentConcurrencyTest.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.scr.integration;
+
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Date;
+import java.util.Hashtable;
+
+import javax.inject.Inject;
+
+import junit.framework.TestCase;
+
+import org.apache.felix.scr.Component;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogEntry;
+import org.osgi.service.log.LogListener;
+import org.osgi.service.log.LogReaderService;
+import org.osgi.service.log.LogService;
+
+@RunWith(JUnit4TestRunner.class)
+public class ComponentConcurrencyTest extends ComponentTestBase
+{
+ static
+ {
+ // uncomment to enable debugging of this test class
+ // paxRunnerVmOption = DEBUG_VM_OPTION;
+ descriptorFile = "/integration_test_component_concurrency.xml";
+ }
+
+ @Inject
+ protected BundleContext bundleContext;
+
+ protected static void delay(int secs)
+ {
+ try
+ {
+ Thread.sleep(secs * 1000);
+ }
+ catch (InterruptedException ie)
+ {
+ }
+ }
+
+ // Used to ignore logs displayed by the framework from stdout.
+ // (the log service will log it because it listen to fwk error
+ // events ...).
+ static class NullStdout extends PrintStream
+ {
+ NullStdout()
+ {
+ super(new OutputStream()
+ {
+ @Override
+ public void write(int b) throws IOException
+ {
+ }
+ });
+ }
+ }
+
+ public static class Log implements LogListener
+ {
+ private volatile boolean _foundWarnings;
+ private final static PrintStream _out =
+ new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.err), 128));
+
+ public void logged(LogEntry entry)
+ {
+ if (entry.getLevel() <= 2)
+ {
+ _foundWarnings = true;
+ }
+ StringWriter sw = new StringWriter();
+ sw.append("D=");
+ sw.append(new Date(entry.getTime()).toString());
+ sw.append(", T=" + Thread.currentThread().getName());
+ sw.append(": ");
+ sw.append(entry.getMessage());
+ if (entry.getException() != null)
+ {
+ sw.append(System.getProperty("line.separator"));
+ PrintWriter pw = new PrintWriter(sw);
+ entry.getException().printStackTrace(pw);
+ }
+ _out.println(sw.toString());
+ }
+
+ boolean foundWarnings()
+ {
+ return _foundWarnings;
+ }
+ }
+
+ @Test
+ public void test_concurrent_component_activation_using_componentFactories()
+ {
+ final PrintStream out = System.out;
+ final PrintStream err = System.err;
+ System.setOut(new NullStdout());
+ System.setErr(new NullStdout());
+
+ try
+ {
+ Log log = new Log();
+ ServiceReference sr = bundleContext.getServiceReference(LogReaderService.class.getName());
+ TestCase.assertNotNull(sr);
+ LogReaderService logReader = (LogReaderService) bundleContext.getService(sr);
+ TestCase.assertNotNull(logReader);
+ logReader.addLogListener(log);
+
+ final Component AFactory =
+ findComponentByName("org.apache.felix.scr.integration.components.concurrency.AFactory");
+ TestCase.assertNotNull(AFactory);
+ AFactory.enable();
+
+ final Component CFactory =
+ findComponentByName("org.apache.felix.scr.integration.components.concurrency.CFactory");
+ TestCase.assertNotNull(CFactory);
+ CFactory.enable();
+
+ delay(30);
+ TestCase.assertFalse(log.foundWarnings());
+ }
+
+ finally
+ {
+ System.setOut(out);
+ System.setErr(err);
+ }
+ }
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
index d13a9ee..9facebd 100644
--- a/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
+++ b/scr/src/test/java/org/apache/felix/scr/integration/ComponentTestBase.java
@@ -104,7 +104,7 @@
@ProbeBuilder
public TestProbeBuilder extendProbe(TestProbeBuilder builder) {
- builder.setHeader("Export-Package", "org.apache.felix.scr.integration.components,org.apache.felix.scr.integration.components.activatesignature,org.apache.felix.scr.integration.components.circular");
+ builder.setHeader("Export-Package", "org.apache.felix.scr.integration.components,org.apache.felix.scr.integration.components.activatesignature,org.apache.felix.scr.integration.components.circular,org.apache.felix.scr.integration.components.concurrency");
builder.setHeader("Import-Package", "org.apache.felix.scr,org.apache.felix.scr.component;mandatory:=\"status\"; status=\"provisional\"");
builder.setHeader("Bundle-ManifestVersion", "2");
return builder;
@@ -125,7 +125,8 @@
provision(
CoreOptions.bundle( bundleFile.toURI().toString() ),
mavenBundle( "org.ops4j.pax.tinybundles", "tinybundles", "1.0.0" ),
- mavenBundle( "org.apache.felix", "org.apache.felix.configadmin", "1.0.10" )
+ mavenBundle( "org.apache.felix", "org.apache.felix.configadmin", "1.0.10" ),
+ mavenBundle( "org.apache.felix", "org.apache.felix.log", "1.0.1" )
),
junitBundles(),
systemProperty( "ds.factory.enabled" ).value( Boolean.toString( NONSTANDARD_COMPONENT_FACTORY_BEHAVIOR ) )
@@ -358,7 +359,7 @@
.set(Constants.BUNDLE_SYMBOLICNAME, "simplecomponent")
.set(Constants.BUNDLE_VERSION, "0.0.11")
.set(Constants.IMPORT_PACKAGE,
- "org.apache.felix.scr.integration.components,org.apache.felix.scr.integration.components.activatesignature,org.apache.felix.scr.integration.components.circular")
+ "org.apache.felix.scr.integration.components,org.apache.felix.scr.integration.components.activatesignature,org.apache.felix.scr.integration.components.circular,org.apache.felix.scr.integration.components.concurrency")
.set("Service-Component", "OSGI-INF/components.xml")
.build(withBnd());
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/A.java b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/A.java
new file mode 100644
index 0000000..c582a31
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/A.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.scr.integration.components.concurrency;
+
+public class A
+{
+ void bindB(B b)
+ {
+ }
+
+ void start()
+ {
+ }
+}
\ No newline at end of file
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/AFactory.java b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/AFactory.java
new file mode 100644
index 0000000..2eb7ff5
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/AFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.scr.integration.components.concurrency;
+
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
+
+public class AFactory implements Runnable {
+ private ComponentFactory _aFactory;
+ private Thread[] _threads = new Thread[1];
+
+ public void bindAFactory(ComponentFactory aFactory) {
+ _aFactory = aFactory;
+ }
+
+ void activate() {
+ System.out.println("AFactory started");
+ for (int i = 0; i < _threads.length; i++) {
+ _threads[i] = new Thread(this);
+ _threads[i].start();
+ }
+ }
+
+ void deactivate() {
+ System.out.println("AFactory stopped");
+ for (int i = 0; i < _threads.length; i++) {
+ _threads[i].interrupt();
+// try {
+// _threads[i].join();
+// } catch (InterruptedException e) {
+// }
+ }
+ }
+
+ public void run() {
+ while (true) {
+ try {
+ //System.out.println("Creating A");
+ ComponentInstance ci = _aFactory.newInstance(null);
+ ci.dispose();
+ if (Thread.currentThread().isInterrupted()) {
+ return;
+ }
+ } catch (Throwable t) {
+ if (!(t instanceof InterruptedException)) {
+ //System.out.println("AFactory thread exiting: got exception: " + t.toString());
+ }
+ return;
+ }
+ }
+ }
+ }
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/B.java b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/B.java
new file mode 100644
index 0000000..4b0833e
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/B.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.scr.integration.components.concurrency;
+
+public class B
+{
+ void bindC(C c)
+ {
+ }
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/C.java b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/C.java
new file mode 100644
index 0000000..1a11206
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/C.java
@@ -0,0 +1,16 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.scr.integration.components.concurrency;
+
+public class C
+{
+
+}
diff --git a/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/CFactory.java b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/CFactory.java
new file mode 100644
index 0000000..98a8a1d
--- /dev/null
+++ b/scr/src/test/java/org/apache/felix/scr/integration/components/concurrency/CFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.felix.scr.integration.components.concurrency;
+
+import org.osgi.service.component.ComponentFactory;
+import org.osgi.service.component.ComponentInstance;
+
+public class CFactory implements Runnable {
+ private ComponentFactory _cFactory;
+ private Thread[] _threads = new Thread[1];
+
+ public void bindCFactory(ComponentFactory cFactory) {
+ _cFactory = cFactory;
+ }
+
+ void activate() {
+ System.out.println("CFactory started");
+ for (int i = 0; i < _threads.length; i++) {
+ _threads[i] = new Thread(this);
+ _threads[i].start();
+ }
+ }
+
+ void deactivate() {
+ System.out.println("CFactory stopped");
+ for (int i = 0; i < _threads.length; i++) {
+ _threads[i].interrupt();
+ try {
+ _threads[i].join();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ public void run() {
+ while (true) {
+ try {
+ ComponentInstance ci = _cFactory.newInstance(null);
+ ci.dispose();
+ if (Thread.currentThread().isInterrupted()) {
+ return;
+ }
+ } catch (Throwable t) {
+ if (!(t instanceof InterruptedException)) {
+ //System.out.println("CFactory thread exiting: got exception: " + t.toString());
+ }
+ return;
+ }
+ }
+ }
+ }
diff --git a/scr/src/test/resources/integration_test_component_concurrency.xml b/scr/src/test/resources/integration_test_component_concurrency.xml
new file mode 100644
index 0000000..aeb7c7f
--- /dev/null
+++ b/scr/src/test/resources/integration_test_component_concurrency.xml
@@ -0,0 +1,64 @@
+<?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. -->
+<components xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0">
+ <scr:component
+ name='org.apache.felix.scr.integration.components.concurrency.A'
+ factory='AFactory' activate='start'>
+ <implementation
+ class='org.apache.felix.scr.integration.components.concurrency.A' />
+ <reference name='b'
+ interface='org.apache.felix.scr.integration.components.concurrency.B'
+ bind='bindB' cardinality='0..n' policy='dynamic' />
+ </scr:component>
+
+ <scr:component
+ name='org.apache.felix.scr.integration.components.concurrency.B'>
+ <implementation
+ class='org.apache.felix.scr.integration.components.concurrency.B' />
+ <service>
+ <provide interface='org.apache.felix.scr.integration.components.concurrency.B' />
+ </service>
+ <reference name='c'
+ interface='org.apache.felix.scr.integration.components.concurrency.C'
+ bind='bindC' />
+ </scr:component>
+
+ <scr:component
+ name='org.apache.felix.scr.integration.components.concurrency.C'
+ factory='CFactory'>
+ <implementation
+ class='org.apache.felix.scr.integration.components.concurrency.C' />
+ <service>
+ <provide interface='org.apache.felix.scr.integration.components.concurrency.C' />
+ </service>
+ </scr:component>
+
+ <scr:component enabled='false'
+ name='org.apache.felix.scr.integration.components.concurrency.AFactory'
+ activate='activate' deactivate='deactivate'>
+ <implementation
+ class='org.apache.felix.scr.integration.components.concurrency.AFactory' />
+ <reference name='aFactory'
+ interface='org.osgi.service.component.ComponentFactory' bind='bindAFactory'
+ target='(component.factory=AFactory)' />
+ </scr:component>
+
+ <scr:component enabled='false'
+ name='org.apache.felix.scr.integration.components.concurrency.CFactory'
+ activate='activate' deactivate='deactivate'>
+ <implementation
+ class='org.apache.felix.scr.integration.components.concurrency.CFactory' />
+ <reference name='cFactory'
+ interface='org.osgi.service.component.ComponentFactory' bind='bindCFactory'
+ target='(component.factory=CFactory)' />
+ </scr:component>
+</components>