    001    /* ========================================================================
    002     * JCommon : a free general purpose class library for the Java(tm) platform
    003     * ========================================================================
    004     *
    005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
    006     *
    007     * Project Info:  http://www.jfree.org/jcommon/index.html
    008     *
    009     * This library is free software; you can redistribute it and/or modify it
    010     * under the terms of the GNU Lesser General Public License as published by
    011     * the Free Software Foundation; either version 2.1 of the License, or
    012     * (at your option) any later version.
    013     *
    014     * This library is distributed in the hope that it will be useful, but
    015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017     * License for more details.
    018     *
    019     * You should have received a copy of the GNU Lesser General Public
    020     * License along with this library; if not, write to the Free Software
    021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022     * USA.
    023     *
    024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
    025     * in the United States and other countries.]
    026     *
    027     * ---------------------
    028     * ObjectUtilitiess.java
    029     * ---------------------
    030     * (C) Copyright 2003-2005, by Object Refinery Limited.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   -;
    034     *
    035     * $Id: ObjectUtilities.java,v 1.12 2005/11/06 22:16:38 taqua Exp $
    036     *
    037     * Changes
    038     * -------
    039     * 25-Mar-2003 : Version 1 (DG);
    040     * 15-Sep-2003 : Fixed bug in clone(List) method (DG);
    041     * 25-Nov-2004 : Modified clone(Object) method to fail with objects that
    042     *               cannot be cloned, added new deepClone(Collection) method.
    043     *               Renamed ObjectUtils --> ObjectUtilities (DG);
    044     * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
    045     * 18-Aug-2005 : Added casts to suppress compiler warnings, as suggested in
    046     *               patch 1260622 (DG);
    047     *
    048     */
    049
    050    package org.jfree.util;
    051
    052    import java.io.IOException;
    053    import java.io.InputStream;
    054    import java.lang.reflect.InvocationTargetException;
    055    import java.lang.reflect.Method;
    056    import java.lang.reflect.Modifier;
    057    import java.net.URL;
    058    import java.util.Collection;
    059    import java.util.Iterator;
    060
    061    /**
    062     * A collection of useful static utility methods for handling classes and object
    063     * instantiation.
    064     *
    065     * @author Thomas Morgner
    066     */
    067    public final class ObjectUtilities {
    068
    069        /**
    070         * A constant for using the TheadContext as source for the classloader.
    071         */
    072        public static final String THREAD_CONTEXT = "ThreadContext";
    073        /**
    074         * A constant for using the ClassContext as source for the classloader.
    075         */
    076        public static final String CLASS_CONTEXT = "ClassContext";
    077
    078        /**
    079         * By default use the thread context.
    080         */
    081        private static String classLoaderSource = THREAD_CONTEXT;
    082        /**
    083         * The custom classloader to be used (if not null).
    084         */
    085        private static ClassLoader classLoader;
    086
    087        /**
    088         * Default constructor - private.
    089         */
    090        private ObjectUtilities() {
    091        }
    092
    093        /**
    094         * Returns the internal configuration entry, whether the classloader of
    095         * the thread context or the context classloader should be used.
    096         *
    097         * @return the classloader source, either THREAD_CONTEXT or CLASS_CONTEXT.
    098         */
    099        public static String getClassLoaderSource() {
    100            return classLoaderSource;
    101        }
    102
    103        /**
    104         * Defines the internal configuration entry, whether the classloader of
    105         * the thread context or the context classloader should be used.
    106         * <p/>
    107         * This setting can only be defined using the API, there is no safe way
    108         * to put this into an external configuration file.
    109         *
    110         * @param classLoaderSource the classloader source,
    111         *                          either THREAD_CONTEXT or CLASS_CONTEXT.
    112         */
    113        public static void setClassLoaderSource(final String classLoaderSource) {
    114            ObjectUtilities.classLoaderSource = classLoaderSource;
    115        }
    116
    117        /**
    118         * Returns <code>true</code> if the two objects are equal OR both
    119         * <code>null</code>.
    120         *
    121         * @param o1 object 1 (<code>null</code> permitted).
    122         * @param o2 object 2 (<code>null</code> permitted).
    123         * @return <code>true</code> or <code>false</code>.
    124         */
    125        public static boolean equal(final Object o1, final Object o2) {
    126            if (o1 == o2) {
    127                return true;
    128            }
    129            if (o1 != null) {
    130                return o1.equals(o2);
    131            }
    132            else {
    133                return false;
    134            }
    135        }
    136
    137        /**
    138         * Returns a hash code for an object, or zero if the object is
    139         * <code>null</code>.
    140         *
    141         * @param object the object (<code>null</code> permitted).
    142         * @return The object's hash code (or zero if the object is
    143         *         <code>null</code>).
    144         */
    145        public static int hashCode(final Object object) {
    146            int result = 0;
    147            if (object != null) {
    148                result = object.hashCode();
    149            }
    150            return result;
    151        }
    152
    153        /**
    154         * Returns a clone of the specified object, if it can be cloned, otherwise
    155         * throws a CloneNotSupportedException.
    156         *
    157         * @param object the object to clone (<code>null</code> not permitted).
    158         * @return A clone of the specified object.
    159         * @throws CloneNotSupportedException if the object cannot be cloned.
    160         */
    161        public static Object clone(final Object object)
    162            throws CloneNotSupportedException {
    163            if (object == null) {
    164                throw new IllegalArgumentException("Null 'object' argument.");
    165            }
    166            if (object instanceof PublicCloneable) {
    167                final PublicCloneable pc = (PublicCloneable) object;
    168                return pc.clone();
    169            }
    170            else {
    171                try {
    172                    final Method method = object.getClass().getMethod("clone",
    173                            (Class[]) null);
    174                    if (Modifier.isPublic(method.getModifiers())) {
    175                        return method.invoke(object, (Object[]) null);
    176                    }
    177                }
    178                catch (NoSuchMethodException e) {
    179                    Log.warn("Object without clone() method is impossible.");
    180                }
    181                catch (IllegalAccessException e) {
    182                    Log.warn("Object.clone(): unable to call method.");
    183                }
    184                catch (InvocationTargetException e) {
    185                    Log.warn("Object without clone() method is impossible.");
    186                }
    187            }
    188            throw new CloneNotSupportedException("Failed to clone.");
    189        }
    190
    191        /**
    192         * Returns a new collection containing clones of all the items in the
    193         * specified collection.
    194         *
    195         * @param collection the collection (<code>null</code> not permitted).
    196         * @return A new collection containing clones of all the items in the
    197         *         specified collection.
    198         * @throws CloneNotSupportedException if any of the items in the collection
    199         *                                    cannot be cloned.
    200         */
    201        public static Collection deepClone(final Collection collection)
    202            throws CloneNotSupportedException {
    203
    204            if (collection == null) {
    205                throw new IllegalArgumentException("Null 'collection' argument.");
    206            }
    207            // all JDK-Collections are cloneable ...
    208            // and if the collection is not clonable, then we should throw
    209            // a CloneNotSupportedException anyway ...
    210            final Collection result
    211                = (Collection) ObjectUtilities.clone(collection);
    212            result.clear();
    213            final Iterator iterator = collection.iterator();
    214            while (iterator.hasNext()) {
    215                final Object item = iterator.next();
    216                if (item != null) {
    217                    result.add(clone(item));
    218                }
    219                else {
    220                    result.add(null);
    221                }
    222            }
    223            return result;
    224        }
    225
    226        /**
    227         * Redefines the custom classloader.
    228         *
    229         * @param classLoader the new classloader or null to use the default.
    230         */
    231        public synchronized static void setClassLoader(
    232                final ClassLoader classLoader) {
    233            ObjectUtilities.classLoader = classLoader;
    234        }
    235
    236        /**
    237         * Returns the custom classloader or null, if no custom classloader is defined.
    238         *
    239         * @return the custom classloader or null to use the default.
    240         */
    241        public static ClassLoader getClassLoader() {
    242          return classLoader;
    243        }
    244
    245        /**
    246         * Returns the classloader, which was responsible for loading the given
    247         * class.
    248         *
    249         * @param c the classloader, either an application class loader or the
    250         *          boot loader.
    251         * @return the classloader, never null.
    252         * @throws SecurityException if the SecurityManager does not allow to grab
    253         *                           the context classloader.
    254         */
    255        public synchronized static ClassLoader getClassLoader(final Class c) {
    256            if (classLoader != null) {
    257                return classLoader;
    258            }
    259            if ("ThreadContext".equals(classLoaderSource)) {
    260                final ClassLoader threadLoader
    261                    = Thread.currentThread().getContextClassLoader();
    262                return threadLoader;
    263            }
    264            else {
    265                // Context classloader - do not cache ..
    266                final ClassLoader applicationCL = c.getClassLoader();
    267                if (applicationCL == null) {
    268                    return ClassLoader.getSystemClassLoader();
    269                }
    270                else {
    271                    return applicationCL;
    272                }
    273            }
    274        }
    275
    276
    277        /**
    278         * Returns the resource specified by the <strong>absolute</strong> name.
    279         *
    280         * @param name the name of the resource
    281         * @param c    the source class
    282         * @return the url of the resource or null, if not found.
    283         */
    284        public static URL getResource(final String name, final Class c) {
    285            final ClassLoader cl = getClassLoader(c);
    286            return cl.getResource(name);
    287        }
    288
    289        /**
    290         * Returns the resource specified by the <strong>relative</strong> name.
    291         *
    292         * @param name the name of the resource relative to the given class
    293         * @param c    the source class
    294         * @return the url of the resource or null, if not found.
    295         */
    296        public static URL getResourceRelative(final String name, final Class c) {
    297            final ClassLoader cl = getClassLoader(c);
    298            final String cname = convertName(name, c);
    299            return cl.getResource(cname);
    300        }
    301
    302        /**
    303         * Transform the class-relative resource name into a global name by
    304         * appending it to the classes package name. If the name is already a
    305         * global name (the name starts with a "/"), then the name is returned
    306         * unchanged.
    307         *
    308         * @param name the resource name
    309         * @param c    the class which the resource is relative to
    310         * @return the tranformed name.
    311         */
    312        private static String convertName(final String name, Class c) {
    313            if (name.startsWith("/")) {
    314                // strip leading slash..
    315                return name.substring(1);
    316            }
    317
    318            // we cant work on arrays, so remove them ...
    319            while (c.isArray()) {
    320                c = c.getComponentType();
    321            }
    322            // extract the package ...
    323            final String baseName = c.getName();
    324            final int index = baseName.lastIndexOf('.');
    325            if (index == -1) {
    326                return name;
    327            }
    328
    329            final String pkgName = baseName.substring(0, index);
    330            return pkgName.replace('.', '/') + "/" + name;
    331        }
    332
    333        /**
    334         * Returns the inputstream for the resource specified by the
    335         * <strong>absolute</strong> name.
    336         *
    337         * @param name the name of the resource
    338         * @param context the source class
    339         * @return the url of the resource or null, if not found.
    340         */
    341        public static InputStream getResourceAsStream(final String name,
    342                                                      final Class context) {
    343            final URL url = getResource(name, context);
    344            if (url == null) {
    345                return null;
    346            }
    347
    348            try {
    349                return url.openStream();
    350            }
    351            catch (IOException e) {
    352                return null;
    353            }
    354        }
    355
    356        /**
    357         * Returns the inputstream for the resource specified by the
    358         * <strong>relative</strong> name.
    359         *
    360         * @param name the name of the resource relative to the given class
    361         * @param context the source class
    362         * @return the url of the resource or null, if not found.
    363         */
    364        public static InputStream getResourceRelativeAsStream
    365            (final String name, final Class context) {
    366            final URL url = getResourceRelative(name, context);
    367            if (url == null) {
    368                return null;
    369            }
    370
    371            try {
    372                return url.openStream();
    373            }
    374            catch (IOException e) {
    375                return null;
    376            }
    377        }
    378
    379        /**
    380         * Tries to create a new instance of the given class. This is a short cut
    381         * for the common bean instantiation code.
    382         *
    383         * @param className the class name as String, never null.
    384         * @param source    the source class, from where to get the classloader.
    385         * @return the instantiated object or null, if an error occured.
    386         */
    387        public static Object loadAndInstantiate(final String className,
    388                                                final Class source) {
    389            try {
    390                final ClassLoader loader = getClassLoader(source);
    391                final Class c = loader.loadClass(className);
    392                return c.newInstance();
    393            }
    394            catch (Exception e) {
    395                return null;
    396            }
    397        }
    398
    399    }