1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4 // ------------------------------------------------------------------------ 5 // All rights reserved. This program and the accompanying materials 6 // are made available under the terms of the Eclipse Public License v1.0 7 // and Apache License v2.0 which accompanies this distribution. 8 // 9 // The Eclipse Public License is available at 10 // http://www.eclipse.org/legal/epl-v10.html 11 // 12 // The Apache License v2.0 is available at 13 // http://www.opensource.org/licenses/apache2.0.php 14 // 15 // You may elect to redistribute this code under either of these licenses. 16 // ======================================================================== 17 // 18 19 package org.eclipse.jetty.util; 20 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.lang.reflect.Constructor; 24 import java.lang.reflect.InvocationTargetException; 25 import java.lang.reflect.Method; 26 import java.lang.reflect.Modifier; 27 import java.net.URL; 28 import java.util.Arrays; 29 import java.util.Collections; 30 import java.util.HashMap; 31 import java.util.List; 32 33 import org.eclipse.jetty.util.log.Log; 34 import org.eclipse.jetty.util.log.Logger; 35 36 37 /* ------------------------------------------------------------ */ 38 /** 39 * TYPE Utilities. 40 * Provides various static utiltiy methods for manipulating types and their 41 * string representations. 42 * 43 * @since Jetty 4.1 44 */ 45 public class TypeUtil 46 { 47 private static final Logger LOG = Log.getLogger(TypeUtil.class); 48 public static int CR = '\015'; 49 public static int LF = '\012'; 50 51 /* ------------------------------------------------------------ */ 52 private static final HashMap<String, Class<?>> name2Class=new HashMap<String, Class<?>>(); 53 static 54 { 55 name2Class.put("boolean",java.lang.Boolean.TYPE); 56 name2Class.put("byte",java.lang.Byte.TYPE); 57 name2Class.put("char",java.lang.Character.TYPE); 58 name2Class.put("double",java.lang.Double.TYPE); 59 name2Class.put("float",java.lang.Float.TYPE); 60 name2Class.put("int",java.lang.Integer.TYPE); 61 name2Class.put("long",java.lang.Long.TYPE); 62 name2Class.put("short",java.lang.Short.TYPE); 63 name2Class.put("void",java.lang.Void.TYPE); 64 65 name2Class.put("java.lang.Boolean.TYPE",java.lang.Boolean.TYPE); 66 name2Class.put("java.lang.Byte.TYPE",java.lang.Byte.TYPE); 67 name2Class.put("java.lang.Character.TYPE",java.lang.Character.TYPE); 68 name2Class.put("java.lang.Double.TYPE",java.lang.Double.TYPE); 69 name2Class.put("java.lang.Float.TYPE",java.lang.Float.TYPE); 70 name2Class.put("java.lang.Integer.TYPE",java.lang.Integer.TYPE); 71 name2Class.put("java.lang.Long.TYPE",java.lang.Long.TYPE); 72 name2Class.put("java.lang.Short.TYPE",java.lang.Short.TYPE); 73 name2Class.put("java.lang.Void.TYPE",java.lang.Void.TYPE); 74 75 name2Class.put("java.lang.Boolean",java.lang.Boolean.class); 76 name2Class.put("java.lang.Byte",java.lang.Byte.class); 77 name2Class.put("java.lang.Character",java.lang.Character.class); 78 name2Class.put("java.lang.Double",java.lang.Double.class); 79 name2Class.put("java.lang.Float",java.lang.Float.class); 80 name2Class.put("java.lang.Integer",java.lang.Integer.class); 81 name2Class.put("java.lang.Long",java.lang.Long.class); 82 name2Class.put("java.lang.Short",java.lang.Short.class); 83 84 name2Class.put("Boolean",java.lang.Boolean.class); 85 name2Class.put("Byte",java.lang.Byte.class); 86 name2Class.put("Character",java.lang.Character.class); 87 name2Class.put("Double",java.lang.Double.class); 88 name2Class.put("Float",java.lang.Float.class); 89 name2Class.put("Integer",java.lang.Integer.class); 90 name2Class.put("Long",java.lang.Long.class); 91 name2Class.put("Short",java.lang.Short.class); 92 name2Class.put(null,java.lang.Void.TYPE)93 name2Class.put(null,java.lang.Void.TYPE); 94 name2Class.put("string",java.lang.String.class); 95 name2Class.put("String",java.lang.String.class); 96 name2Class.put("java.lang.String",java.lang.String.class); 97 } 98 99 /* ------------------------------------------------------------ */ 100 private static final HashMap<Class<?>, String> class2Name=new HashMap<Class<?>, String>(); 101 static 102 { class2Name.put(java.lang.Boolean.TYPE,"boolean")103 class2Name.put(java.lang.Boolean.TYPE,"boolean"); class2Name.put(java.lang.Byte.TYPE,"byte")104 class2Name.put(java.lang.Byte.TYPE,"byte"); class2Name.put(java.lang.Character.TYPE,"char")105 class2Name.put(java.lang.Character.TYPE,"char"); class2Name.put(java.lang.Double.TYPE,"double")106 class2Name.put(java.lang.Double.TYPE,"double"); class2Name.put(java.lang.Float.TYPE,"float")107 class2Name.put(java.lang.Float.TYPE,"float"); class2Name.put(java.lang.Integer.TYPE,"int")108 class2Name.put(java.lang.Integer.TYPE,"int"); class2Name.put(java.lang.Long.TYPE,"long")109 class2Name.put(java.lang.Long.TYPE,"long"); class2Name.put(java.lang.Short.TYPE,"short")110 class2Name.put(java.lang.Short.TYPE,"short"); class2Name.put(java.lang.Void.TYPE,"void")111 class2Name.put(java.lang.Void.TYPE,"void"); 112 class2Name.put(java.lang.Boolean.class,"java.lang.Boolean")113 class2Name.put(java.lang.Boolean.class,"java.lang.Boolean"); class2Name.put(java.lang.Byte.class,"java.lang.Byte")114 class2Name.put(java.lang.Byte.class,"java.lang.Byte"); class2Name.put(java.lang.Character.class,"java.lang.Character")115 class2Name.put(java.lang.Character.class,"java.lang.Character"); class2Name.put(java.lang.Double.class,"java.lang.Double")116 class2Name.put(java.lang.Double.class,"java.lang.Double"); class2Name.put(java.lang.Float.class,"java.lang.Float")117 class2Name.put(java.lang.Float.class,"java.lang.Float"); class2Name.put(java.lang.Integer.class,"java.lang.Integer")118 class2Name.put(java.lang.Integer.class,"java.lang.Integer"); class2Name.put(java.lang.Long.class,"java.lang.Long")119 class2Name.put(java.lang.Long.class,"java.lang.Long"); class2Name.put(java.lang.Short.class,"java.lang.Short")120 class2Name.put(java.lang.Short.class,"java.lang.Short"); 121 class2Name.put(null,"void")122 class2Name.put(null,"void"); class2Name.put(java.lang.String.class,"java.lang.String")123 class2Name.put(java.lang.String.class,"java.lang.String"); 124 } 125 126 /* ------------------------------------------------------------ */ 127 private static final HashMap<Class<?>, Method> class2Value=new HashMap<Class<?>, Method>(); 128 static 129 { 130 try 131 { 132 Class<?>[] s ={java.lang.String.class}; 133 class2Value.put(java.lang.Boolean.TYPE, java.lang.Boolean.class.getMethod("valueOf",s))134 class2Value.put(java.lang.Boolean.TYPE, 135 java.lang.Boolean.class.getMethod("valueOf",s)); class2Value.put(java.lang.Byte.TYPE, java.lang.Byte.class.getMethod("valueOf",s))136 class2Value.put(java.lang.Byte.TYPE, 137 java.lang.Byte.class.getMethod("valueOf",s)); class2Value.put(java.lang.Double.TYPE, java.lang.Double.class.getMethod("valueOf",s))138 class2Value.put(java.lang.Double.TYPE, 139 java.lang.Double.class.getMethod("valueOf",s)); class2Value.put(java.lang.Float.TYPE, java.lang.Float.class.getMethod("valueOf",s))140 class2Value.put(java.lang.Float.TYPE, 141 java.lang.Float.class.getMethod("valueOf",s)); class2Value.put(java.lang.Integer.TYPE, java.lang.Integer.class.getMethod("valueOf",s))142 class2Value.put(java.lang.Integer.TYPE, 143 java.lang.Integer.class.getMethod("valueOf",s)); class2Value.put(java.lang.Long.TYPE, java.lang.Long.class.getMethod("valueOf",s))144 class2Value.put(java.lang.Long.TYPE, 145 java.lang.Long.class.getMethod("valueOf",s)); class2Value.put(java.lang.Short.TYPE, java.lang.Short.class.getMethod("valueOf",s))146 class2Value.put(java.lang.Short.TYPE, 147 java.lang.Short.class.getMethod("valueOf",s)); 148 class2Value.put(java.lang.Boolean.class, java.lang.Boolean.class.getMethod("valueOf",s))149 class2Value.put(java.lang.Boolean.class, 150 java.lang.Boolean.class.getMethod("valueOf",s)); class2Value.put(java.lang.Byte.class, java.lang.Byte.class.getMethod("valueOf",s))151 class2Value.put(java.lang.Byte.class, 152 java.lang.Byte.class.getMethod("valueOf",s)); class2Value.put(java.lang.Double.class, java.lang.Double.class.getMethod("valueOf",s))153 class2Value.put(java.lang.Double.class, 154 java.lang.Double.class.getMethod("valueOf",s)); class2Value.put(java.lang.Float.class, java.lang.Float.class.getMethod("valueOf",s))155 class2Value.put(java.lang.Float.class, 156 java.lang.Float.class.getMethod("valueOf",s)); class2Value.put(java.lang.Integer.class, java.lang.Integer.class.getMethod("valueOf",s))157 class2Value.put(java.lang.Integer.class, 158 java.lang.Integer.class.getMethod("valueOf",s)); class2Value.put(java.lang.Long.class, java.lang.Long.class.getMethod("valueOf",s))159 class2Value.put(java.lang.Long.class, 160 java.lang.Long.class.getMethod("valueOf",s)); class2Value.put(java.lang.Short.class, java.lang.Short.class.getMethod("valueOf",s))161 class2Value.put(java.lang.Short.class, 162 java.lang.Short.class.getMethod("valueOf",s)); 163 } 164 catch(Exception e) 165 { 166 throw new Error(e); 167 } 168 } 169 170 /* ------------------------------------------------------------ */ 171 /** Array to List. 172 * <p> 173 * Works like {@link Arrays#asList(Object...)}, but handles null arrays. 174 * @return a list backed by the array. 175 */ asList(T[] a)176 public static <T> List<T> asList(T[] a) 177 { 178 if (a==null) 179 return Collections.emptyList(); 180 return Arrays.asList(a); 181 } 182 183 /* ------------------------------------------------------------ */ 184 /** Class from a canonical name for a type. 185 * @param name A class or type name. 186 * @return A class , which may be a primitive TYPE field.. 187 */ fromName(String name)188 public static Class<?> fromName(String name) 189 { 190 return name2Class.get(name); 191 } 192 193 /* ------------------------------------------------------------ */ 194 /** Canonical name for a type. 195 * @param type A class , which may be a primitive TYPE field. 196 * @return Canonical name. 197 */ toName(Class<?> type)198 public static String toName(Class<?> type) 199 { 200 return class2Name.get(type); 201 } 202 203 /* ------------------------------------------------------------ */ 204 /** Convert String value to instance. 205 * @param type The class of the instance, which may be a primitive TYPE field. 206 * @param value The value as a string. 207 * @return The value as an Object. 208 */ valueOf(Class<?> type, String value)209 public static Object valueOf(Class<?> type, String value) 210 { 211 try 212 { 213 if (type.equals(java.lang.String.class)) 214 return value; 215 216 Method m = class2Value.get(type); 217 if (m!=null) 218 return m.invoke(null, value); 219 220 if (type.equals(java.lang.Character.TYPE) || 221 type.equals(java.lang.Character.class)) 222 return new Character(value.charAt(0)); 223 224 Constructor<?> c = type.getConstructor(java.lang.String.class); 225 return c.newInstance(value); 226 } 227 catch(NoSuchMethodException e) 228 { 229 // LogSupport.ignore(log,e); 230 } 231 catch(IllegalAccessException e) 232 { 233 // LogSupport.ignore(log,e); 234 } 235 catch(InstantiationException e) 236 { 237 // LogSupport.ignore(log,e); 238 } 239 catch(InvocationTargetException e) 240 { 241 if (e.getTargetException() instanceof Error) 242 throw (Error)(e.getTargetException()); 243 // LogSupport.ignore(log,e); 244 } 245 return null; 246 } 247 248 /* ------------------------------------------------------------ */ 249 /** Convert String value to instance. 250 * @param type classname or type (eg int) 251 * @param value The value as a string. 252 * @return The value as an Object. 253 */ valueOf(String type, String value)254 public static Object valueOf(String type, String value) 255 { 256 return valueOf(fromName(type),value); 257 } 258 259 /* ------------------------------------------------------------ */ 260 /** Parse an int from a substring. 261 * Negative numbers are not handled. 262 * @param s String 263 * @param offset Offset within string 264 * @param length Length of integer or -1 for remainder of string 265 * @param base base of the integer 266 * @return the parsed integer 267 * @throws NumberFormatException if the string cannot be parsed 268 */ parseInt(String s, int offset, int length, int base)269 public static int parseInt(String s, int offset, int length, int base) 270 throws NumberFormatException 271 { 272 int value=0; 273 274 if (length<0) 275 length=s.length()-offset; 276 277 for (int i=0;i<length;i++) 278 { 279 char c=s.charAt(offset+i); 280 281 int digit=convertHexDigit((int)c); 282 if (digit<0 || digit>=base) 283 throw new NumberFormatException(s.substring(offset,offset+length)); 284 value=value*base+digit; 285 } 286 return value; 287 } 288 289 /* ------------------------------------------------------------ */ 290 /** Parse an int from a byte array of ascii characters. 291 * Negative numbers are not handled. 292 * @param b byte array 293 * @param offset Offset within string 294 * @param length Length of integer or -1 for remainder of string 295 * @param base base of the integer 296 * @return the parsed integer 297 * @throws NumberFormatException if the array cannot be parsed into an integer 298 */ parseInt(byte[] b, int offset, int length, int base)299 public static int parseInt(byte[] b, int offset, int length, int base) 300 throws NumberFormatException 301 { 302 int value=0; 303 304 if (length<0) 305 length=b.length-offset; 306 307 for (int i=0;i<length;i++) 308 { 309 char c=(char)(0xff&b[offset+i]); 310 311 int digit=c-'0'; 312 if (digit<0 || digit>=base || digit>=10) 313 { 314 digit=10+c-'A'; 315 if (digit<10 || digit>=base) 316 digit=10+c-'a'; 317 } 318 if (digit<0 || digit>=base) 319 throw new NumberFormatException(new String(b,offset,length)); 320 value=value*base+digit; 321 } 322 return value; 323 } 324 325 /* ------------------------------------------------------------ */ parseBytes(String s, int base)326 public static byte[] parseBytes(String s, int base) 327 { 328 byte[] bytes=new byte[s.length()/2]; 329 for (int i=0;i<s.length();i+=2) 330 bytes[i/2]=(byte)TypeUtil.parseInt(s,i,2,base); 331 return bytes; 332 } 333 334 /* ------------------------------------------------------------ */ toString(byte[] bytes, int base)335 public static String toString(byte[] bytes, int base) 336 { 337 StringBuilder buf = new StringBuilder(); 338 for (byte b : bytes) 339 { 340 int bi=0xff&b; 341 int c='0'+(bi/base)%base; 342 if (c>'9') 343 c= 'a'+(c-'0'-10); 344 buf.append((char)c); 345 c='0'+bi%base; 346 if (c>'9') 347 c= 'a'+(c-'0'-10); 348 buf.append((char)c); 349 } 350 return buf.toString(); 351 } 352 353 /* ------------------------------------------------------------ */ 354 /** 355 * @param c An ASCII encoded character 0-9 a-f A-F 356 * @return The byte value of the character 0-16. 357 */ convertHexDigit( byte c )358 public static byte convertHexDigit( byte c ) 359 { 360 byte b = (byte)((c & 0x1f) + ((c >> 6) * 0x19) - 0x10); 361 if (b<0 || b>15) 362 throw new IllegalArgumentException("!hex "+c); 363 return b; 364 } 365 366 /* ------------------------------------------------------------ */ 367 /** 368 * @param c An ASCII encoded character 0-9 a-f A-F 369 * @return The byte value of the character 0-16. 370 */ convertHexDigit( int c )371 public static int convertHexDigit( int c ) 372 { 373 int d= ((c & 0x1f) + ((c >> 6) * 0x19) - 0x10); 374 if (d<0 || d>15) 375 throw new NumberFormatException("!hex "+c); 376 return d; 377 } 378 379 /* ------------------------------------------------------------ */ toHex(byte b,Appendable buf)380 public static void toHex(byte b,Appendable buf) 381 { 382 try 383 { 384 int d=0xf&((0xF0&b)>>4); 385 buf.append((char)((d>9?('A'-10):'0')+d)); 386 d=0xf&b; 387 buf.append((char)((d>9?('A'-10):'0')+d)); 388 } 389 catch(IOException e) 390 { 391 throw new RuntimeException(e); 392 } 393 } 394 395 /* ------------------------------------------------------------ */ toHex(int value,Appendable buf)396 public static void toHex(int value,Appendable buf) throws IOException 397 { 398 int d=0xf&((0xF0000000&value)>>28); 399 buf.append((char)((d>9?('A'-10):'0')+d)); 400 d=0xf&((0x0F000000&value)>>24); 401 buf.append((char)((d>9?('A'-10):'0')+d)); 402 d=0xf&((0x00F00000&value)>>20); 403 buf.append((char)((d>9?('A'-10):'0')+d)); 404 d=0xf&((0x000F0000&value)>>16); 405 buf.append((char)((d>9?('A'-10):'0')+d)); 406 d=0xf&((0x0000F000&value)>>12); 407 buf.append((char)((d>9?('A'-10):'0')+d)); 408 d=0xf&((0x00000F00&value)>>8); 409 buf.append((char)((d>9?('A'-10):'0')+d)); 410 d=0xf&((0x000000F0&value)>>4); 411 buf.append((char)((d>9?('A'-10):'0')+d)); 412 d=0xf&value; 413 buf.append((char)((d>9?('A'-10):'0')+d)); 414 415 Integer.toString(0,36); 416 } 417 418 419 /* ------------------------------------------------------------ */ toHex(long value,Appendable buf)420 public static void toHex(long value,Appendable buf) throws IOException 421 { 422 toHex((int)(value>>32),buf); 423 toHex((int)value,buf); 424 } 425 426 /* ------------------------------------------------------------ */ toHexString(byte b)427 public static String toHexString(byte b) 428 { 429 return toHexString(new byte[]{b}, 0, 1); 430 } 431 432 /* ------------------------------------------------------------ */ toHexString(byte[] b)433 public static String toHexString(byte[] b) 434 { 435 return toHexString(b, 0, b.length); 436 } 437 438 /* ------------------------------------------------------------ */ toHexString(byte[] b,int offset,int length)439 public static String toHexString(byte[] b,int offset,int length) 440 { 441 StringBuilder buf = new StringBuilder(); 442 for (int i=offset;i<offset+length;i++) 443 { 444 int bi=0xff&b[i]; 445 int c='0'+(bi/16)%16; 446 if (c>'9') 447 c= 'A'+(c-'0'-10); 448 buf.append((char)c); 449 c='0'+bi%16; 450 if (c>'9') 451 c= 'a'+(c-'0'-10); 452 buf.append((char)c); 453 } 454 return buf.toString(); 455 } 456 457 /* ------------------------------------------------------------ */ fromHexString(String s)458 public static byte[] fromHexString(String s) 459 { 460 if (s.length()%2!=0) 461 throw new IllegalArgumentException(s); 462 byte[] array = new byte[s.length()/2]; 463 for (int i=0;i<array.length;i++) 464 { 465 int b = Integer.parseInt(s.substring(i*2,i*2+2),16); 466 array[i]=(byte)(0xff&b); 467 } 468 return array; 469 } 470 471 dump(Class<?> c)472 public static void dump(Class<?> c) 473 { 474 System.err.println("Dump: "+c); 475 dump(c.getClassLoader()); 476 } 477 dump(ClassLoader cl)478 public static void dump(ClassLoader cl) 479 { 480 System.err.println("Dump Loaders:"); 481 while(cl!=null) 482 { 483 System.err.println(" loader "+cl); 484 cl = cl.getParent(); 485 } 486 } 487 488 489 /* ------------------------------------------------------------ */ 490 /** 491 * @deprecated 492 */ readLine(InputStream in)493 public static byte[] readLine(InputStream in) throws IOException 494 { 495 byte[] buf = new byte[256]; 496 497 int i=0; 498 int loops=0; 499 int ch=0; 500 501 while (true) 502 { 503 ch=in.read(); 504 if (ch<0) 505 break; 506 loops++; 507 508 // skip a leading LF's 509 if (loops==1 && ch==LF) 510 continue; 511 512 if (ch==CR || ch==LF) 513 break; 514 515 if (i>=buf.length) 516 { 517 byte[] old_buf=buf; 518 buf=new byte[old_buf.length+256]; 519 System.arraycopy(old_buf, 0, buf, 0, old_buf.length); 520 } 521 buf[i++]=(byte)ch; 522 } 523 524 if (ch==-1 && i==0) 525 return null; 526 527 // skip a trailing LF if it exists 528 if (ch==CR && in.available()>=1 && in.markSupported()) 529 { 530 in.mark(1); 531 ch=in.read(); 532 if (ch!=LF) 533 in.reset(); 534 } 535 536 byte[] old_buf=buf; 537 buf=new byte[i]; 538 System.arraycopy(old_buf, 0, buf, 0, i); 539 540 return buf; 541 } 542 jarFor(String className)543 public static URL jarFor(String className) 544 { 545 try 546 { 547 className=className.replace('.','/')+".class"; 548 // hack to discover jstl libraries 549 URL url = Loader.getResource(null,className,false); 550 String s=url.toString(); 551 if (s.startsWith("jar:file:")) 552 return new URL(s.substring(4,s.indexOf("!/"))); 553 } 554 catch(Exception e) 555 { 556 LOG.ignore(e); 557 } 558 return null; 559 } 560 call(Class<?> oClass, String method, Object obj, Object[] arg)561 public static Object call(Class<?> oClass, String method, Object obj, Object[] arg) 562 throws InvocationTargetException, NoSuchMethodException 563 { 564 // Lets just try all methods for now 565 Method[] methods = oClass.getMethods(); 566 for (int c = 0; methods != null && c < methods.length; c++) 567 { 568 if (!methods[c].getName().equals(method)) 569 continue; 570 if (methods[c].getParameterTypes().length != arg.length) 571 continue; 572 if (Modifier.isStatic(methods[c].getModifiers()) != (obj == null)) 573 continue; 574 if ((obj == null) && methods[c].getDeclaringClass() != oClass) 575 continue; 576 577 try 578 { 579 return methods[c].invoke(obj,arg); 580 } 581 catch (IllegalAccessException e) 582 { 583 LOG.ignore(e); 584 } 585 catch (IllegalArgumentException e) 586 { 587 LOG.ignore(e); 588 } 589 } 590 591 throw new NoSuchMethodException(method); 592 } 593 } 594