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.behaviors;
011    
012    import static org.junit.Assert.assertEquals;
013    import static org.junit.Assert.assertFalse;
014    import static org.junit.Assert.assertNotNull;
015    import static org.junit.Assert.assertSame;
016    
017    import org.junit.Test;
018    import org.picocontainer.Characteristics;
019    import org.picocontainer.DefaultPicoContainer;
020    import org.picocontainer.classname.DefaultClassLoadingPicoContainer;
021    import org.picocontainer.injectors.CompositeInjection;
022    import org.picocontainer.injectors.ConstructorInjection;
023    import org.picocontainer.injectors.SetterInjection;
024    import org.picocontainer.lifecycle.NullLifecycleStrategy;
025    import org.picocontainer.monitors.NullComponentMonitor;
026    
027    public class ThreadCachingTestCase {
028    
029        public static class Foo {
030            public Foo(StringBuilder sb) {
031                sb.append("<Foo");
032            }
033        }
034    
035        public static class Baz {
036    
037            public Baz() {
038            }
039    
040            public void setStringBuilder(StringBuilder sb) {
041                    sb.append("<Baz");
042            }
043    
044        }
045    
046        public static class Qux {
047    
048            private static final Object lock = new Object();
049    
050            private static int CTR;
051    
052            private int inst;
053    
054            public Qux(StringBuilder sb) {
055                synchronized (lock) {
056                    inst = CTR++;
057                    sb.append("!").append(inst).append(" ");
058                }
059            }
060            public void setStringBuilder(StringBuilder sb) {
061                synchronized (lock) {
062                    sb.append("<").append(inst).append(" ");
063                }
064            }
065    
066            @Override
067            public String toString() {
068                return "baz2: " + inst;
069            }
070        }
071    
072        public static class Bar {
073            private final Foo foo;
074            public Bar(StringBuilder sb, Foo foo) {
075                this.foo = foo;
076                sb.append("<Bar");
077            }
078        }
079    
080        @Test public void testThatForASingleThreadTheBehaviorIsTheSameAsPlainCaching() {
081    
082            DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
083            DefaultPicoContainer child = new DefaultPicoContainer(new ThreadCaching(), new NullLifecycleStrategy(), parent);
084    
085            parent.addComponent(StringBuilder.class);
086            child.addComponent(Foo.class);
087    
088            StringBuilder sb = parent.getComponent(StringBuilder.class);
089            Foo foo = child.getComponent(Foo.class);
090            Foo foo2 = child.getComponent(Foo.class);
091            assertNotNull(foo);
092            assertNotNull(foo2);
093            assertEquals(foo,foo2);
094            assertEquals("<Foo", sb.toString());
095            assertEquals("ThreadCached:ConstructorInjector-class org.picocontainer.behaviors.ThreadCachingTestCase$Foo", child.getComponentAdapter(Foo.class).toString());
096        }
097    
098        @Test public void testThatForASingleThreadTheBehaviorIsTheSameAsPlainCachingWithSetterInjection() {
099    
100            DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
101            DefaultPicoContainer child = new DefaultPicoContainer(new ThreadCaching().wrap(new SetterInjection()), new NullLifecycleStrategy(), parent);
102    
103            parent.addComponent(StringBuilder.class);
104            child.addComponent(Baz.class);
105    
106            StringBuilder sb = parent.getComponent(StringBuilder.class);
107            Baz baz = child.getComponent(Baz.class);
108            Baz baz2 = child.getComponent(Baz.class);
109            assertNotNull(baz);
110            assertNotNull(baz2);
111            assertEquals(baz,baz2);
112            assertEquals("<Baz", sb.toString());
113            assertEquals("ThreadCached:SetterInjector-class org.picocontainer.behaviors.ThreadCachingTestCase$Baz", child.getComponentAdapter(Baz.class).toString());
114        }
115    
116        @Test public void testThatTwoThreadsHaveSeparatedCacheValues() {
117    
118            final Foo[] foos = new Foo[4];
119    
120            DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
121            final DefaultPicoContainer child = new DefaultPicoContainer(new ThreadCaching(), new NullLifecycleStrategy(), parent);
122    
123            parent.addComponent(StringBuilder.class);
124            child.addComponent(Foo.class);
125    
126            StringBuilder sb = parent.getComponent(StringBuilder.class);
127            foos[0] = child.getComponent(Foo.class);
128    
129            Thread thread = new Thread() {
130                public void run() {
131                    foos[1] = child.getComponent(Foo.class);
132                    foos[3] = child.getComponent(Foo.class);
133                }
134            };
135            thread.start();
136            foos[2] = child.getComponent(Foo.class);
137            try {
138                Thread.sleep(100);
139            } catch (InterruptedException e) {
140            }
141    
142            assertNotNull(foos[0]);
143            assertNotNull(foos[1]);
144            assertNotNull(foos[2]);
145            assertNotNull(foos[3]);
146            assertSame(foos[0],foos[2]);
147            assertEquals(foos[1],foos[3]);
148            assertFalse(foos[0] == foos[1]);
149            assertEquals("<Foo<Foo", sb.toString());
150            assertEquals("ThreadCached:ConstructorInjector-class org.picocontainer.behaviors.ThreadCachingTestCase$Foo", child.getComponentAdapter(Foo.class).toString());
151        }
152    
153        @Test public void testThatTwoThreadsHaveSeparatedCacheValuesWithCompositeInjection() {
154    
155            final Qux[] quxs = new Qux[4];
156    
157            DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
158            final DefaultPicoContainer child = new DefaultPicoContainer(new ThreadCaching().wrap(
159                    new CompositeInjection(new ConstructorInjection(), new SetterInjection())),
160                    new NullLifecycleStrategy(), parent);
161    
162            parent.addComponent(StringBuilder.class);
163            child.addComponent(Qux.class);
164    
165            StringBuilder sb = parent.getComponent(StringBuilder.class);
166            quxs[0] = child.getComponent(Qux.class);
167    
168            Thread thread = new Thread() {
169                public void run() {
170                    quxs[1] = child.getComponent(Qux.class);
171                    quxs[3] = child.getComponent(Qux.class);
172                }
173            };
174            thread.start();
175            quxs[2] = child.getComponent(Qux.class);
176            try {
177                Thread.sleep(100);
178            } catch (InterruptedException e) {
179            }
180    
181            assertNotNull(quxs[0]);
182            assertNotNull(quxs[1]);
183            assertNotNull(quxs[2]);
184            assertNotNull(quxs[3]);
185            assertSame(quxs[0],quxs[2]);
186            assertEquals(quxs[1],quxs[3]);
187            assertFalse(quxs[0] == quxs[1]);
188            assertEquals("!0 <0 !1 <1", sb.toString().trim());
189            assertEquals("ThreadCached:CompositeInjector(ConstructorInjector+SetterInjector)-class org.picocontainer.behaviors.ThreadCachingTestCase$Qux", child.getComponentAdapter(Qux.class).toString());
190        }
191    
192        @Test public void testThatTwoThreadsHaveSeparatedCacheValuesWithInstanceRegistrationAndClassLoadingPicoContainer() {
193    
194            final Foo[] foos = new Foo[4];
195    
196            DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
197            parent.change(Characteristics.USE_NAMES);
198            parent.addComponent(StringBuilder.class);
199    
200            final DefaultClassLoadingPicoContainer child = new DefaultClassLoadingPicoContainer(new ThreadCaching(), new NullLifecycleStrategy(), parent, this.getClass().getClassLoader(), new NullComponentMonitor());
201            child.change(Characteristics.USE_NAMES);
202            child.addComponent(Foo.class);
203            child.addComponent("hello");
204    
205            StringBuilder sb = parent.getComponent(StringBuilder.class);
206            foos[0] = child.getComponent(Foo.class);
207    
208            Thread thread = new Thread() {
209                public void run() {
210                    foos[1] = child.getComponent(Foo.class);
211                    foos[3] = child.getComponent(Foo.class);
212                }
213            };
214            thread.start();
215            foos[2] = child.getComponent(Foo.class);
216            try {
217                Thread.sleep(100);
218            } catch (InterruptedException e) {
219            }
220    
221            assertNotNull(foos[0]);
222            assertNotNull(foos[1]);
223            assertNotNull(foos[2]);
224            assertNotNull(foos[3]);
225            assertSame(foos[0],foos[2]);
226            assertEquals(foos[1],foos[3]);
227            assertFalse(foos[0] == foos[1]);
228            assertEquals("<Foo<Foo", sb.toString());
229            assertEquals("ThreadCached:ConstructorInjector-class org.picocontainer.behaviors.ThreadCachingTestCase$Foo", child.getComponentAdapter(Foo.class).toString());
230        }
231    
232    
233        @Test public void testThatTwoThreadsHaveSeparatedCacheValuesForThreeScopeScenario() {
234    
235            final Foo[] foos = new Foo[4];
236            final Bar[] bars = new Bar[4];
237    
238            DefaultPicoContainer appScope = new DefaultPicoContainer(new Caching());
239            final DefaultPicoContainer sessionScope = new DefaultPicoContainer(new ThreadCaching(), new NullLifecycleStrategy(), appScope);
240            final DefaultPicoContainer requestScope = new DefaultPicoContainer(new ThreadCaching(), new NullLifecycleStrategy(), sessionScope);
241    
242            appScope.addComponent(StringBuilder.class);
243            sessionScope.addComponent(Foo.class);
244            requestScope.addComponent(Bar.class);
245    
246            StringBuilder sb = appScope.getComponent(StringBuilder.class);
247            foos[0] = sessionScope.getComponent(Foo.class);
248            bars[0] = requestScope.getComponent(Bar.class);
249    
250            Thread thread = new Thread() {
251                public void run() {
252                    foos[1] = sessionScope.getComponent(Foo.class);
253                    bars[1] = requestScope.getComponent(Bar.class);
254                    foos[3] = sessionScope.getComponent(Foo.class);
255                    bars[3] = requestScope.getComponent(Bar.class);
256                }
257            };
258            thread.start();
259            foos[2] = sessionScope.getComponent(Foo.class);
260            bars[2] = requestScope.getComponent(Bar.class);
261            try {
262                Thread.sleep(100);
263            } catch (InterruptedException e) {
264            }
265    
266            assertSame(bars[0],bars[2]);
267            assertEquals(bars[1],bars[3]);
268            assertFalse(bars[0] == bars[1]);
269            assertSame(bars[0].foo,foos[0]);
270            assertSame(bars[1].foo,foos[1]);
271            assertSame(bars[2].foo,foos[2]);
272            assertSame(bars[3].foo,foos[3]);
273            assertEquals("<Foo<Bar<Foo<Bar", sb.toString());
274            assertEquals("ThreadCached:ConstructorInjector-class org.picocontainer.behaviors.ThreadCachingTestCase$Foo", sessionScope.getComponentAdapter(Foo.class).toString());
275        }
276    
277    
278    }