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