Collections Java Tutorial

/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * ---------------------
 * ReadOnlyIterator.java
 * ---------------------
 * (C)opyright 2003-2008, by Thomas Morgner and Contributors.
 *
 * Original Author:  Thomas Morgner;
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *
 * $Id: ResourceBundleSupport.java,v 1.12 2008/12/18 09:57:32 mungady Exp $
 *
 * Changes
 * -------
 * 18-Dec-2008 : Use ResourceBundleWrapper - see JFreeChart patch 1607918 by
 *               Jess Thrysoee (DG);
 *
 */
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLClassLoader;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JMenu;
import javax.swing.KeyStroke;
import sun.rmi.runtime.Log;
/**
 * An utility class to ease up using property-file resource bundles.
 * 


 * The class support references within the resource bundle set to minimize the
 * occurence of duplicate keys. References are given in the format:
 * 


 * a.key.name=@referenced.key
 * 

 * 


 * A lookup to a key in an other resource bundle should be written by
 * 


 * a.key.name=@@resourcebundle_name@referenced.key
 * 

 *
 * @author Thomas Morgner
 */
public class ResourceBundleSupport
{
  /**
   * The resource bundle that will be used for local lookups.
   */
  private ResourceBundle resources;
  /**
   * A cache for string values, as looking up the cache is faster than looking
   * up the value in the bundle.
   */
  private TreeMap cache;
  /**
   * The current lookup path when performing non local lookups. This prevents
   * infinite loops during such lookups.
   */
  private TreeSet lookupPath;
  /**
   * The name of the local resource bundle.
   */
  private String resourceBase;
  /**
   * The locale for this bundle.
   */
  private Locale locale;
  /**
   * Creates a new instance.
   *
   * @param locale  the locale.
   * @param baseName the base name of the resource bundle, a fully qualified
   *                 class name
   */
  public ResourceBundleSupport(final Locale locale, final String baseName)
  {
    this(locale, ResourceBundleWrapper.getBundle(baseName, locale), baseName);
  }
  /**
   * Creates a new instance.
   *
   * @param locale         the locale for which this resource bundle is
   *                       created.
   * @param resourceBundle the resourcebundle
   * @param baseName       the base name of the resource bundle, a fully
   *                       qualified class name
   */
  protected ResourceBundleSupport(final Locale locale,
                                  final ResourceBundle resourceBundle,
                                  final String baseName)
  {
    if (locale == null)
    {
      throw new NullPointerException("Locale must not be null");
    }
    if (resourceBundle == null)
    {
      throw new NullPointerException("Resources must not be null");
    }
    if (baseName == null)
    {
      throw new NullPointerException("BaseName must not be null");
    }
    this.locale = locale;
    this.resources = resourceBundle;
    this.resourceBase = baseName;
    this.cache = new TreeMap();
    this.lookupPath = new TreeSet();
  }
  /**
   * Creates a new instance.
   *
   * @param locale         the locale for which the resource bundle is
   *                       created.
   * @param resourceBundle the resourcebundle
   */
  public ResourceBundleSupport(final Locale locale,
                               final ResourceBundle resourceBundle)
  {
    this(locale, resourceBundle, resourceBundle.toString());
  }
  /**
   * Creates a new instance.
   *
   * @param baseName the base name of the resource bundle, a fully qualified
   *                 class name
   */
  public ResourceBundleSupport(final String baseName)
  {
    this(Locale.getDefault(), ResourceBundleWrapper.getBundle(baseName),
            baseName);
  }
  /**
   * Creates a new instance.
   *
   * @param resourceBundle the resourcebundle
   * @param baseName       the base name of the resource bundle, a fully
   *                       qualified class name
   */
  protected ResourceBundleSupport(final ResourceBundle resourceBundle,
                                  final String baseName)
  {
    this(Locale.getDefault(), resourceBundle, baseName);
  }
  /**
   * Creates a new instance.
   *
   * @param resourceBundle the resourcebundle
   */
  public ResourceBundleSupport(final ResourceBundle resourceBundle)
  {
    this(Locale.getDefault(), resourceBundle, resourceBundle.toString());
  }
  /**
   * The base name of the resource bundle.
   *
   * @return the resource bundle's name.
   */
  protected final String getResourceBase()
  {
    return this.resourceBase;
  }
  /**
   * Gets a string for the given key from this resource bundle or one of its
   * parents. If the key is a link, the link is resolved and the referenced
   * string is returned instead.
   *
   * @param key the key for the desired string
   * @return the string for the given key
   * @throws NullPointerException     if key is null
   * @throws MissingResourceException if no object for the given key can be
   *                                  found
   * @throws ClassCastException       if the object found for the given key is
   *                                  not a string
   */
  public synchronized String getString(final String key)
  {
    final String retval = (String) this.cache.get(key);
    if (retval != null)
    {
      return retval;
    }
    this.lookupPath.clear();
    return internalGetString(key);
  }
  /**
   * Performs the lookup for the given key. If the key points to a link the
   * link is resolved and that key is looked up instead.
   *
   * @param key the key for the string
   * @return the string for the given key
   */
  protected String internalGetString(final String key)
  {
    if (this.lookupPath.contains(key))
    {
      throw new MissingResourceException
          ("InfiniteLoop in resource lookup",
              getResourceBase(), this.lookupPath.toString());
    }
    final String fromResBundle = this.resources.getString(key);
    if (fromResBundle.startsWith("@@"))
    {
      // global forward ...
      final int idx = fromResBundle.indexOf('@', 2);
      if (idx == -1)
      {
        throw new MissingResourceException
            ("Invalid format for global lookup key.", getResourceBase(), key);
      }
      try
      {
        final ResourceBundle res = ResourceBundleWrapper.getBundle
            (fromResBundle.substring(2, idx));
        return res.getString(fromResBundle.substring(idx + 1));
      }
      catch (Exception e)
      {
        System.out.println("Error during global lookup:"+ e);
        throw new MissingResourceException
            ("Error during global lookup", getResourceBase(), key);
      }
    }
    else if (fromResBundle.startsWith("@"))
    {
      // local forward ...
      final String newKey = fromResBundle.substring(1);
      this.lookupPath.add(key);
      final String retval = internalGetString(newKey);
      this.cache.put(key, retval);
      return retval;
    }
    else
    {
      this.cache.put(key, fromResBundle);
      return fromResBundle;
    }
  }
  /**
   * Returns an scaled icon suitable for buttons or menus.
   *
   * @param key   the name of the resource bundle key
   * @param large true, if the image should be scaled to 24x24, or false for
   *              16x16
   * @return the icon.
   */
  public Icon getIcon(final String key, final boolean large)
  {
    final String name = getString(key);
    return createIcon(name, true, large);
  }
  /**
   * Returns an unscaled icon.
   *
   * @param key the name of the resource bundle key
   * @return the icon.
   */
  public Icon getIcon(final String key)
  {
    final String name = getString(key);
    return createIcon(name, false, false);
  }
  /**
   * Returns the mnemonic stored at the given resourcebundle key. The mnemonic
   * should be either the symbolic name of one of the KeyEvent.VK_* constants
   * (without the 'VK_') or the character for that key.
   * 


   * For the enter key, the resource bundle would therefore either contain
   * "ENTER" or "\n".
   * 


   * a.resourcebundle.key=ENTER
   * an.other.resourcebundle.key=\n
   * 

   *
   * @param key the resourcebundle key
   * @return the mnemonic
   */
  public Integer getMnemonic(final String key)
  {
    final String name = getString(key);
    return createMnemonic(name);
  }
  /**
   * Returns an optional mnemonic.
   *
   * @param key  the key.
   *
   * @return The mnemonic.
   */
  public Integer getOptionalMnemonic(final String key)
  {
    final String name = getString(key);
    if (name != null && name.length() > 0)
    {
      return createMnemonic(name);
    }
    return null;
  }
  /**
   * Returns the keystroke stored at the given resourcebundle key.
   * 


   * The keystroke will be composed of a simple key press and the plattform's
   * MenuKeyMask.
   * 


   * The keystrokes character key should be either the symbolic name of one of
   * the KeyEvent.VK_* constants or the character for that key.
   * 


   * For the 'A' key, the resource bundle would therefore either contain
   * "VK_A" or "a".
   * 


   * a.resourcebundle.key=VK_A
   * an.other.resourcebundle.key=a
   * 

   *
   * @param key the resourcebundle key
   * @return the mnemonic
   * @see Toolkit#getMenuShortcutKeyMask()
   */
  public KeyStroke getKeyStroke(final String key)
  {
    return getKeyStroke(key, getMenuKeyMask());
  }
  /**
   * Returns an optional key stroke.
   *
   * @param key  the key.
   *
   * @return The key stroke.
   */
  public KeyStroke getOptionalKeyStroke(final String key)
  {
    return getOptionalKeyStroke(key, getMenuKeyMask());
  }
  /**
   * Returns the keystroke stored at the given resourcebundle key.
   * 


   * The keystroke will be composed of a simple key press and the given
   * KeyMask. If the KeyMask is zero, a plain Keystroke is returned.
   * 


   * The keystrokes character key should be either the symbolic name of one of
   * the KeyEvent.VK_* constants or the character for that key.
   * 


   * For the 'A' key, the resource bundle would therefore either contain
   * "VK_A" or "a".
   * 


   * a.resourcebundle.key=VK_A
   * an.other.resourcebundle.key=a
   * 

   *
   * @param key the resourcebundle key.
   * @param mask  the mask.
   *
   * @return the mnemonic
   * @see Toolkit#getMenuShortcutKeyMask()
   */
  public KeyStroke getKeyStroke(final String key, final int mask)
  {
    final String name = getString(key);
    return KeyStroke.getKeyStroke(createMnemonic(name).intValue(), mask);
  }
  /**
   * Returns an optional key stroke.
   *
   * @param key  the key.
   * @param mask  the mask.
   *
   * @return The key stroke.
   */
  public KeyStroke getOptionalKeyStroke(final String key, final int mask)
  {
    final String name = getString(key);
    if (name != null && name.length() > 0)
    {
      return KeyStroke.getKeyStroke(createMnemonic(name).intValue(), mask);
    }
    return null;
  }
  /**
   * Returns a JMenu created from a resource bundle definition.
   * 


   * The menu definition consists of two keys, the name of the menu and the
   * mnemonic for that menu. Both keys share a common prefix, which is
   * extended by ".name" for the name of the menu and ".mnemonic" for the
   * mnemonic.
   * 


   * 


   * # define the file menu
   * menu.file.name=File
   * menu.file.mnemonic=F
   * 

   * The menu definition above can be used to create the menu by calling
   * createMenu ("menu.file").
   *
   * @param keyPrefix the common prefix for that menu
   * @return the created menu
   */
  public JMenu createMenu(final String keyPrefix)
  {
    final JMenu retval = new JMenu();
    retval.setText(getString(keyPrefix + ".name"));
    retval.setMnemonic(getMnemonic(keyPrefix + ".mnemonic").intValue());
    return retval;
  }
  /**
   * Returns a URL pointing to a resource located in the classpath. The
   * resource is looked up using the given key.
   * 


   * Example: The load a file named 'logo.gif' which is stored in a java
   * package named 'org.jfree.resources':
   * 


   * mainmenu.logo=org/jfree/resources/logo.gif
   * 

   * The URL for that file can be queried with: getResource("mainmenu.logo");.
   *
   * @param key the key for the resource
   * @return the resource URL
   */
  public URL getResourceURL(final String key)
  {
    final String name = getString(key);
    final URL in = ObjectUtilities.getResource(name, ResourceBundleSupport.class);
    if (in == null)
    {
      System.out.println("Unable to find file in the class path: " + name + "; key=" + key);
    }
    return in;
  }
  /**
   * Attempts to load an image from classpath. If this fails, an empty image
   * icon is returned.
   *
   * @param resourceName the name of the image. The name should be a global
   *                     resource name.
   * @param scale        true, if the image should be scaled, false otherwise
   * @param large        true, if the image should be scaled to 24x24, or
   *                     false for 16x16
   * @return the image icon.
   */
  private ImageIcon createIcon(final String resourceName, final boolean scale,
                               final boolean large)
  {
    final URL in = ObjectUtilities.getResource(resourceName, ResourceBundleSupport.class);
    ;
    if (in == null)
    {
      System.out.println("Unable to find file in the class path: " + resourceName);
      return new ImageIcon(createTransparentImage(1, 1));
    }
    final Image img = Toolkit.getDefaultToolkit().createImage(in);
    if (img == null)
    {
      System.out.println("Unable to instantiate the image: " + resourceName);
      return new ImageIcon(createTransparentImage(1, 1));
    }
    if (scale)
    {
      if (large)
      {
        return new ImageIcon(img.getScaledInstance(24, 24, Image.SCALE_SMOOTH));
      }
      return new ImageIcon(img.getScaledInstance(16, 16, Image.SCALE_SMOOTH));
    }
    return new ImageIcon(img);
  }
  /**
   * Creates the Mnemonic from the given String. The String consists of the
   * name of the VK constants of the class KeyEvent without VK_*.
   *
   * @param keyString the string
   * @return the mnemonic as integer
   */
  private Integer createMnemonic(final String keyString)
  {
    if (keyString == null)
    {
      throw new NullPointerException("Key is null.");
    }
    if (keyString.length() == 0)
    {
      throw new IllegalArgumentException("Key is empty.");
    }
    int character = keyString.charAt(0);
    if (keyString.startsWith("VK_"))
    {
      try
      {
        final Field f = KeyEvent.class.getField(keyString);
        final Integer keyCode = (Integer) f.get(null);
        character = keyCode.intValue();
      }
      catch (Exception nsfe)
      {
        // ignore the exception ...
      }
    }
    return new Integer(character);
  }
  /**
   * Returns the plattforms default menu shortcut keymask.
   *
   * @return the default key mask.
   */
  private int getMenuKeyMask()
  {
    try
    {
      return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
    }
    catch (UnsupportedOperationException he)
    {
      // headless exception extends UnsupportedOperation exception,
      // but the HeadlessException is not defined in older JDKs...
      return InputEvent.CTRL_MASK;
    }
  }
  /**
   * Creates a transparent image.  These can be used for aligning menu items.
   *
   * @param width  the width.
   * @param height the height.
   * @return the created transparent image.
   */
  private BufferedImage createTransparentImage(final int width,
                                               final int height)
  {
    final BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    final int[] data = img.getRGB(0, 0, width, height, null, 0, width);
    Arrays.fill(data, 0x00000000);
    img.setRGB(0, 0, width, height, data, 0, width);
    return img;
  }
  /**
   * Creates a transparent icon. The Icon can be used for aligning menu
   * items.
   *
   * @param width  the width of the new icon
   * @param height the height of the new icon
   * @return the created transparent icon.
   */
  public Icon createTransparentIcon(final int width, final int height)
  {
    return new ImageIcon(createTransparentImage(width, height));
  }
  /**
   * Formats the message stored in the resource bundle (using a
   * MessageFormat).
   *
   * @param key       the resourcebundle key
   * @param parameter the parameter for the message
   * @return the formated string
   */
  public String formatMessage(final String key, final Object parameter)
  {
    return formatMessage(key, new Object[]{parameter});
  }
  /**
   * Formats the message stored in the resource bundle (using a
   * MessageFormat).
   *
   * @param key  the resourcebundle key
   * @param par1 the first parameter for the message
   * @param par2 the second parameter for the message
   * @return the formated string
   */
  public String formatMessage(final String key,
                              final Object par1,
                              final Object par2)
  {
    return formatMessage(key, new Object[]{par1, par2});
  }
  /**
   * Formats the message stored in the resource bundle (using a
   * MessageFormat).
   *
   * @param key        the resourcebundle key
   * @param parameters the parameter collection for the message
   * @return the formated string
   */
  public String formatMessage(final String key, final Object[] parameters)
  {
    final MessageFormat format = new MessageFormat(getString(key));
    format.setLocale(getLocale());
    return format.format(parameters);
  }
  /**
   * Returns the current locale for this resource bundle.
   *
   * @return the locale.
   */
  public Locale getLocale()
  {
    return this.locale;
  }
}
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * --------------------------
 * ResourceBundleWrapper.java
 * --------------------------
 * (C)opyright 2008, by Jess Thrysoee and Contributors.
 *
 * Original Author:  Jess Thrysoee;
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *
 * Changes
 * -------
 * 18-Dec-2008 : Version 1 (JT);
 *
 */
/**
 * Wrapper of ResourceBundle.getBundle() methods. This wrapper is introduced to
 * avoid a dramatic performance penalty by superfluous resource (and classes
 * loaded by Class.forName) lookups on web server in applets.
 *
 * 

 * public class AppletC extends javax.swing.JApplet {
 *    public void init() {
 *       ResourceBundleWrapper.removeCodeBase(getCodeBase(),
 *               (URLClassLoader) getClass().getClassLoader());
 *    ...
 * 

 *
 * @see 
 *               Bug ID: 4243379
 * @see 
 *               Bug ID: 4668479
 *
 * @since 1.0.15
 */
 class ResourceBundleWrapper {
    /**
     * A special class loader with no code base lookup.  This field may be
     * null (the field is only initialised if removeCodeBase() is
     * called from an applet.
     */
    private static URLClassLoader noCodeBaseClassLoader;
    /**
     * Private constructor.
     */
    private ResourceBundleWrapper() {
        // all methods are static, no need to instantiate
    }
    /**
     * Instantiate a {@link URLClassLoader} for resource lookups where the
     * codeBase URL is removed.  This method is typically called from an
     * applet's init() method.  If this method is never called, the
     * getBundle() methods map to the standard
     * {@link ResourceBundle} lookup methods.
     *
     * @param codeBase  the codeBase URL.
     * @param urlClassLoader  the class loader.
     */
    public static void removeCodeBase(URL codeBase,
            URLClassLoader urlClassLoader) {
        List urlsNoBase = new ArrayList();
        URL[] urls = urlClassLoader.getURLs();
        for (int i = 0; i < urls.length; i++) {
            if (! urls[i].sameFile(codeBase)) {
                urlsNoBase.add(urls[i]);
            }
        }
        // substitute the filtered URL list
        URL[] urlsNoBaseArray = (URL[]) urlsNoBase.toArray(new URL[0]);
        noCodeBaseClassLoader = URLClassLoader.newInstance(urlsNoBaseArray);
    }
    /**
     * Finds and returns the specified resource bundle.
     *
     * @param baseName  the base name.
     *
     * @return The resource bundle.
     */
    public static final ResourceBundle getBundle(String baseName) {
        // the noCodeBaseClassLoader is configured by a call to the
        // removeCodeBase() method, typically in the init() method of an
        // applet...
        if (noCodeBaseClassLoader != null) {
            return ResourceBundle.getBundle(baseName, Locale.getDefault(),
                    noCodeBaseClassLoader);
        }
        else {
            // standard ResourceBundle behaviour
            return ResourceBundle.getBundle(baseName);
        }
    }
    /**
     * Finds and returns the specified resource bundle.
     *
     * @param baseName  the base name.
     * @param locale  the locale.
     *
     * @return The resource bundle.
     */
    public static final ResourceBundle getBundle(String baseName,
            Locale locale) {
        // the noCodeBaseClassLoader is configured by a call to the
        // removeCodeBase() method, typically in the init() method of an
        // applet...
        if (noCodeBaseClassLoader != null) {
            return ResourceBundle.getBundle(baseName, locale,
                    noCodeBaseClassLoader);
        }
        else {
            // standard ResourceBundle behaviour
            return ResourceBundle.getBundle(baseName, locale);
        }
    }
    /**
     * Maps directly to ResourceBundle.getBundle(baseName, locale,
     * loader)
.
     *
     * @param baseName  the base name.
     * @param locale  the locale.
     * @param loader  the class loader.
     *
     * @return The resource bundle.
     */
    public static ResourceBundle getBundle(String baseName, Locale locale,
            ClassLoader loader) {
        return ResourceBundle.getBundle(baseName, locale, loader);
    }
}
 /* 
  * JCommon : a free general purpose class library for the Java(tm) platform
  * 
  *
  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
  *
  * Project Info:  http://www.jfree.org/jcommon/index.html
  *
  * This library is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
  * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  * License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
  * USA.
  *
  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  * in the United States and other countries.]
  *
  * ---------------------
  * ObjectUtilitiess.java
  * ---------------------
  * (C) Copyright 2003-2005, by Object Refinery Limited.
  *
  * Original Author:  David Gilbert (for Object Refinery Limited);
  * Contributor(s):   -;
  *
  * $Id: ObjectUtilities.java,v 1.21 2008/09/10 09:24:41 mungady Exp $
  *
  * Changes
  * -------
  * 25-Mar-2003 : Version 1 (DG);
  * 15-Sep-2003 : Fixed bug in clone(List) method (DG);
  * 25-Nov-2004 : Modified clone(Object) method to fail with objects that
  *               cannot be cloned, added new deepClone(Collection) method.
  *               Renamed ObjectUtils --> ObjectUtilities (DG);
  * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
  * 18-Aug-2005 : Added casts to suppress compiler warnings, as suggested in
  *               patch 1260622 (DG);
  *
  */
 /**
  * A collection of useful static utility methods for handling classes and object
  * instantiation.
  *
  * @author Thomas Morgner
  */
 final class ObjectUtilities {
     /**
      * A constant for using the TheadContext as source for the classloader.
      */
     public static final String THREAD_CONTEXT = "ThreadContext";
     /**
      * A constant for using the ClassContext as source for the classloader.
      */
     public static final String CLASS_CONTEXT = "ClassContext";
     /**
      * By default use the thread context.
      */
     private static String classLoaderSource = THREAD_CONTEXT;
     /**
      * The custom classloader to be used (if not null).
      */
     private static ClassLoader classLoader;
     /**
      * Default constructor - private.
      */
     private ObjectUtilities() {
     }
     /**
      * Returns the internal configuration entry, whether the classloader of
      * the thread context or the context classloader should be used.
      *
      * @return the classloader source, either THREAD_CONTEXT or CLASS_CONTEXT.
      */
     public static String getClassLoaderSource() {
         return classLoaderSource;
     }
     /**
      * Defines the internal configuration entry, whether the classloader of
      * the thread context or the context classloader should be used.
      * 


      * This setting can only be defined using the API, there is no safe way
      * to put this into an external configuration file.
      *
      * @param classLoaderSource the classloader source,
      *                          either THREAD_CONTEXT or CLASS_CONTEXT.
      */
     public static void setClassLoaderSource(final String classLoaderSource) {
         ObjectUtilities.classLoaderSource = classLoaderSource;
     }
     /**
      * Returns true if the two objects are equal OR both
      * null.
      *
      * @param o1 object 1 (null permitted).
      * @param o2 object 2 (null permitted).
      * @return true or false.
      */
     public static boolean equal(final Object o1, final Object o2) {
         if (o1 == o2) {
             return true;
         }
         if (o1 != null) {
             return o1.equals(o2);
         }
         else {
             return false;
         }
     }
     /**
      * Returns a hash code for an object, or zero if the object is
      * null.
      *
      * @param object the object (null permitted).
      * @return The object's hash code (or zero if the object is
      *         null).
      */
     public static int hashCode(final Object object) {
         int result = 0;
         if (object != null) {
             result = object.hashCode();
         }
         return result;
     }
     /**
      * Returns a clone of the specified object, if it can be cloned, otherwise
      * throws a CloneNotSupportedException.
      *
      * @param object the object to clone (null not permitted).
      * @return A clone of the specified object.
      * @throws CloneNotSupportedException if the object cannot be cloned.
      */
     public static Object clone(final Object object)
         throws CloneNotSupportedException {
         if (object == null) {
             throw new IllegalArgumentException("Null 'object' argument.");
         }
             try {
                 final Method method = object.getClass().getMethod("clone",
                         (Class[]) null);
                 if (Modifier.isPublic(method.getModifiers())) {
                     return method.invoke(object, (Object[]) null);
                 }
             }
             catch (NoSuchMethodException e) {
               System.out.println("Object without clone() method is impossible.");
             }
             catch (IllegalAccessException e) {
               System.out.println("Object.clone(): unable to call method.");
             }
             catch (InvocationTargetException e) {
                 System.out.println("Object without clone() method is impossible.");
             }
         throw new CloneNotSupportedException("Failed to clone.");
     }
     /**
      * Returns a new collection containing clones of all the items in the
      * specified collection.
      *
      * @param collection the collection (null not permitted).
      * @return A new collection containing clones of all the items in the
      *         specified collection.
      * @throws CloneNotSupportedException if any of the items in the collection
      *                                    cannot be cloned.
      */
     public static Collection deepClone(final Collection collection)
         throws CloneNotSupportedException {
         if (collection == null) {
             throw new IllegalArgumentException("Null 'collection' argument.");
         }
         // all JDK-Collections are cloneable ...
         // and if the collection is not clonable, then we should throw
         // a CloneNotSupportedException anyway ...
         final Collection result
             = (Collection) ObjectUtilities.clone(collection);
         result.clear();
         final Iterator iterator = collection.iterator();
         while (iterator.hasNext()) {
             final Object item = iterator.next();
             if (item != null) {
                 result.add(clone(item));
             }
             else {
                 result.add(null);
             }
         }
         return result;
     }
     /**
      * Returns the classloader, which was responsible for loading the given
      * class.
      *
      * @param c the classloader, either an application class loader or the
      *          boot loader.
      * @return the classloader, never null.
      * @throws SecurityException if the SecurityManager does not allow to grab
      *                           the context classloader.
      */
     public static ClassLoader getClassLoader(final Class c) {
         final String localClassLoaderSource;
         synchronized(ObjectUtilities.class)
         {
           if (classLoader != null) {
               return classLoader;
           }
           localClassLoaderSource = classLoaderSource;
         }
         if ("ThreadContext".equals(localClassLoaderSource)) {
             final ClassLoader threadLoader = Thread.currentThread().getContextClassLoader();
             if (threadLoader != null) {
                 return threadLoader;
             }
         }
         // Context classloader - do not cache ..
         final ClassLoader applicationCL = c.getClassLoader();
         if (applicationCL == null) {
             return ClassLoader.getSystemClassLoader();
         }
         else {
             return applicationCL;
         }
     }
     /**
      * Returns the resource specified by the absolute name.
      *
      * @param name the name of the resource
      * @param c    the source class
      * @return the url of the resource or null, if not found.
      */
     public static URL getResource(final String name, final Class c) {
         final ClassLoader cl = getClassLoader(c);
         if (cl == null) {
             return null;
         }
         return cl.getResource(name);
     }
     /**
      * Returns the resource specified by the relative name.
      *
      * @param name the name of the resource relative to the given class
      * @param c    the source class
      * @return the url of the resource or null, if not found.
      */
     public static URL getResourceRelative(final String name, final Class c) {
         final ClassLoader cl = getClassLoader(c);
         final String cname = convertName(name, c);
         if (cl == null) {
             return null;
         }
         return cl.getResource(cname);
     }
     /**
      * Transform the class-relative resource name into a global name by
      * appending it to the classes package name. If the name is already a
      * global name (the name starts with a "/"), then the name is returned
      * unchanged.
      *
      * @param name the resource name
      * @param c    the class which the resource is relative to
      * @return the tranformed name.
      */
     private static String convertName(final String name, Class c) {
         if (name.startsWith("/")) {
             // strip leading slash..
             return name.substring(1);
         }
         // we cant work on arrays, so remove them ...
         while (c.isArray()) {
             c = c.getComponentType();
         }
         // extract the package ...
         final String baseName = c.getName();
         final int index = baseName.lastIndexOf('.');
         if (index == -1) {
             return name;
         }
         final String pkgName = baseName.substring(0, index);
         return pkgName.replace('.', '/') + "/" + name;
     }
     /**
      * Returns the inputstream for the resource specified by the
      * absolute name.
      *
      * @param name the name of the resource
      * @param context the source class
      * @return the url of the resource or null, if not found.
      */
     public static InputStream getResourceAsStream(final String name,
                                                   final Class context) {
         final URL url = getResource(name, context);
         if (url == null) {
             return null;
         }
         try {
             return url.openStream();
         }
         catch (IOException e) {
             return null;
         }
     }
     /**
      * Returns the inputstream for the resource specified by the
      * relative name.
      *
      * @param name the name of the resource relative to the given class
      * @param context the source class
      * @return the url of the resource or null, if not found.
      */
     public static InputStream getResourceRelativeAsStream
         (final String name, final Class context) {
         final URL url = getResourceRelative(name, context);
         if (url == null) {
             return null;
         }
         try {
             return url.openStream();
         }
         catch (IOException e) {
             return null;
         }
     }
     /**
      * Tries to create a new instance of the given class. This is a short cut
      * for the common bean instantiation code.
      *
      * @param className the class name as String, never null.
      * @param source    the source class, from where to get the classloader.
      * @return the instantiated object or null, if an error occured.
      */
     public static Object loadAndInstantiate(final String className,
                                             final Class source) {
         try {
             final ClassLoader loader = getClassLoader(source);
             final Class c = loader.loadClass(className);
             return c.newInstance();
         }
         catch (Exception e) {
             return null;
         }
     }
     /**
      * Tries to create a new instance of the given class. This is a short cut
      * for the common bean instantiation code. This method is a type-safe method
      * and will not instantiate the class unless it is an instance of the given
      * type.
      *
      * @param className the class name as String, never null.
      * @param source    the source class, from where to get the classloader.
      * @param type  the type.
      * @return the instantiated object or null, if an error occurred.
      */
     public static Object loadAndInstantiate(final String className,
                                             final Class source,
                                             final Class type) {
         try {
             final ClassLoader loader = getClassLoader(source);
             final Class c = loader.loadClass(className);
             if (type.isAssignableFrom(c)) {
                 return c.newInstance();
             }
         }
         catch (Exception e) {
             return null;
         }
         return null;
     }
     /**
      * Returns true if this is version 1.4 or later of the
      * Java runtime.
      *
      * @return A boolean.
      */
     public static boolean isJDK14() {
         return false;
     }
     private static String[] parseVersions (String version)
     {
       if (version == null)
       {
         return new String[0];
       }
       final ArrayList versions = new ArrayList();
       final StringTokenizer strtok = new StringTokenizer(version, ".");
       while (strtok.hasMoreTokens())
       {
         versions.add (strtok.nextToken());
       }
       return (String[]) versions.toArray(new String[versions.size()]);
     }
 }