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 Joerg Schaible * 009 *****************************************************************************/ 010 package org.picocontainer.injectors; 011 012 import static org.junit.Assert.assertEquals; 013 import static org.junit.Assert.assertNull; 014 import static org.junit.Assert.assertSame; 015 import static org.junit.Assert.assertTrue; 016 017 import org.junit.Test; 018 019 /** 020 * Test the CyclicDependecy. 021 */ 022 public final class ThreadLocalCyclicDependencyGuardTestCase { 023 024 private final Runnable[] runner = new Runnable[3]; 025 026 class ThreadLocalRunner implements Runnable { 027 public AbstractInjector.CyclicDependencyException exception; 028 private final Blocker blocker; 029 private final AbstractInjector.ThreadLocalCyclicDependencyGuard guard; 030 031 public ThreadLocalRunner() { 032 this.blocker = new Blocker(); 033 this.guard = new AbstractInjector.ThreadLocalCyclicDependencyGuard() { 034 public Object run() { 035 try { 036 blocker.block(); 037 } catch (InterruptedException e) { 038 } 039 return null; 040 } 041 }; 042 } 043 044 public void run() { 045 try { 046 guard.observe(ThreadLocalRunner.class); 047 } catch (AbstractInjector.CyclicDependencyException e) { 048 exception = e; 049 } 050 } 051 } 052 053 public class Blocker { 054 public void block() throws InterruptedException { 055 final Thread thread = Thread.currentThread(); 056 synchronized (thread) { 057 thread.wait(); 058 } 059 } 060 } 061 062 private void initTest(final Runnable[] runner) throws InterruptedException { 063 064 Thread racer[] = new Thread[runner.length]; 065 for(int i = 0; i < racer.length; ++i) { 066 racer[i] = new Thread(runner[i]); 067 } 068 069 for (Thread aRacer : racer) { 070 aRacer.start(); 071 Thread.sleep(200); 072 } 073 074 for (Thread aRacer : racer) { 075 synchronized (aRacer) { 076 aRacer.notify(); 077 } 078 } 079 080 for (Thread aRacer : racer) { 081 aRacer.join(); 082 } 083 } 084 085 @Test public void testCyclicDependencyWithThreadSafeGuard() throws InterruptedException { 086 for(int i = 0; i < runner.length; ++i) { 087 runner[i] = new ThreadLocalRunner(); 088 } 089 090 initTest(runner); 091 092 for (Runnable aRunner : runner) { 093 assertNull(((ThreadLocalRunner) aRunner).exception); 094 } 095 } 096 097 @Test public void testCyclicDependencyException() { 098 final AbstractInjector.CyclicDependencyException cdEx = new AbstractInjector.CyclicDependencyException(getClass()); 099 cdEx.push(String.class); 100 final Class[] classes = cdEx.getDependencies(); 101 assertEquals(2, classes.length); 102 assertSame(getClass(), classes[0]); 103 assertSame(String.class, classes[1]); 104 assertTrue(cdEx.getMessage().indexOf(getClass().getName()) >= 0); 105 } 106 107 108 109 }