001 package railo.commons.lang; 002 003 import java.io.File; 004 import java.io.IOException; 005 import java.io.InputStream; 006 import java.lang.reflect.Constructor; 007 import java.lang.reflect.Field; 008 import java.lang.reflect.InvocationTargetException; 009 import java.lang.reflect.Method; 010 import java.net.URL; 011 import java.net.URLClassLoader; 012 import java.util.Map; 013 import java.util.Set; 014 015 import railo.commons.collections.HashTable; 016 import railo.commons.io.FileUtil; 017 import railo.commons.io.IOUtil; 018 import railo.runtime.PageContext; 019 import railo.runtime.PageContextImpl; 020 import railo.runtime.config.Config; 021 import railo.runtime.engine.ThreadLocalPageContext; 022 import railo.runtime.exp.PageException; 023 import railo.runtime.op.Caster; 024 import railo.runtime.type.Array; 025 import railo.runtime.type.util.ListUtil; 026 027 028 public final class ClassUtil { 029 030 /** 031 * @param pc 032 * @param lcType 033 * @param type 034 * @return 035 * @throws ClassException 036 * @throws PageException 037 */ 038 public static Class toClass(String className) throws ClassException { 039 className = className.trim(); 040 String lcClassName=className.toLowerCase(); 041 boolean isRef=false; 042 if(lcClassName.startsWith("java.lang.")){ 043 lcClassName=lcClassName.substring(10); 044 isRef=true; 045 } 046 047 if(lcClassName.equals("boolean")) { 048 if(isRef) return Boolean.class; 049 return boolean.class; 050 } 051 if(lcClassName.equals("byte")) { 052 if(isRef) return Byte.class; 053 return byte.class; 054 } 055 if(lcClassName.equals("int")) { 056 return int.class; 057 } 058 if(lcClassName.equals("long")) { 059 if(isRef) return Long.class; 060 return long.class; 061 } 062 if(lcClassName.equals("float")) { 063 if(isRef) return Float.class; 064 return float.class; 065 } 066 if(lcClassName.equals("double")) { 067 if(isRef) return Double.class; 068 return double.class; 069 } 070 if(lcClassName.equals("char")) { 071 return char.class; 072 } 073 if(lcClassName.equals("short")) { 074 if(isRef) return Short.class; 075 return short.class; 076 } 077 078 if(lcClassName.equals("integer")) return Integer.class; 079 if(lcClassName.equals("character")) return Character.class; 080 if(lcClassName.equals("object")) return Object.class; 081 if(lcClassName.equals("string")) return String.class; 082 if(lcClassName.equals("null")) return Object.class; 083 if(lcClassName.equals("numeric")) return Double.class; 084 085 return ClassUtil.loadClass(className); 086 } 087 088 089 090 /** 091 * loads a class from a String classname 092 * @param className 093 * @param defaultValue 094 * @return matching Class 095 */ 096 public static Class loadClass(String className, Class defaultValue) { 097 return loadClass(null,className,defaultValue); 098 } 099 100 /** 101 * loads a class from a String classname 102 * @param className 103 * @return matching Class 104 * @throws ClassException 105 */ 106 public static Class loadClass(String className) throws ClassException { 107 Config config = ThreadLocalPageContext.getConfig(); 108 Class clazz = loadClass(config==null?null:config.getClassLoader(),className,null); 109 if(clazz!=null) return clazz; 110 throw new ClassException("cannot load class through its string name, because no definition for the class with the specified name ["+className+"] could be found"); 111 } 112 113 /** 114 * loads a class from a specified Classloader with given classname 115 * @param className 116 * @param cl 117 * @return matching Class 118 */ 119 public static Class loadClass(ClassLoader cl,String className, Class defaultValue) { 120 121 if(cl==null){ 122 PageContextImpl pci = (PageContextImpl) ThreadLocalPageContext.get(); 123 if(pci!=null){ 124 try { 125 cl=pci.getClassLoader(); 126 } 127 catch (IOException e) {} 128 } 129 if(cl==null) { 130 Config config = ThreadLocalPageContext.getConfig(); 131 if(config!=null)cl=config.getClassLoader(); 132 } 133 } 134 135 136 137 try { 138 if(cl==null)return Class.forName(className.trim()); 139 return cl.loadClass(className.trim()); 140 141 } 142 catch (ClassNotFoundException e) { 143 try { 144 return Class.forName(className, false, cl); 145 } 146 catch (ClassNotFoundException e1) { 147 if("boolean".equals(className)) return boolean.class; 148 if("char".equals(className)) return char.class; 149 if("float".equals(className)) return float.class; 150 if("short".equals(className)) return short.class; 151 if("int".equals(className)) return int.class; 152 if("long".equals(className)) return long.class; 153 if("double".equals(className)) return double.class; 154 155 156 return defaultValue; 157 } 158 } 159 } 160 161 /** 162 * loads a class from a specified Classloader with given classname 163 * @param className 164 * @param cl 165 * @return matching Class 166 * @throws ClassException 167 */ 168 public static Class loadClass(ClassLoader cl,String className) throws ClassException { 169 Class clazz = loadClass(cl,className,null); 170 if(clazz!=null) return clazz; 171 throw new ClassException("cannot load class through its string name, because no definition for the class with the specified name ["+className+"] could be found"); 172 } 173 174 /** 175 * loads a class from a String classname 176 * @param clazz class to load 177 * @return matching Class 178 * @throws ClassException 179 */ 180 public static Object loadInstance(Class clazz) throws ClassException{ 181 try { 182 return clazz.newInstance(); 183 } 184 catch (InstantiationException e) { 185 throw new ClassException("the specified class object ["+clazz.getName()+"()] cannot be instantiated"); 186 } 187 catch (IllegalAccessException e) { 188 throw new ClassException("can't load class because the currently executing method does not have access to the definition of the specified class"); 189 } 190 } 191 192 public static Object loadInstance(String className) throws ClassException{ 193 return loadInstance(loadClass(className)); 194 } 195 public static Object loadInstance(ClassLoader cl, String className) throws ClassException{ 196 return loadInstance(loadClass(cl,className)); 197 } 198 199 /** 200 * loads a class from a String classname 201 * @param clazz class to load 202 * @return matching Class 203 */ 204 public static Object loadInstance(Class clazz, Object defaultValue){ 205 try { 206 return clazz.newInstance(); 207 } 208 catch (Throwable t) { 209 return defaultValue; 210 } 211 } 212 213 public static Object loadInstance(String className, Object deaultValue){ 214 Class clazz = loadClass(className,null); 215 if(clazz==null) return deaultValue; 216 return loadInstance(clazz,deaultValue); 217 } 218 219 public static Object loadInstance(ClassLoader cl, String className, Object deaultValue) { 220 Class clazz = loadClass(cl,className,null); 221 if(clazz==null) return deaultValue; 222 return loadInstance(clazz,deaultValue); 223 } 224 225 /** 226 * loads a class from a String classname 227 * @param clazz class to load 228 * @param args 229 * @return matching Class 230 * @throws ClassException 231 * @throws ClassException 232 * @throws InvocationTargetException 233 */ 234 public static Object loadInstance(Class clazz, Object[] args) throws ClassException, InvocationTargetException { 235 if(args==null || args.length==0) return loadInstance(clazz); 236 237 Class[] cArgs=new Class[args.length]; 238 for(int i=0;i<args.length;i++) { 239 cArgs[i]=args[i].getClass(); 240 } 241 242 try { 243 Constructor c = clazz.getConstructor(cArgs); 244 return c.newInstance(args); 245 246 } 247 catch (SecurityException e) { 248 throw new ClassException("there is a security violation (throwed by security manager)"); 249 } 250 catch (NoSuchMethodException e) { 251 252 StringBuilder sb=new StringBuilder(clazz.getName()); 253 char del='('; 254 for(int i=0;i<cArgs.length;i++) { 255 sb.append(del); 256 sb.append(cArgs[i].getName()); 257 del=','; 258 } 259 sb.append(')'); 260 261 throw new ClassException("there is no constructor with this ["+sb+"] signature for the class ["+clazz.getName()+"]"); 262 } 263 catch (IllegalArgumentException e) { 264 throw new ClassException("has been passed an illegal or inappropriate argument"); 265 } 266 catch (InstantiationException e) { 267 throw new ClassException("the specified class object ["+clazz.getName()+"] cannot be instantiated because it is an interface or is an abstract class"); 268 } 269 catch (IllegalAccessException e) { 270 throw new ClassException("can't load class because the currently executing method does not have access to the definition of the specified class"); 271 } 272 } 273 274 public static Object loadInstance(String className, Object[] args) throws ClassException, InvocationTargetException{ 275 return loadInstance(loadClass(className),args); 276 } 277 278 public static Object loadInstance(ClassLoader cl, String className, Object[] args) throws ClassException, InvocationTargetException{ 279 return loadInstance(loadClass(cl,className),args); 280 } 281 282 /** 283 * loads a class from a String classname 284 * @param clazz class to load 285 * @param args 286 * @return matching Class 287 */ 288 public static Object loadInstance(Class clazz, Object[] args, Object defaultValue) { 289 if(args==null || args.length==0) return loadInstance(clazz,defaultValue); 290 try { 291 Class[] cArgs=new Class[args.length]; 292 for(int i=0;i<args.length;i++) { 293 if(args[i]==null)cArgs[i]=Object.class; 294 else cArgs[i]=args[i].getClass(); 295 } 296 Constructor c = clazz.getConstructor(cArgs); 297 return c.newInstance(args); 298 299 } 300 catch (Throwable t) {//print.printST(t); 301 return defaultValue; 302 } 303 304 } 305 306 public static Object loadInstance(String className, Object[] args, Object deaultValue){ 307 Class clazz = loadClass(className,null); 308 if(clazz==null) return deaultValue; 309 return loadInstance(clazz,args,deaultValue); 310 } 311 312 public static Object loadInstance(ClassLoader cl, String className, Object[] args, Object deaultValue) { 313 Class clazz = loadClass(cl,className,null); 314 if(clazz==null) return deaultValue; 315 return loadInstance(clazz,args,deaultValue); 316 } 317 318 /** 319 * @return returns a string array of all pathes in classpath 320 */ 321 public static String[] getClassPath(Config config) { 322 323 Map pathes=new HashTable(); 324 String pathSeperator=System.getProperty("path.separator"); 325 if(pathSeperator==null)pathSeperator=";"; 326 327 // pathes from system properties 328 String strPathes=System.getProperty("java.class.path"); 329 if(strPathes!=null) { 330 Array arr=ListUtil.listToArrayRemoveEmpty(strPathes,pathSeperator); 331 int len=arr.size(); 332 for(int i=1;i<=len;i++) { 333 File file=FileUtil.toFile(Caster.toString(arr.get(i,""),"").trim()); 334 if(file.exists()) 335 try { 336 pathes.put(file.getCanonicalPath(),""); 337 } catch (IOException e) {} 338 } 339 } 340 341 342 // pathes from url class Loader (dynamic loaded classes) 343 getClassPathesFromLoader(new ClassUtil().getClass().getClassLoader(), pathes); 344 getClassPathesFromLoader(config.getClassLoader(), pathes); 345 346 Set set = pathes.keySet(); 347 return (String[]) set.toArray(new String[set.size()]); 348 } 349 350 /** 351 * get class pathes from all url ClassLoaders 352 * @param ucl URL Class Loader 353 * @param pathes Hashmap with allpathes 354 */ 355 private static void getClassPathesFromLoader(ClassLoader cl, Map pathes) { 356 if(cl instanceof URLClassLoader) 357 _getClassPathesFromLoader((URLClassLoader) cl, pathes); 358 } 359 360 361 private static void _getClassPathesFromLoader(URLClassLoader ucl, Map pathes) { 362 getClassPathesFromLoader(ucl.getParent(), pathes); 363 364 // get all pathes 365 URL[] urls=ucl.getURLs(); 366 367 for(int i=0;i<urls.length;i++) { 368 File file=FileUtil.toFile(urls[i].getPath()); 369 if(file.exists()) 370 try { 371 pathes.put(file.getCanonicalPath(),""); 372 } catch (IOException e) {} 373 } 374 } 375 376 // CafeBabe (Java Magic Number) 377 private static final int ICA=202;//CA 378 private static final int IFE=254;//FE 379 private static final int IBA=186;//BA 380 private static final int IBE=190;//BE 381 382 // CF33 (Railo Magic Number) 383 private static final int ICF=207;//CF 384 private static final int I33=51;//33 385 386 387 private static final byte BCA=(byte)ICA;//CA 388 private static final byte BFE=(byte)IFE;//FE 389 private static final byte BBA=(byte)IBA;//BA 390 private static final byte BBE=(byte)IBE;//BE 391 392 private static final byte BCF=(byte)ICF;//CF 393 private static final byte B33=(byte)I33;//33 394 395 396 /** 397 * check if given stream is a bytecode stream, if yes remove bytecode mark 398 * @param is 399 * @return is bytecode stream 400 * @throws IOException 401 */ 402 public static boolean isBytecode(InputStream is) throws IOException { 403 if(!is.markSupported()) 404 throw new IOException("can only read input streams that support mark/reset"); 405 is.mark(-1); 406 //print(bytes); 407 int first=is.read(); 408 int second=is.read(); 409 boolean rtn=(first==ICF && second==I33) || (first==ICA && second==IFE && is.read()==IBA && is.read()==IBE); 410 411 is.reset(); 412 return rtn; 413 } 414 415 416 public static boolean isBytecode(byte[] barr){ 417 if(barr.length<4) return false; 418 return (barr[0]==BCF && barr[1]==B33) || (barr[0]==BCA && barr[1]==BFE && barr[2]==BBA && barr[3]==BBE); 419 } 420 public static boolean isRawBytecode(byte[] barr){ 421 if(barr.length<4) return false; 422 return (barr[0]==BCA && barr[1]==BFE && barr[2]==BBA && barr[3]==BBE); 423 } 424 425 public static boolean hasCF33Prefix(byte[] barr) { 426 if(barr.length<4) return false; 427 return (barr[0]==BCF && barr[1]==B33); 428 } 429 430 public static byte[] removeCF33Prefix(byte[] barr) { 431 if(!hasCF33Prefix(barr)) return barr; 432 433 byte[] dest = new byte[barr.length-10]; 434 System.arraycopy(barr, 10, dest, 0, 10); 435 return dest; 436 } 437 438 public static String getName(Class clazz) { 439 if(clazz.isArray()){ 440 return getName(clazz.getComponentType())+"[]"; 441 } 442 443 return clazz.getName(); 444 } 445 446 public static Method getMethodIgnoreCase(Class clazz, String methodName, Class[] args) throws ClassException { 447 Method[] methods = clazz.getMethods(); 448 Method method; 449 Class[] params; 450 outer:for(int i=0;i<methods.length;i++){ 451 method=methods[i]; 452 if(method.getName().equalsIgnoreCase(methodName)){ 453 params = method.getParameterTypes(); 454 if(params.length==args.length){ 455 for(int y=0;y<params.length;y++){ 456 if(!params[y].equals(args[y])){ 457 continue outer; 458 } 459 } 460 return method; 461 } 462 } 463 } 464 465 throw new ClassException("class "+clazz.getName()+" has no method with name "+methodName); 466 } 467 468 469 /** 470 * return all field names as String array 471 * @param clazz class to get field names from 472 * @return field names 473 */ 474 public static String[] getFieldNames(Class clazz) { 475 Field[] fields = clazz.getFields(); 476 String[] names=new String[fields.length]; 477 for(int i=0;i<names.length;i++){ 478 names[i]=fields[i].getName(); 479 } 480 return names; 481 } 482 483 public static byte[] toBytes(Class clazz) throws IOException { 484 return IOUtil.toBytes(clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.','/')+".class"),true); 485 } 486 487 /** 488 * return a array class based on the given class (opposite from Class.getComponentType()) 489 * @param clazz 490 * @return 491 */ 492 public static Class toArrayClass(Class clazz) { 493 return java.lang.reflect.Array.newInstance(clazz, 0).getClass(); 494 } 495 496 497 498 public static Class<?> toComponentType(Class<?> clazz) { 499 Class<?> tmp; 500 while(true){ 501 tmp=clazz.getComponentType(); 502 if(tmp==null) break; 503 clazz=tmp; 504 } 505 return clazz; 506 } 507 }