    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    }