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 }