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.assertNotSame;
016 import static org.junit.Assert.assertSame;
017 import static org.junit.Assert.assertTrue;
018 import static org.junit.Assert.fail;
019
020 import org.junit.Test;
021 import org.picocontainer.DefaultPicoContainer;
022
023 public class StoringTestCase {
024
025 public static class Foo {
026 public Foo(StringBuilder sb) {
027 sb.append("<Foo");
028 }
029 }
030
031 public static class Bar {
032 private final Foo foo;
033 public Bar(StringBuilder sb, Foo foo) {
034 this.foo = foo;
035 sb.append("<Bar");
036 }
037 }
038
039 @Test public void testThatForASingleThreadTheBehaviorIsTheSameAsPlainCaching() {
040
041 DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
042 Storing storeCaching = new Storing();
043 DefaultPicoContainer child = new DefaultPicoContainer(storeCaching, parent);
044
045 parent.addComponent(StringBuilder.class);
046 child.addComponent(Foo.class);
047
048 StringBuilder sb = parent.getComponent(StringBuilder.class);
049 Foo foo = child.getComponent(Foo.class);
050 Foo foo2 = child.getComponent(Foo.class);
051 assertNotNull(foo);
052 assertNotNull(foo2);
053 assertEquals(foo,foo2);
054 assertEquals("<Foo", sb.toString());
055 assertEquals("Stored:ConstructorInjector-class org.picocontainer.behaviors.StoringTestCase$Foo", child.getComponentAdapter(Foo.class).toString());
056 }
057
058 @Test public void testThatTwoThreadsHaveSeparatedCacheValues() {
059
060 final Foo[] foos = new Foo[4];
061 final int[] sizes = new int[2];
062
063 DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
064 final Storing storing = new Storing();
065 final DefaultPicoContainer child = new DefaultPicoContainer(storing, parent);
066
067 parent.addComponent(StringBuilder.class);
068 child.addComponent(Foo.class);
069
070 StringBuilder sb = parent.getComponent(StringBuilder.class);
071 assertEquals("store was not empty at outset for main thread", 0, storing.getCacheSize());
072 foos[0] = child.getComponent(Foo.class);
073
074 Thread thread = new Thread("other") {
075 public void run() {
076 sizes[0] = storing.getCacheSize();
077 foos[1] = child.getComponent(Foo.class);
078 foos[3] = child.getComponent(Foo.class);
079 sizes[1] = storing.getCacheSize();
080 }
081 };
082 thread.start();
083 foos[2] = child.getComponent(Foo.class);
084 assertEquals("store was not sized 1 at end for main thread", 1, storing.getCacheSize());
085
086 sleepALittle();
087
088 assertNotNull(foos[0]);
089 assertNotNull(foos[1]);
090 assertNotNull(foos[2]);
091 assertNotNull(foos[3]);
092 assertSame(foos[0],foos[2]);
093 assertEquals(foos[1],foos[3]);
094 assertFalse(foos[0] == foos[1]);
095 assertEquals("<Foo<Foo", sb.toString());
096 assertEquals("Stored:ConstructorInjector-class org.picocontainer.behaviors.StoringTestCase$Foo", child.getComponentAdapter(Foo.class).toString());
097
098 assertEquals("store was not empty at outset for other thread", 0, sizes[0]);
099 assertEquals("store was not sized 1 at end for other thread", 1, sizes[1]);
100 }
101
102 @Test public void testThatTwoThreadsHaveSeparatedCacheValuesForThreeScopeScenario() {
103
104 final Foo[] foos = new Foo[4];
105 final Bar[] bars = new Bar[4];
106
107 DefaultPicoContainer appScope = new DefaultPicoContainer(new Caching());
108 final DefaultPicoContainer sessionScope = new DefaultPicoContainer(new Storing(), appScope);
109 final DefaultPicoContainer requestScope = new DefaultPicoContainer(new Storing(), sessionScope);
110
111 appScope.addComponent(StringBuilder.class);
112 sessionScope.addComponent(Foo.class);
113 requestScope.addComponent(Bar.class);
114
115 StringBuilder sb = appScope.getComponent(StringBuilder.class);
116 foos[0] = sessionScope.getComponent(Foo.class);
117 bars[0] = requestScope.getComponent(Bar.class);
118
119 Thread thread = new Thread() {
120 public void run() {
121 foos[1] = sessionScope.getComponent(Foo.class);
122 bars[1] = requestScope.getComponent(Bar.class);
123 foos[3] = sessionScope.getComponent(Foo.class);
124 bars[3] = requestScope.getComponent(Bar.class);
125 }
126 };
127 thread.start();
128 foos[2] = sessionScope.getComponent(Foo.class);
129 bars[2] = requestScope.getComponent(Bar.class);
130 sleepALittle();
131
132 assertSame(bars[0],bars[2]);
133 assertEquals(bars[1],bars[3]);
134 assertFalse(bars[0] == bars[1]);
135 assertSame(bars[0].foo,foos[0]);
136 assertSame(bars[1].foo,foos[1]);
137 assertSame(bars[2].foo,foos[2]);
138 assertSame(bars[3].foo,foos[3]);
139 assertEquals("<Foo<Bar<Foo<Bar", sb.toString());
140 assertEquals("Stored:ConstructorInjector-class org.picocontainer.behaviors.StoringTestCase$Foo", sessionScope.getComponentAdapter(Foo.class).toString());
141 }
142
143 @Test public void testThatCacheMapCanBeReUsedOnASubsequentThreadSimulatingASessionConcept() {
144
145 final Foo[] foos = new Foo[4];
146
147 DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
148 final Storing storeCaching = new Storing();
149 final DefaultPicoContainer child = new DefaultPicoContainer(storeCaching, parent);
150
151 parent.addComponent(StringBuilder.class);
152 child.addComponent(Foo.class);
153
154 StringBuilder sb = parent.getComponent(StringBuilder.class);
155
156 final Storing.StoreWrapper[] tmpMap = new Storing.StoreWrapper[1];
157 Thread thread = new Thread() {
158 public void run() {
159 foos[0] = child.getComponent(Foo.class);
160 foos[1] = child.getComponent(Foo.class);
161 tmpMap[0] = storeCaching.getCacheForThread();
162
163 }
164 };
165 thread.start();
166 sleepALittle();
167 thread = new Thread() {
168 public void run() {
169 storeCaching.putCacheForThread(tmpMap[0]);
170 foos[2] = child.getComponent(Foo.class);
171 foos[3] = child.getComponent(Foo.class);
172 tmpMap[0] = storeCaching.getCacheForThread();
173
174 }
175 };
176 thread.start();
177 sleepALittle();
178
179 assertNotNull(foos[0]);
180 assertNotNull(foos[1]);
181 assertNotNull(foos[2]);
182 assertNotNull(foos[3]);
183 assertSame(foos[0],foos[1]);
184 assertSame(foos[1],foos[2]);
185 assertSame(foos[2],foos[3]);
186 assertEquals("<Foo", sb.toString());
187 assertEquals("Stored:ConstructorInjector-class org.picocontainer.behaviors.StoringTestCase$Foo", child.getComponentAdapter(Foo.class).toString());
188 }
189
190 @Test public void testThatCacheMapCanBeResetOnASubsequentThreadSimulatingASessionConcept() {
191
192
193 DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
194 final Storing storeCaching = new Storing();
195 final DefaultPicoContainer child = new DefaultPicoContainer(storeCaching, parent);
196
197 parent.addComponent(StringBuilder.class);
198 child.addComponent(Foo.class);
199
200 StringBuilder sb = parent.getComponent(StringBuilder.class);
201
202 Foo one = child.getComponent(Foo.class);
203 Foo two = child.getComponent(Foo.class);
204
205 assertNotNull(one);
206 assertNotNull(two);
207 assertSame(one,two);
208
209 assertTrue(storeCaching.resetCacheForThread() instanceof Storing.StoreWrapper);
210
211 Foo three = child.getComponent(Foo.class);
212 Foo four = child.getComponent(Foo.class);
213
214 assertNotNull(three);
215 assertNotNull(four);
216 assertNotSame(one,three);
217 assertSame(three,four);
218
219 assertEquals("<Foo<Foo", sb.toString());
220 assertEquals("Stored:ConstructorInjector-class org.picocontainer.behaviors.StoringTestCase$Foo", child.getComponentAdapter(Foo.class).toString());
221 }
222
223 @Test public void testThatCacheMapCanBeDisabledSimulatingAnEndedRequest() {
224
225 DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
226 final Storing storeCaching = new Storing();
227 final DefaultPicoContainer child = new DefaultPicoContainer(storeCaching, parent);
228
229 parent.addComponent(StringBuilder.class);
230 child.addComponent(Foo.class);
231
232 StringBuilder sb = parent.getComponent(StringBuilder.class);
233
234 Foo one = child.getComponent(Foo.class);
235 Foo two = child.getComponent(Foo.class);
236
237 assertNotNull(one);
238 assertNotNull(two);
239 assertSame(one,two);
240
241 storeCaching.invalidateCacheForThread();
242
243 try {
244 Foo three = child.getComponent(Foo.class);
245 fail("should have barfed");
246 } catch (UnsupportedOperationException e) {
247 // expected
248 }
249 }
250
251
252 private void sleepALittle() {
253 try {
254 Thread.sleep(100);
255 } catch (InterruptedException e) {
256 }
257 }
258
259
260 }