You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rd...@apache.org on 2004/01/05 21:56:16 UTC

cvs commit: jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale LocaleBeanificationTestCase.java LocaleConvertTestSuite.java

rdonkin     2004/01/05 12:56:16

  Modified:    beanutils/src/java/org/apache/commons/beanutils/locale
                        LocaleBeanUtilsBean.java
                        LocaleConvertUtilsBean.java
               beanutils/src/test/org/apache/commons/beanutils/locale
                        LocaleConvertTestSuite.java
  Added:       beanutils/src/test/org/apache/commons/beanutils/locale
                        LocaleBeanificationTestCase.java
  Log:
  Made LocaleBeanUtils a per context-classloader pseudo-singleton (like BeanUtils is). Thanks to flaviostutz for contributing the bones of the implementation.
  
  Revision  Changes    Path
  1.4       +117 -55   jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtilsBean.java
  
  Index: LocaleBeanUtilsBean.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/locale/LocaleBeanUtilsBean.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- LocaleBeanUtilsBean.java	9 Oct 2003 20:41:40 -0000	1.3
  +++ LocaleBeanUtilsBean.java	5 Jan 2004 20:56:16 -0000	1.4
  @@ -63,6 +63,7 @@
   
   
   import org.apache.commons.beanutils.*;
  +import org.apache.commons.beanutils.ContextClassLoaderLocal;
   import org.apache.commons.logging.Log;
   import org.apache.commons.logging.LogFactory;
   
  @@ -87,13 +88,30 @@
   
   public class LocaleBeanUtilsBean extends BeanUtilsBean {
   
  -    /** Singleton instance used by static methods */
  -    private static LocaleBeanUtilsBean singleton;
  -    
  -    /** Gets singleton instance */
  -    public static LocaleBeanUtilsBean getLocaleBeanUtilsInstance() {
  -        return singleton;
  -    }
  +	/** 
  +	 * Contains <code>LocaleBeanUtilsBean</code> instances indexed by context classloader.
  +	 */
  +    private static final ContextClassLoaderLocal 
  +            localeBeansByClassLoader = new ContextClassLoaderLocal() {
  +                        // Creates the default instance used when the context classloader is unavailable
  +                        protected Object initialValue() {
  +                            return new LocaleBeanUtilsBean();
  +                        }
  +                    };
  +     
  +     /** Gets singleton instance */
  +     public synchronized static LocaleBeanUtilsBean getLocaleBeanUtilsInstance() {
  +        return (LocaleBeanUtilsBean)localeBeansByClassLoader.get();
  +     }
  + 
  +	/** 
  +	 * Sets the instance which provides the functionality for {@link LocaleBeanUtils}.
  +	 * This is a pseudo-singleton - an single instance is provided per (thread) context classloader.
  +	 * This mechanism provides isolation for web apps deployed in the same container. 
  +	 */
  +	public synchronized static void setInstance(LocaleBeanUtilsBean newInstance) {
  +        localeBeansByClassLoader.set(newInstance);
  +	}
   
       /** All logging goes through this logger */
       private static Log log = LogFactory.getLog(LocaleBeanUtilsBean.class);
  @@ -107,7 +125,7 @@
       
       /** Construct instance with standard conversion bean */
       public LocaleBeanUtilsBean() {
  -        this.localeConvertUtils = LocaleConvertUtilsBean.getInstance();
  +        this.localeConvertUtils = new LocaleConvertUtilsBean();
       }
       
       /** 
  @@ -138,13 +156,13 @@
       
       // --------------------------------------------------------- Public Methods
       
  -    /** Gets bean used for conversions */
  +    /** Gets the bean instance used for conversions */
       public LocaleConvertUtilsBean getLocaleConvertUtils() {
           return localeConvertUtils;
       }
       
       /**
  -     * getter for defaultLocale
  +     * Gets the default Locale
        */
       public Locale getDefaultLocale() {
   
  @@ -153,7 +171,7 @@
   
   
       /**
  -     * setter for defaultLocale
  +     * Sets the default Locale
        */
       public void setDefaultLocale(Locale locale) {
   
  @@ -161,7 +179,7 @@
       }
   
       /**
  -     * getter for applyLocalized
  +     * Is the pattern to be applied localized
        * (Indicate whether the pattern is localized or not)
        */
       public boolean getApplyLocalized() {
  @@ -170,7 +188,7 @@
       }
   
       /**
  -     * setter for applyLocalized
  +     * Sets whether the pattern is applied localized
        * (Indicate whether the pattern is localized or not)
        */
       public void setApplyLocalized(boolean newApplyLocalized) {
  @@ -200,11 +218,16 @@
        * @exception NoSuchMethodException if an accessor method for this
        *  propety cannot be found
        */
  -    public String getIndexedProperty(Object bean, String name, String pattern)
  -            throws IllegalAccessException, InvocationTargetException,
  -            NoSuchMethodException {
  +    public String getIndexedProperty(
  +                                    Object bean, 
  +                                    String name, 
  +                                    String pattern)
  +                                        throws 
  +                                            IllegalAccessException, 
  +                                            InvocationTargetException,
  +                                            NoSuchMethodException {
   
  -        Object value = PropertyUtils.getIndexedProperty(bean, name);
  +        Object value = getPropertyUtils().getIndexedProperty(bean, name);
           return getLocaleConvertUtils().convert(value, pattern);
       }
   
  @@ -226,9 +249,13 @@
        * @exception NoSuchMethodException if an accessor method for this
        *  propety cannot be found
        */
  -    public String getIndexedProperty(Object bean, String name)
  -            throws IllegalAccessException, InvocationTargetException,
  -            NoSuchMethodException {
  +    public String getIndexedProperty(
  +                                    Object bean, 
  +                                    String name)
  +                                        throws 
  +                                            IllegalAccessException, 
  +                                            InvocationTargetException,
  +                                            NoSuchMethodException {
   
           return getIndexedProperty(bean, name, null);
       }
  @@ -256,7 +283,7 @@
               throws IllegalAccessException, InvocationTargetException,
               NoSuchMethodException {
   
  -        Object value = PropertyUtils.getIndexedProperty(bean, name, index);
  +        Object value = getPropertyUtils().getIndexedProperty(bean, name, index);
           return getLocaleConvertUtils().convert(value, pattern);
       }
   
  @@ -305,7 +332,7 @@
               throws IllegalAccessException, InvocationTargetException,
               NoSuchMethodException {
   
  -        Object value = PropertyUtils.getSimpleProperty(bean, name);
  +        Object value = getPropertyUtils().getSimpleProperty(bean, name);
           return getLocaleConvertUtils().convert(value, pattern);
       }
   
  @@ -349,12 +376,17 @@
        * @exception NoSuchMethodException if an accessor method for this
        *  propety cannot be found
        */
  -    public String getMappedProperty(Object bean,
  -                                           String name, String key, String pattern)
  -            throws IllegalAccessException, InvocationTargetException,
  -            NoSuchMethodException {
  +    public String getMappedProperty(
  +                                    Object bean,
  +                                    String name, 
  +                                    String key, 
  +                                    String pattern)
  +                                        throws 
  +                                            IllegalAccessException, 
  +                                            InvocationTargetException,
  +                                            NoSuchMethodException {
   
  -        Object value = PropertyUtils.getMappedProperty(bean, name, key);
  +        Object value = getPropertyUtils().getMappedProperty(bean, name, key);
           return getLocaleConvertUtils().convert(value, pattern);
       }
   
  @@ -404,11 +436,16 @@
        * @exception NoSuchMethodException if an accessor method for this
        *  propety cannot be found
        */
  -    public String getMappedPropertyLocale(Object bean, String name, String pattern)
  -            throws IllegalAccessException, InvocationTargetException,
  -            NoSuchMethodException {
  +    public String getMappedPropertyLocale(
  +                                        Object bean, 
  +                                        String name, 
  +                                        String pattern)
  +                                            throws 
  +                                                IllegalAccessException, 
  +                                                InvocationTargetException,
  +                                                NoSuchMethodException {
   
  -        Object value = PropertyUtils.getMappedProperty(bean, name);
  +        Object value = getPropertyUtils().getMappedProperty(bean, name);
           return getLocaleConvertUtils().convert(value, pattern);
       }
   
  @@ -434,8 +471,10 @@
        *  propety cannot be found
        */
       public String getMappedProperty(Object bean, String name)
  -            throws IllegalAccessException, InvocationTargetException,
  -            NoSuchMethodException {
  +                                    throws 
  +                                        IllegalAccessException, 
  +                                        InvocationTargetException,
  +                                        NoSuchMethodException {
   
           return getMappedPropertyLocale(bean, name, null);
       }
  @@ -458,11 +497,16 @@
        * @exception NoSuchMethodException if an accessor method for this
        *  propety cannot be found
        */
  -    public String getNestedProperty(Object bean, String name, String pattern)
  -            throws IllegalAccessException, InvocationTargetException,
  -            NoSuchMethodException {
  +    public String getNestedProperty(    
  +                                    Object bean, 
  +                                    String name, 
  +                                    String pattern)
  +                                        throws 
  +                                            IllegalAccessException, 
  +                                            InvocationTargetException,
  +                                            NoSuchMethodException {
   
  -        Object value = PropertyUtils.getNestedProperty(bean, name);
  +        Object value = getPropertyUtils().getNestedProperty(bean, name);
           return getLocaleConvertUtils().convert(value, pattern);
       }
   
  @@ -484,8 +528,10 @@
        *  propety cannot be found
        */
       public String getNestedProperty(Object bean, String name)
  -            throws IllegalAccessException, InvocationTargetException,
  -            NoSuchMethodException {
  +                                    throws 
  +                                        IllegalAccessException, 
  +                                        InvocationTargetException,
  +                                        NoSuchMethodException {
   
           return getNestedProperty(bean, name, null);
       }
  @@ -508,8 +554,10 @@
        *  propety cannot be found
        */
       public String getProperty(Object bean, String name, String pattern)
  -            throws IllegalAccessException, InvocationTargetException,
  -            NoSuchMethodException {
  +                                throws 
  +                                    IllegalAccessException, 
  +                                    InvocationTargetException,
  +                                    NoSuchMethodException {
   
           return getNestedProperty(bean, name, pattern);
       }
  @@ -532,8 +580,10 @@
        *  propety cannot be found
        */
       public String getProperty(Object bean, String name)
  -            throws IllegalAccessException, InvocationTargetException,
  -            NoSuchMethodException {
  +                                throws 
  +                                    IllegalAccessException, 
  +                                    InvocationTargetException,
  +                                    NoSuchMethodException {
   
           return getNestedProperty(bean, name);
       }
  @@ -553,7 +603,9 @@
        *  throws an exception
        */
       public void setProperty(Object bean, String name, Object value)
  -            throws IllegalAccessException, InvocationTargetException {
  +                                throws 
  +                                    IllegalAccessException, 
  +                                    InvocationTargetException {
   
           setProperty(bean, name, value, null);
       }
  @@ -573,8 +625,14 @@
        * @exception InvocationTargetException if the property accessor method
        *  throws an exception
        */
  -    public void setProperty(Object bean, String name, Object value, String pattern)
  -            throws IllegalAccessException, InvocationTargetException {
  +    public void setProperty(
  +                            Object bean, 
  +                            String name, 
  +                            Object value, 
  +                            String pattern)
  +                                throws 
  +                                    IllegalAccessException, 
  +                                    InvocationTargetException {
   
           // Trace logging (if enabled)
           if (log.isTraceEnabled()) {
  @@ -650,7 +708,7 @@
               PropertyDescriptor descriptor = null;
               try {
                   descriptor =
  -                        PropertyUtils.getPropertyDescriptor(target, name);
  +                        getPropertyUtils().getPropertyDescriptor(target, name);
                   if (descriptor == null) {
                       return null; // Skip this property setter
                   }
  @@ -683,7 +741,11 @@
        * @param pattern The convertion pattern
        */
       protected Object convert(Class type, int index, Object value, String pattern) {
  -
  +		
  +		if (log.isTraceEnabled()) {
  +			log.trace("Converting value '" + value + "' to type:" + type);
  +		}
  +		
           Object newValue = null;
   
           if (type.isArray() && (index < 0)) { // Scalar value into array
  @@ -798,15 +860,15 @@
   
           try {
               if (index >= 0) {
  -                PropertyUtils.setIndexedProperty(target, propName,
  +                getPropertyUtils().setIndexedProperty(target, propName,
                           index, newValue);
               }
               else if (key != null) {
  -                PropertyUtils.setMappedProperty(target, propName,
  +                getPropertyUtils().setMappedProperty(target, propName,
                           key, newValue);
               }
               else {
  -                PropertyUtils.setProperty(target, propName, newValue);
  +                getPropertyUtils().setProperty(target, propName, newValue);
               }
           }
           catch (NoSuchMethodException e) {
  @@ -838,7 +900,7 @@
           if (delim >= 0) {
               try {
                   target =
  -                        PropertyUtils.getProperty(bean, name.substring(0, delim));
  +                        getPropertyUtils().getProperty(bean, name.substring(0, delim));
               }
               catch (NoSuchMethodException e) {
                   return null; // Skip this property setter
  
  
  
  1.4       +16 -10    jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtilsBean.java
  
  Index: LocaleConvertUtilsBean.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/beanutils/src/java/org/apache/commons/beanutils/locale/LocaleConvertUtilsBean.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- LocaleConvertUtilsBean.java	9 Oct 2003 20:41:40 -0000	1.3
  +++ LocaleConvertUtilsBean.java	5 Jan 2004 20:56:16 -0000	1.4
  @@ -117,12 +117,12 @@
    */
   public class LocaleConvertUtilsBean {
       
  -    /** Singleton instance */
  -    private static final LocaleConvertUtilsBean singleton = new LocaleConvertUtilsBean();
  -    
  -    /** Gets singleton instance */
  +    /** 
  +     * Gets singleton instance.
  +     * This is the same as the instance used by the default {@link LocaleBeanUtilsBean} singleton.
  +     */
       public static LocaleConvertUtilsBean getInstance() {
  -        return singleton;
  +        return LocaleBeanUtilsBean.getLocaleBeanUtilsInstance().getLocaleConvertUtils();
       }
   
       // ----------------------------------------------------- Instance Variables
  @@ -228,7 +228,7 @@
       public String convert(Object value, Locale locale, String pattern) {
   
           LocaleConverter converter = lookup(String.class, locale);
  -
  +		
           return (String) converter.convert(String.class, value, pattern);
       }
   
  @@ -416,7 +416,13 @@
        */
       public LocaleConverter lookup(Class clazz, Locale locale) {
   
  -        return (LocaleConverter) lookup(locale).get(clazz);
  +        LocaleConverter converter = (LocaleConverter) lookup(locale).get(clazz);
  +        
  +        if (log.isTraceEnabled()) {
  +            log.trace("LocaleConverter:" + converter);
  +        }
  +        
  +        return converter;
       }
   
       /**
  
  
  
  1.4       +5 -4      jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale/LocaleConvertTestSuite.java
  
  Index: LocaleConvertTestSuite.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale/LocaleConvertTestSuite.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- LocaleConvertTestSuite.java	9 Oct 2003 20:39:04 -0000	1.3
  +++ LocaleConvertTestSuite.java	5 Jan 2004 20:56:16 -0000	1.4
  @@ -86,6 +86,7 @@
           TestSuite testSuite = new TestSuite();
           testSuite.addTestSuite(LocaleConvertUtilsTestCase.class);
           testSuite.addTestSuite(DateLocaleConverterTestCase.class);
  +        testSuite.addTestSuite(LocaleBeanificationTestCase.class);
           return testSuite;
       }
   }
  
  
  
  1.1                  jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale/LocaleBeanificationTestCase.java
  
  Index: LocaleBeanificationTestCase.java
  ===================================================================
  /*
   * $Header: /home/cvs/jakarta-commons/beanutils/src/test/org/apache/commons/beanutils/locale/LocaleBeanificationTestCase.java,v 1.1 2004/01/05 20:56:16 rdonkin Exp $
   * $Revision: 1.1 $
   * $Date: 2004/01/05 20:56:16 $
   *
   * ====================================================================
   * 
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgement:  
   *       "This product includes software developed by the 
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgement may appear in the software itself,
   *    if and wherever such third-party acknowledgements normally appear.
   *
   * 4. The names "Apache", "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache" nor may "Apache" appear in their names without prior 
   *    written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   */ 
  
  package org.apache.commons.beanutils.locale;
  
  import java.util.*;
  
  import java.lang.ref.WeakReference;
  import java.lang.ref.ReferenceQueue;
  
  import junit.framework.TestCase;
  import junit.framework.Test;
  import junit.framework.TestSuite;
  
  import org.apache.commons.collections.ReferenceMap;
  import org.apache.commons.logging.LogFactory;
  
  import org.apache.commons.beanutils.ContextClassLoaderLocal;
  import org.apache.commons.beanutils.PrimitiveBean;
  
  /**
   * <p>
   * Test Case for changes made during LocaleBeanutils Beanification.
   * This is basically a cut-and-correct version of the beanutils beanifications tests.
   * </p>
   *
   * @author Robert Burrell Donkin
   * @author Juozas Baliuka
   * @version $Revision: 1.1 $ $Date: 2004/01/05 20:56:16 $
   */
  
  public class LocaleBeanificationTestCase extends TestCase {
      
      // ---------------------------------------------------- Constants
      
      /** Maximum number of iterations before our test fails */
      public static final int MAX_GC_ITERATIONS = 50;
      
      // ---------------------------------------------------- Instance Variables
  
  
      // ---------------------------------------------------------- Constructors
  
  
      /**
       * Construct a new instance of this test case.
       *
       * @param name Name of the test case
       */
      public LocaleBeanificationTestCase(String name) {
          super(name);
      }
  
  
      // -------------------------------------------------- Overall Test Methods
  
  
      /**
       * Set up instance variables required by this test case.
       */
      public void setUp() {
  
          LocaleConvertUtils.deregister();
  
      }
  
  
      /**
       * Return the tests included in this test suite.
       */
      public static Test suite() {
          return (new TestSuite(LocaleBeanificationTestCase.class));
      }
  
  
      /**
       * Tear down instance variables required by this test case.
       */
      public void tearDown() {
          ;    // No action required
      }
  
  
      // ------------------------------------------------ Individual Test Methods
      
      /** Test of the methodology we'll use for some of the later tests */
      public void testMemoryTestMethodology() throws Exception {
          // test methodology
          // many thanks to Juozas Baliuka for suggesting this method
          ClassLoader loader = new ClassLoader() {};
          WeakReference reference = new  WeakReference(loader);
          Class myClass = loader.loadClass("org.apache.commons.beanutils.BetaBean");
          
          assertNotNull("Weak reference released early", reference.get());
          
          // dereference class loader and class:
          loader = null;
          myClass = null;
          
          int iterations = 0;
          int bytz = 2;
          while(true) {
              System.gc();
              if(iterations++ > MAX_GC_ITERATIONS){
                  fail("Max iterations reached before resource released.");
              }
              if( reference.get() == null ) {
                  break;
                  
              } else {
                  // create garbage:
                  byte[] b =  new byte[bytz];
                  bytz = bytz * 2;
              }
          }
      }
      
      /** Tests whether classloaders and beans are released from memory by the map used by beanutils */
      public void testMemoryLeak2() throws Exception {
          // tests when the map used by beanutils has the right behaviour
          
          if (isPre14JVM()) {
              System.out.println("WARNING: CANNOT TEST MEMORY LEAK ON PRE1.4 JVM");
              return;
          }
          
          // many thanks to Juozas Baliuka for suggesting this methodology
          TestClassLoader loader = new TestClassLoader();
          ReferenceQueue queue = new ReferenceQueue();
          WeakReference loaderReference = new WeakReference(loader, queue);
          Integer test = new Integer(1);
          
          WeakReference testReference = new WeakReference(test, queue);
          //Map map = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD, true);
          Map map = new WeakHashMap();
          map.put(loader, test);
          
          assertEquals("In map", test, map.get(loader));
          assertNotNull("Weak reference released early (1)", loaderReference.get());
          assertNotNull("Weak reference released early (2)", testReference.get());
          
          // dereference strong references
          loader = null;
          test = null;
          
          int iterations = 0;
          int bytz = 2;
          while(true) {
              System.gc();
              if(iterations++ > MAX_GC_ITERATIONS){
                  fail("Max iterations reached before resource released.");
              }
              map.isEmpty();
              
              if( 
                  loaderReference.get() == null &&
                  testReference.get() == null) {
                  break;
                  
              } else {
                  // create garbage:
                  byte[] b =  new byte[bytz];
                  bytz = bytz * 2;
              }
          }
      }
  	
      /** Tests whether classloaders and beans are released from memory */
      public void testMemoryLeak() throws Exception {
          if (isPre14JVM()) {
              System.out.println("WARNING: CANNOT TEST MEMORY LEAK ON PRE1.4 JVM");
              return;
          }
          
          // many thanks to Juozas Baliuka for suggesting this methodology
          TestClassLoader loader = new TestClassLoader();
          WeakReference loaderReference = new  WeakReference(loader);
          LocaleBeanUtilsBean.getLocaleBeanUtilsInstance();
  
          class GetBeanUtilsBeanThread extends Thread {
              
              LocaleBeanUtilsBean beanUtils;
              LocaleConvertUtilsBean convertUtils;
          
              GetBeanUtilsBeanThread() {}
              
              public void run() {
                  beanUtils = LocaleBeanUtilsBean.getLocaleBeanUtilsInstance();
                  convertUtils = LocaleConvertUtilsBean.getInstance();
                  // XXX Log keeps a reference around!
                  LogFactory.releaseAll();
              }
              
              public String toString() {
                  return "GetBeanUtilsBeanThread";
              }
          }
          
      
          GetBeanUtilsBeanThread thread = new GetBeanUtilsBeanThread();
          WeakReference threadWeakReference = new WeakReference(thread);
          thread.setContextClassLoader(loader);
  
          thread.start();
          thread.join();
          
          WeakReference beanUtilsReference = new WeakReference(thread.beanUtils);
          WeakReference convertUtilsReference = new WeakReference(thread.convertUtils);
          
          assertNotNull("Weak reference released early (1)", loaderReference.get());
          assertNotNull("Weak reference released early (2)", beanUtilsReference.get());
          assertNotNull("Weak reference released early (4)", convertUtilsReference.get());
          
          // dereference strong references
          loader = null;
          thread.setContextClassLoader(null);
          thread = null;
          
          int iterations = 0;
          int bytz = 2;
          while(true) {
              LocaleBeanUtilsBean.getLocaleBeanUtilsInstance();
              System.gc();
              if(iterations++ > MAX_GC_ITERATIONS){
                  fail("Max iterations reached before resource released.");
              }
  
              if( 
                  loaderReference.get() == null &&
                  beanUtilsReference.get() == null && 
                  convertUtilsReference.get() == null) {
                  break;
                  
              } else {
                  // create garbage:
                  byte[] b =  new byte[bytz];
                  bytz = bytz * 2;
              }
          }
      }
      
      /** 
       * Tests whether difference instances are loaded by different 
       * context classloaders.
       */
      public void testGetByContextClassLoader() throws Exception {
              
          class GetBeanUtilsBeanThread extends Thread {
              
              private Signal signal;
          
              GetBeanUtilsBeanThread(Signal signal) {
                  this.signal = signal;
              }
              
              public void run() {
                  signal.setSignal(2);
                  signal.setBean(LocaleBeanUtilsBean.getLocaleBeanUtilsInstance());
                  signal.setConvertUtils(LocaleConvertUtilsBean.getInstance());
              }
              
              public String toString() {
                  return "GetBeanUtilsBeanThread";
              }
          }
              
          Signal signal = new Signal();
          signal.setSignal(1);
          
          GetBeanUtilsBeanThread thread = new GetBeanUtilsBeanThread(signal);
          thread.setContextClassLoader(new TestClassLoader());
          
          thread.start();
          thread.join();
          
          assertEquals("Signal not set by test thread", 2, signal.getSignal());
          assertTrue(
                      "Different LocaleBeanUtilsBean instances per context classloader", 
                      LocaleBeanUtilsBean.getInstance() != signal.getBean());
          assertTrue(
                      "Different LocaleConvertUtilsBean instances per context classloader", 
                      LocaleConvertUtilsBean.getInstance() != signal.getConvertUtils());
      }
      
      
      /** 
       * Tests whether difference instances are loaded by different 
       * context classloaders.
       */
      public void testContextClassLoaderLocal() throws Exception {
              
          class CCLLTesterThread extends Thread {
              
              private Signal signal;
              private ContextClassLoaderLocal ccll;
          
              CCLLTesterThread(Signal signal, ContextClassLoaderLocal ccll) {
                  this.signal = signal;
                  this.ccll = ccll;
              }
              
              public void run() {
                  ccll.set(new Integer(1789));
                  signal.setSignal(2);
                  signal.setMarkerObject(ccll.get());
              }
              
              public String toString() {
                  return "CCLLTesterThread";
              }
          }
              
          ContextClassLoaderLocal ccll = new ContextClassLoaderLocal();
          ccll.set(new Integer(1776));
          assertEquals("Start thread sets value", new Integer(1776), ccll.get());  
          
          Signal signal = new Signal();
          signal.setSignal(1);
          
          CCLLTesterThread thread = new CCLLTesterThread(signal, ccll);
          thread.setContextClassLoader(new TestClassLoader());
          
          thread.start();
          thread.join();
          
          assertEquals("Signal not set by test thread", 2, signal.getSignal());     
          assertEquals("Second thread preserves value", new Integer(1776), ccll.get()); 
          assertEquals("Second thread gets value it set", new Integer(1789), signal.getMarkerObject()); 
      }
      
      /** Tests whether calls are independent for different classloaders */
      public void testContextClassloaderIndependence() throws Exception {
      
          class TestIndependenceThread extends Thread {
              private Signal signal;
              private PrimitiveBean bean;
          
              TestIndependenceThread(Signal signal, PrimitiveBean bean) {
                  this.signal = signal;
                  this.bean = bean;
              }
              
              public void run() {
                  try {
                      signal.setSignal(3);
                      LocaleConvertUtils.register(new LocaleConverter() {
  											public Object convert(Class type, Object value) {
                                                  return new Integer(9);
                                              }
                                              public Object convert(Class type, Object value, String pattern) {
                                                  return new Integer(9);
                                              }
                                                  }, Integer.TYPE, Locale.getDefault());
                      LocaleBeanUtils.setProperty(bean, "int", "1");
                  } catch (Exception e) {
                      e.printStackTrace();
                      signal.setException(e);
                  }
              }
              
              public String toString() {
                  return "TestIndependenceThread";
              }
          }
          
          PrimitiveBean bean = new PrimitiveBean();
          LocaleBeanUtils.setProperty(bean, "int", new Integer(1));
          assertEquals("Wrong property value (1)", 1, bean.getInt());
  
          LocaleConvertUtils.register(new LocaleConverter() {
  								public Object convert(Class type, Object value) {
                                      return new Integer(5);
                                  }
                                  public Object convert(Class type, Object value, String pattern) {
                                      return new Integer(5);
                                  }
                                      }, Integer.TYPE, Locale.getDefault());
          LocaleBeanUtils.setProperty(bean, "int", "1");
          assertEquals("Wrong property value(2)", 5, bean.getInt());
      
          Signal signal = new Signal();
          signal.setSignal(1);
          TestIndependenceThread thread = new TestIndependenceThread(signal, bean);
          thread.setContextClassLoader(new TestClassLoader());
          
          thread.start();
          thread.join();
          
          assertNull("Exception thrown by test thread:" + signal.getException(), signal.getException());
          assertEquals("Signal not set by test thread", 3, signal.getSignal());
          assertEquals("Wrong property value(3)", 9, bean.getInt());
          
      }
      
      /** Tests whether different threads can set beanutils instances correctly */
      public void testBeanUtilsBeanSetInstance() throws Exception {
              
          class SetInstanceTesterThread extends Thread {
              
              private Signal signal;
              private LocaleBeanUtilsBean bean;
          
              SetInstanceTesterThread(Signal signal, LocaleBeanUtilsBean bean) {
                  this.signal = signal;
                  this.bean = bean;
              }
              
              public void run() {
                  LocaleBeanUtilsBean.setInstance(bean);
                  signal.setSignal(21);
                  signal.setBean(LocaleBeanUtilsBean.getLocaleBeanUtilsInstance());
              }
              
              public String toString() {
                  return "SetInstanceTesterThread";
              }
          }
          
          Signal signal = new Signal();
          signal.setSignal(1);
  
          LocaleBeanUtilsBean beanOne = new LocaleBeanUtilsBean();
          LocaleBeanUtilsBean beanTwo = new LocaleBeanUtilsBean();
          
          SetInstanceTesterThread thread = new SetInstanceTesterThread(signal, beanTwo);
          thread.setContextClassLoader(new TestClassLoader());
          
          LocaleBeanUtilsBean.setInstance(beanOne);
          assertEquals("Start thread gets right instance", beanOne, LocaleBeanUtilsBean.getLocaleBeanUtilsInstance()); 
          
          thread.start();
          thread.join();
          
          assertEquals("Signal not set by test thread", 21, signal.getSignal());     
          assertEquals("Second thread preserves value", beanOne, LocaleBeanUtilsBean.getLocaleBeanUtilsInstance()); 
          assertEquals("Second thread gets value it set", beanTwo, signal.getBean()); 
      }
      
      /** Tests whether the unset method works*/
      public void testContextClassLoaderUnset() throws Exception {
          LocaleBeanUtilsBean beanOne = new LocaleBeanUtilsBean();
          ContextClassLoaderLocal ccll = new ContextClassLoaderLocal();
          ccll.set(beanOne);
          assertEquals("Start thread gets right instance", beanOne, ccll.get()); 
          ccll.unset();
          assertTrue("Unset works", !beanOne.equals(ccll.get())); 
      }
      
      private boolean isPre14JVM() {
          // some pre 1.4 JVM have buggy WeakHashMap implementations 
          // this is used to test for those JVM
          String version = System.getProperty("java.specification.version");
          StringTokenizer tokenizer = new StringTokenizer(version,".");
          if (tokenizer.nextToken().equals("1")) {
              String minorVersion = tokenizer.nextToken();
              if (minorVersion.equals("0")) return true;
              if (minorVersion.equals("1")) return true;
              if (minorVersion.equals("2")) return true;
              if (minorVersion.equals("3")) return true;
          }
          return false;
      }
      
      // ---- Auxillary classes
      
      class TestClassLoader extends ClassLoader {
          public String toString() {
              return "TestClassLoader";
          }
      }
      
      class Signal {
          private Exception e;
          private int signal = 0;
          private LocaleBeanUtilsBean bean;
          private LocaleConvertUtilsBean convertUtils;
          private Object marker;
          
          public Exception getException() {
              return e;
          }
          
          public void setException(Exception e) {
              this.e = e;
          }
          
          public int getSignal() {
              return signal;
          }
          
          public void setSignal(int signal) {
              this.signal = signal;
          }
          
          public Object getMarkerObject() {
              return marker;
          }
          
          public void setMarkerObject(Object marker) {
              this.marker = marker;
          }
          
          public LocaleBeanUtilsBean getBean() {
              return bean;
          }
          
          public void setBean(LocaleBeanUtilsBean bean) {
              this.bean = bean;
          }
          
          public LocaleConvertUtilsBean getConvertUtils() {
              return convertUtils;
          }
          
          public void setConvertUtils(LocaleConvertUtilsBean convertUtils) {
              this.convertUtils = convertUtils;
          }
      }
  }
  
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org