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 *****************************************************************************/
010package org.picocontainer.defaults.issues;
011
012import static org.junit.Assert.assertTrue;
013
014import java.util.ArrayList;
015import java.util.List;
016
017import org.junit.Test;
018import org.picocontainer.DefaultPicoContainer;
019import org.picocontainer.PicoContainer;
020import org.picocontainer.behaviors.Synchronizing;
021import org.picocontainer.injectors.ConstructorInjection;
022
023public 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}