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 }