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 }