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    }