1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.beanutils.locale;
18
19 import java.util.*;
20
21 import java.lang.ref.WeakReference;
22 import java.lang.ref.ReferenceQueue;
23
24 import junit.framework.TestCase;
25 import junit.framework.Test;
26 import junit.framework.TestSuite;
27
28 import org.apache.commons.collections.ReferenceMap;
29 import org.apache.commons.logging.LogFactory;
30
31 import org.apache.commons.beanutils.ContextClassLoaderLocal;
32 import org.apache.commons.beanutils.PrimitiveBean;
33
34 /**
35 * <p>
36 * Test Case for changes made during LocaleBeanutils Beanification.
37 * This is basically a cut-and-correct version of the beanutils beanifications tests.
38 * </p>
39 *
40 * @author Robert Burrell Donkin
41 * @author Juozas Baliuka
42 * @version $Revision: 1.2 $ $Date: 2004/02/28 13:18:37 $
43 */
44
45 public class LocaleBeanificationTestCase extends TestCase {
46
47
48
49 /** Maximum number of iterations before our test fails */
50 public static final int MAX_GC_ITERATIONS = 50;
51
52
53
54
55
56
57
58 /**
59 * Construct a new instance of this test case.
60 *
61 * @param name Name of the test case
62 */
63 public LocaleBeanificationTestCase(String name) {
64 super(name);
65 }
66
67
68
69
70
71 /**
72 * Set up instance variables required by this test case.
73 */
74 public void setUp() {
75
76 LocaleConvertUtils.deregister();
77
78 }
79
80
81 /**
82 * Return the tests included in this test suite.
83 */
84 public static Test suite() {
85 return (new TestSuite(LocaleBeanificationTestCase.class));
86 }
87
88
89 /**
90 * Tear down instance variables required by this test case.
91 */
92 public void tearDown() {
93 ;
94 }
95
96
97
98
99 /** Test of the methodology we'll use for some of the later tests */
100 public void testMemoryTestMethodology() throws Exception {
101
102
103 ClassLoader loader = new ClassLoader(this.getClass().getClassLoader()) {};
104 WeakReference reference = new WeakReference(loader);
105 Class myClass = loader.loadClass("org.apache.commons.beanutils.BetaBean");
106
107 assertNotNull("Weak reference released early", reference.get());
108
109
110 loader = null;
111 myClass = null;
112
113 int iterations = 0;
114 int bytz = 2;
115 while(true) {
116 System.gc();
117 if(iterations++ > MAX_GC_ITERATIONS){
118 fail("Max iterations reached before resource released.");
119 }
120 if( reference.get() == null ) {
121 break;
122
123 } else {
124
125 byte[] b = new byte[bytz];
126 bytz = bytz * 2;
127 }
128 }
129 }
130
131 /** Tests whether classloaders and beans are released from memory by the map used by beanutils */
132 public void testMemoryLeak2() throws Exception {
133
134
135 if (isPre14JVM()) {
136 System.out.println("WARNING: CANNOT TEST MEMORY LEAK ON PRE1.4 JVM");
137 return;
138 }
139
140
141 TestClassLoader loader = new TestClassLoader();
142 ReferenceQueue queue = new ReferenceQueue();
143 WeakReference loaderReference = new WeakReference(loader, queue);
144 Integer test = new Integer(1);
145
146 WeakReference testReference = new WeakReference(test, queue);
147
148 Map map = new WeakHashMap();
149 map.put(loader, test);
150
151 assertEquals("In map", test, map.get(loader));
152 assertNotNull("Weak reference released early (1)", loaderReference.get());
153 assertNotNull("Weak reference released early (2)", testReference.get());
154
155
156 loader = null;
157 test = null;
158
159 int iterations = 0;
160 int bytz = 2;
161 while(true) {
162 System.gc();
163 if(iterations++ > MAX_GC_ITERATIONS){
164 fail("Max iterations reached before resource released.");
165 }
166 map.isEmpty();
167
168 if(
169 loaderReference.get() == null &&
170 testReference.get() == null) {
171 break;
172
173 } else {
174
175 byte[] b = new byte[bytz];
176 bytz = bytz * 2;
177 }
178 }
179 }
180
181 /** Tests whether classloaders and beans are released from memory */
182 public void testMemoryLeak() throws Exception {
183 if (isPre14JVM()) {
184 System.out.println("WARNING: CANNOT TEST MEMORY LEAK ON PRE1.4 JVM");
185 return;
186 }
187
188
189 TestClassLoader loader = new TestClassLoader();
190 WeakReference loaderReference = new WeakReference(loader);
191 LocaleBeanUtilsBean.getLocaleBeanUtilsInstance();
192
193 class GetBeanUtilsBeanThread extends Thread {
194
195 LocaleBeanUtilsBean beanUtils;
196 LocaleConvertUtilsBean convertUtils;
197
198 GetBeanUtilsBeanThread() {}
199
200 public void run() {
201 beanUtils = LocaleBeanUtilsBean.getLocaleBeanUtilsInstance();
202 convertUtils = LocaleConvertUtilsBean.getInstance();
203
204 LogFactory.releaseAll();
205 }
206
207 public String toString() {
208 return "GetBeanUtilsBeanThread";
209 }
210 }
211
212
213 GetBeanUtilsBeanThread thread = new GetBeanUtilsBeanThread();
214 WeakReference threadWeakReference = new WeakReference(thread);
215 thread.setContextClassLoader(loader);
216
217 thread.start();
218 thread.join();
219
220 WeakReference beanUtilsReference = new WeakReference(thread.beanUtils);
221 WeakReference convertUtilsReference = new WeakReference(thread.convertUtils);
222
223 assertNotNull("Weak reference released early (1)", loaderReference.get());
224 assertNotNull("Weak reference released early (2)", beanUtilsReference.get());
225 assertNotNull("Weak reference released early (4)", convertUtilsReference.get());
226
227
228 loader = null;
229 thread.setContextClassLoader(null);
230 thread = null;
231
232 int iterations = 0;
233 int bytz = 2;
234 while(true) {
235 LocaleBeanUtilsBean.getLocaleBeanUtilsInstance();
236 System.gc();
237 if(iterations++ > MAX_GC_ITERATIONS){
238 fail("Max iterations reached before resource released.");
239 }
240
241 if(
242 loaderReference.get() == null &&
243 beanUtilsReference.get() == null &&
244 convertUtilsReference.get() == null) {
245 break;
246
247 } else {
248
249 byte[] b = new byte[bytz];
250 bytz = bytz * 2;
251 }
252 }
253 }
254
255 /**
256 * Tests whether difference instances are loaded by different
257 * context classloaders.
258 */
259 public void testGetByContextClassLoader() throws Exception {
260
261 class GetBeanUtilsBeanThread extends Thread {
262
263 private Signal signal;
264
265 GetBeanUtilsBeanThread(Signal signal) {
266 this.signal = signal;
267 }
268
269 public void run() {
270 signal.setSignal(2);
271 signal.setBean(LocaleBeanUtilsBean.getLocaleBeanUtilsInstance());
272 signal.setConvertUtils(LocaleConvertUtilsBean.getInstance());
273 }
274
275 public String toString() {
276 return "GetBeanUtilsBeanThread";
277 }
278 }
279
280 Signal signal = new Signal();
281 signal.setSignal(1);
282
283 GetBeanUtilsBeanThread thread = new GetBeanUtilsBeanThread(signal);
284 thread.setContextClassLoader(new TestClassLoader());
285
286 thread.start();
287 thread.join();
288
289 assertEquals("Signal not set by test thread", 2, signal.getSignal());
290 assertTrue(
291 "Different LocaleBeanUtilsBean instances per context classloader",
292 LocaleBeanUtilsBean.getInstance() != signal.getBean());
293 assertTrue(
294 "Different LocaleConvertUtilsBean instances per context classloader",
295 LocaleConvertUtilsBean.getInstance() != signal.getConvertUtils());
296 }
297
298
299 /**
300 * Tests whether difference instances are loaded by different
301 * context classloaders.
302 */
303 public void testContextClassLoaderLocal() throws Exception {
304
305 class CCLLTesterThread extends Thread {
306
307 private Signal signal;
308 private ContextClassLoaderLocal ccll;
309
310 CCLLTesterThread(Signal signal, ContextClassLoaderLocal ccll) {
311 this.signal = signal;
312 this.ccll = ccll;
313 }
314
315 public void run() {
316 ccll.set(new Integer(1789));
317 signal.setSignal(2);
318 signal.setMarkerObject(ccll.get());
319 }
320
321 public String toString() {
322 return "CCLLTesterThread";
323 }
324 }
325
326 ContextClassLoaderLocal ccll = new ContextClassLoaderLocal();
327 ccll.set(new Integer(1776));
328 assertEquals("Start thread sets value", new Integer(1776), ccll.get());
329
330 Signal signal = new Signal();
331 signal.setSignal(1);
332
333 CCLLTesterThread thread = new CCLLTesterThread(signal, ccll);
334 thread.setContextClassLoader(new TestClassLoader());
335
336 thread.start();
337 thread.join();
338
339 assertEquals("Signal not set by test thread", 2, signal.getSignal());
340 assertEquals("Second thread preserves value", new Integer(1776), ccll.get());
341 assertEquals("Second thread gets value it set", new Integer(1789), signal.getMarkerObject());
342 }
343
344 /** Tests whether calls are independent for different classloaders */
345 public void testContextClassloaderIndependence() throws Exception {
346
347 class TestIndependenceThread extends Thread {
348 private Signal signal;
349 private PrimitiveBean bean;
350
351 TestIndependenceThread(Signal signal, PrimitiveBean bean) {
352 this.signal = signal;
353 this.bean = bean;
354 }
355
356 public void run() {
357 try {
358 signal.setSignal(3);
359 LocaleConvertUtils.register(new LocaleConverter() {
360 public Object convert(Class type, Object value) {
361 return new Integer(9);
362 }
363 public Object convert(Class type, Object value, String pattern) {
364 return new Integer(9);
365 }
366 }, Integer.TYPE, Locale.getDefault());
367 LocaleBeanUtils.setProperty(bean, "int", "1");
368 } catch (Exception e) {
369 e.printStackTrace();
370 signal.setException(e);
371 }
372 }
373
374 public String toString() {
375 return "TestIndependenceThread";
376 }
377 }
378
379 PrimitiveBean bean = new PrimitiveBean();
380 LocaleBeanUtils.setProperty(bean, "int", new Integer(1));
381 assertEquals("Wrong property value (1)", 1, bean.getInt());
382
383 LocaleConvertUtils.register(new LocaleConverter() {
384 public Object convert(Class type, Object value) {
385 return new Integer(5);
386 }
387 public Object convert(Class type, Object value, String pattern) {
388 return new Integer(5);
389 }
390 }, Integer.TYPE, Locale.getDefault());
391 LocaleBeanUtils.setProperty(bean, "int", "1");
392 assertEquals("Wrong property value(2)", 5, bean.getInt());
393
394 Signal signal = new Signal();
395 signal.setSignal(1);
396 TestIndependenceThread thread = new TestIndependenceThread(signal, bean);
397 thread.setContextClassLoader(new TestClassLoader());
398
399 thread.start();
400 thread.join();
401
402 assertNull("Exception thrown by test thread:" + signal.getException(), signal.getException());
403 assertEquals("Signal not set by test thread", 3, signal.getSignal());
404 assertEquals("Wrong property value(3)", 9, bean.getInt());
405
406 }
407
408 /** Tests whether different threads can set beanutils instances correctly */
409 public void testBeanUtilsBeanSetInstance() throws Exception {
410
411 class SetInstanceTesterThread extends Thread {
412
413 private Signal signal;
414 private LocaleBeanUtilsBean bean;
415
416 SetInstanceTesterThread(Signal signal, LocaleBeanUtilsBean bean) {
417 this.signal = signal;
418 this.bean = bean;
419 }
420
421 public void run() {
422 LocaleBeanUtilsBean.setInstance(bean);
423 signal.setSignal(21);
424 signal.setBean(LocaleBeanUtilsBean.getLocaleBeanUtilsInstance());
425 }
426
427 public String toString() {
428 return "SetInstanceTesterThread";
429 }
430 }
431
432 Signal signal = new Signal();
433 signal.setSignal(1);
434
435 LocaleBeanUtilsBean beanOne = new LocaleBeanUtilsBean();
436 LocaleBeanUtilsBean beanTwo = new LocaleBeanUtilsBean();
437
438 SetInstanceTesterThread thread = new SetInstanceTesterThread(signal, beanTwo);
439 thread.setContextClassLoader(new TestClassLoader());
440
441 LocaleBeanUtilsBean.setInstance(beanOne);
442 assertEquals("Start thread gets right instance", beanOne, LocaleBeanUtilsBean.getLocaleBeanUtilsInstance());
443
444 thread.start();
445 thread.join();
446
447 assertEquals("Signal not set by test thread", 21, signal.getSignal());
448 assertEquals("Second thread preserves value", beanOne, LocaleBeanUtilsBean.getLocaleBeanUtilsInstance());
449 assertEquals("Second thread gets value it set", beanTwo, signal.getBean());
450 }
451
452 /** Tests whether the unset method works*/
453 public void testContextClassLoaderUnset() throws Exception {
454 LocaleBeanUtilsBean beanOne = new LocaleBeanUtilsBean();
455 ContextClassLoaderLocal ccll = new ContextClassLoaderLocal();
456 ccll.set(beanOne);
457 assertEquals("Start thread gets right instance", beanOne, ccll.get());
458 ccll.unset();
459 assertTrue("Unset works", !beanOne.equals(ccll.get()));
460 }
461
462 private boolean isPre14JVM() {
463
464
465 String version = System.getProperty("java.specification.version");
466 StringTokenizer tokenizer = new StringTokenizer(version,".");
467 if (tokenizer.nextToken().equals("1")) {
468 String minorVersion = tokenizer.nextToken();
469 if (minorVersion.equals("0")) return true;
470 if (minorVersion.equals("1")) return true;
471 if (minorVersion.equals("2")) return true;
472 if (minorVersion.equals("3")) return true;
473 }
474 return false;
475 }
476
477
478
479 class TestClassLoader extends ClassLoader {
480 public String toString() {
481 return "TestClassLoader";
482 }
483 }
484
485 class Signal {
486 private Exception e;
487 private int signal = 0;
488 private LocaleBeanUtilsBean bean;
489 private LocaleConvertUtilsBean convertUtils;
490 private Object marker;
491
492 public Exception getException() {
493 return e;
494 }
495
496 public void setException(Exception e) {
497 this.e = e;
498 }
499
500 public int getSignal() {
501 return signal;
502 }
503
504 public void setSignal(int signal) {
505 this.signal = signal;
506 }
507
508 public Object getMarkerObject() {
509 return marker;
510 }
511
512 public void setMarkerObject(Object marker) {
513 this.marker = marker;
514 }
515
516 public LocaleBeanUtilsBean getBean() {
517 return bean;
518 }
519
520 public void setBean(LocaleBeanUtilsBean bean) {
521 this.bean = bean;
522 }
523
524 public LocaleConvertUtilsBean getConvertUtils() {
525 return convertUtils;
526 }
527
528 public void setConvertUtils(LocaleConvertUtilsBean convertUtils) {
529 this.convertUtils = convertUtils;
530 }
531 }
532 }
533