001    /*****************************************************************************
002     * Copyright (C) PicoContainer Organization. All rights reserved.            *
003     * ------------------------------------------------------------------------- *
004     * The software in this package is published under the terms of the BSD      *
005     * style license a copy of which has been included with this distribution in *
006     * the LICENSE.txt file.                                                     *
007     *                                                                           *
008     * Original code by                                                          *
009     *****************************************************************************/
010    package org.picocontainer.defaults.issues;
011    
012    import junit.framework.TestCase;
013    
014    import java.util.List;
015    import java.util.ArrayList;
016    
017    import org.picocontainer.PicoContainer;
018    import org.picocontainer.DefaultPicoContainer;
019    import org.picocontainer.injectors.ConstructorInjectionFactory;
020    import org.picocontainer.behaviors.SynchronizedBehaviorFactory;
021    
022    public final class Issue0199TestCase extends TestCase {
023    
024        public static class A {
025            public A(C c) {}
026        }
027    
028        public static class B {
029            public B(C c) {}
030        }
031    
032        public static class C {}
033    
034        final class Runner extends Thread {
035            private final PicoContainer container;
036            private final Object componentKey;
037            private Throwable throwable;
038            private boolean finished;
039    
040            Runner(String name, PicoContainer container, Object componentKey) {
041                super(name);
042                this.container = container;
043                this.componentKey = componentKey;
044            }
045    
046            public void run() {
047                try {
048                    report("Started instantiating " + componentKey.toString());
049                    container.getComponent(componentKey);
050                    report("Finished instantiating " + componentKey.toString());
051                    finished = true;
052                } catch (Throwable t) {
053                    this.throwable = t;
054                }
055            }
056    
057            private void report(String messsage) {
058                System.out.println(getName() + ": " + messsage);
059            }
060    
061            public boolean isFinished() {
062                return finished;
063            }
064    
065            public Throwable getThrowable() {
066                return throwable;
067            }
068        }
069    
070        public void testPicoContainerCausesDeadlock() throws InterruptedException {
071            DefaultPicoContainer container = createContainer();
072            container.addComponent("A", A.class);
073            container.addComponent("B", B.class);
074            container.addComponent("C", C.class);
075    
076            final int THREAD_COUNT = 2;
077            List runnerList = new ArrayList(THREAD_COUNT);
078    
079            for (int i = 0; i < THREAD_COUNT; ++i) {
080                Runner runner = new Runner("Runner " + i, container, (i % 2 == 0) ? "A" : "B");
081                runnerList.add(runner);
082                runner.start();
083            }
084    
085            final long WAIT_TIME = 1000;
086    
087            for (int i = 0; i < THREAD_COUNT; ++i) {
088                Runner runner = (Runner) runnerList.get(i);
089                runner.join(WAIT_TIME);
090                assertTrue("Deadlock occurred", runner.isFinished());
091            }
092        }
093    
094        private DefaultPicoContainer createContainer() {
095            return new DefaultPicoContainer(
096                    new SynchronizedBehaviorFactory().forThis(new ConstructorInjectionFactory()));
097        }
098    }