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 static org.junit.Assert.assertTrue;
013    
014    import java.util.ArrayList;
015    import java.util.List;
016    
017    import org.junit.Test;
018    import org.picocontainer.DefaultPicoContainer;
019    import org.picocontainer.PicoContainer;
020    import org.picocontainer.behaviors.Synchronizing;
021    import org.picocontainer.injectors.ConstructorInjection;
022    
023    public final class Issue0199TestCase {
024    
025        public static class A {
026            public A(C c) {}
027        }
028    
029        public static class B {
030            public B(C c) {}
031        }
032    
033        public static class C {}
034    
035        final class Runner extends Thread {
036            private final PicoContainer container;
037            private final Object componentKey;
038            private Throwable throwable;
039            private boolean finished;
040    
041            Runner(String name, PicoContainer container, Object componentKey) {
042                super(name);
043                this.container = container;
044                this.componentKey = componentKey;
045            }
046    
047            public void run() {
048                try {
049                    report("Started instantiating " + componentKey.toString());
050                    container.getComponent(componentKey);
051                    report("Finished instantiating " + componentKey.toString());
052                    finished = true;
053                } catch (Throwable t) {
054                    this.throwable = t;
055                }
056            }
057    
058            private void report(String messsage) {
059                System.out.println(getName() + ": " + messsage);
060            }
061    
062            public boolean isFinished() {
063                return finished;
064            }
065    
066            public Throwable getThrowable() {
067                return throwable;
068            }
069        }
070    
071        @Test public void testPicoContainerCausesDeadlock() throws InterruptedException {
072            DefaultPicoContainer container = createContainer();
073            container.addComponent("A", A.class);
074            container.addComponent("B", B.class);
075            container.addComponent("C", C.class);
076    
077            final int THREAD_COUNT = 2;
078            List runnerList = new ArrayList(THREAD_COUNT);
079    
080            for (int i = 0; i < THREAD_COUNT; ++i) {
081                Runner runner = new Runner("Runner " + i, container, (i % 2 == 0) ? "A" : "B");
082                runnerList.add(runner);
083                runner.start();
084            }
085    
086            final long WAIT_TIME = 1000;
087    
088            for (int i = 0; i < THREAD_COUNT; ++i) {
089                Runner runner = (Runner) runnerList.get(i);
090                runner.join(WAIT_TIME);
091                assertTrue("Deadlock occurred", runner.isFinished());
092            }
093        }
094    
095        private DefaultPicoContainer createContainer() {
096            return new DefaultPicoContainer(
097                    new Synchronizing().wrap(new ConstructorInjection()));
098        }
099    }