/*
* 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.
* <p/>
* The class support references within the resource bundle set to minimize the
* occurence of duplicate keys. References are given in the format:
* <pre>
* a.key.name=@referenced.key
* </pre>
* <p/>
* A lookup to a key in an other resource bundle should be written by
* <pre>
* a.key.name=@@resourcebundle_name@referenced.key
* </pre>
*
* @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 <code>key</code> is <code>null</code>
* @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.
* <p/>
* For the enter key, the resource bundle would therefore either contain
* "ENTER" or "\n".
* <pre>
* a.resourcebundle.key=ENTER
* an.other.resourcebundle.key=\n
* </pre>
*
* @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.
* <p/>
* The keystroke will be composed of a simple key press and the plattform's
* MenuKeyMask.
* <p/>
* The keystrokes character key should be either the symbolic name of one of
* the KeyEvent.VK_* constants or the character for that key.
* <p/>
* For the 'A' key, the resource bundle would therefore either contain
* "VK_A" or "a".
* <pre>
* a.resourcebundle.key=VK_A
* an.other.resourcebundle.key=a
* </pre>
*
* @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.
* <p/>
* The keystroke will be composed of a simple key press and the given
* KeyMask. If the KeyMask is zero, a plain Keystroke is returned.
* <p/>
* The keystrokes character key should be either the symbolic name of one of
* the KeyEvent.VK_* constants or the character for that key.
* <p/>
* For the 'A' key, the resource bundle would therefore either contain
* "VK_A" or "a".
* <pre>
* a.resourcebundle.key=VK_A
* an.other.resourcebundle.key=a
* </pre>
*
* @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.
* <p/>
* 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.
* <p/>
* <pre>
* # define the file menu
* menu.file.name=File
* menu.file.mnemonic=F
* </pre>
* The menu definition above can be used to create the menu by calling
* <code>createMenu ("menu.file")</code>.
*
* @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.
* <p/>
* Example: The load a file named 'logo.gif' which is stored in a java
* package named 'org.jfree.resources':
* <pre>
* mainmenu.logo=org/jfree/resources/logo.gif
* </pre>
* The URL for that file can be queried with: <code>getResource("mainmenu.logo");</code>.
*
* @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.
*
* <pre>
* public class AppletC extends javax.swing.JApplet {
* public void init() {
* ResourceBundleWrapper.removeCodeBase(getCodeBase(),
* (URLClassLoader) getClass().getClassLoader());
* ...
* </pre>
*
* @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4243379">
* Bug ID: 4243379</a>
* @see <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4668479">
* Bug ID: 4668479</a>
*
* @since 1.0.15
*/
class ResourceBundleWrapper {
/**
* A special class loader with no code base lookup. This field may be
* <code>null</code> (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
* <code>getBundle()</code> 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 <code>ResourceBundle.getBundle(baseName, locale,
* loader)</code>.
*
* @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.
* <p/>
* 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 <code>true</code> if the two objects are equal OR both
* <code>null</code>.
*
* @param o1 object 1 (<code>null</code> permitted).
* @param o2 object 2 (<code>null</code> permitted).
* @return <code>true</code> or <code>false</code>.
*/
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
* <code>null</code>.
*
* @param object the object (<code>null</code> permitted).
* @return The object's hash code (or zero if the object is
* <code>null</code>).
*/
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 (<code>null</code> 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 (<code>null</code> 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 <strong>absolute</strong> 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 <strong>relative</strong> 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
* <strong>absolute</strong> 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
* <strong>relative</strong> 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 <code>true</code> 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()]);
}
}