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