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 *****************************************************************************/
010package org.picocontainer.behaviors;
011
012import static org.junit.Assert.assertEquals;
013import static org.junit.Assert.assertFalse;
014import static org.junit.Assert.assertNotNull;
015import static org.junit.Assert.assertNotSame;
016import static org.junit.Assert.assertSame;
017import static org.junit.Assert.assertTrue;
018import static org.junit.Assert.fail;
019
020import org.junit.Test;
021import org.picocontainer.DefaultPicoContainer;
022import org.picocontainer.containers.EmptyPicoContainer;
023import org.picocontainer.lifecycle.NullLifecycleStrategy;
024
025public 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}