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