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