001: // ========================================================================
002: // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
003: // ------------------------------------------------------------------------
004: // Licensed under the Apache License, Version 2.0 (the "License");
005: // you may not use this file except in compliance with the License.
006: // You may obtain a copy of the License at
007: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014:
015: package org.mortbay.util;
016:
017: import java.io.IOException;
018: import java.io.InputStream;
019: import java.lang.reflect.Constructor;
020: import java.lang.reflect.InvocationTargetException;
021: import java.lang.reflect.Method;
022: import java.net.URL;
023: import java.util.HashMap;
024:
025: import org.mortbay.log.Log;
026:
027: /* ------------------------------------------------------------ */
028: /** TYPE Utilities.
029: * Provides various static utiltiy methods for manipulating types and their
030: * string representations.
031: *
032: * @since Jetty 4.1
033: * @author Greg Wilkins (gregw)
034: */
035: public class TypeUtil {
036: public static int CR = '\015';
037: public static int LF = '\012';
038:
039: /* ------------------------------------------------------------ */
040: private static final HashMap name2Class = new HashMap();
041: static {
042: name2Class.put("boolean", java.lang.Boolean.TYPE);
043: name2Class.put("byte", java.lang.Byte.TYPE);
044: name2Class.put("char", java.lang.Character.TYPE);
045: name2Class.put("double", java.lang.Double.TYPE);
046: name2Class.put("float", java.lang.Float.TYPE);
047: name2Class.put("int", java.lang.Integer.TYPE);
048: name2Class.put("long", java.lang.Long.TYPE);
049: name2Class.put("short", java.lang.Short.TYPE);
050: name2Class.put("void", java.lang.Void.TYPE);
051:
052: name2Class
053: .put("java.lang.Boolean.TYPE", java.lang.Boolean.TYPE);
054: name2Class.put("java.lang.Byte.TYPE", java.lang.Byte.TYPE);
055: name2Class.put("java.lang.Character.TYPE",
056: java.lang.Character.TYPE);
057: name2Class.put("java.lang.Double.TYPE", java.lang.Double.TYPE);
058: name2Class.put("java.lang.Float.TYPE", java.lang.Float.TYPE);
059: name2Class
060: .put("java.lang.Integer.TYPE", java.lang.Integer.TYPE);
061: name2Class.put("java.lang.Long.TYPE", java.lang.Long.TYPE);
062: name2Class.put("java.lang.Short.TYPE", java.lang.Short.TYPE);
063: name2Class.put("java.lang.Void.TYPE", java.lang.Void.TYPE);
064:
065: name2Class.put("java.lang.Boolean", java.lang.Boolean.class);
066: name2Class.put("java.lang.Byte", java.lang.Byte.class);
067: name2Class
068: .put("java.lang.Character", java.lang.Character.class);
069: name2Class.put("java.lang.Double", java.lang.Double.class);
070: name2Class.put("java.lang.Float", java.lang.Float.class);
071: name2Class.put("java.lang.Integer", java.lang.Integer.class);
072: name2Class.put("java.lang.Long", java.lang.Long.class);
073: name2Class.put("java.lang.Short", java.lang.Short.class);
074:
075: name2Class.put("Boolean", java.lang.Boolean.class);
076: name2Class.put("Byte", java.lang.Byte.class);
077: name2Class.put("Character", java.lang.Character.class);
078: name2Class.put("Double", java.lang.Double.class);
079: name2Class.put("Float", java.lang.Float.class);
080: name2Class.put("Integer", java.lang.Integer.class);
081: name2Class.put("Long", java.lang.Long.class);
082: name2Class.put("Short", java.lang.Short.class);
083:
084: name2Class.put(null, java.lang.Void.TYPE);
085: name2Class.put("string", java.lang.String.class);
086: name2Class.put("String", java.lang.String.class);
087: name2Class.put("java.lang.String", java.lang.String.class);
088: }
089:
090: /* ------------------------------------------------------------ */
091: private static final HashMap class2Name = new HashMap();
092: static {
093: class2Name.put(java.lang.Boolean.TYPE, "boolean");
094: class2Name.put(java.lang.Byte.TYPE, "byte");
095: class2Name.put(java.lang.Character.TYPE, "char");
096: class2Name.put(java.lang.Double.TYPE, "double");
097: class2Name.put(java.lang.Float.TYPE, "float");
098: class2Name.put(java.lang.Integer.TYPE, "int");
099: class2Name.put(java.lang.Long.TYPE, "long");
100: class2Name.put(java.lang.Short.TYPE, "short");
101: class2Name.put(java.lang.Void.TYPE, "void");
102:
103: class2Name.put(java.lang.Boolean.class, "java.lang.Boolean");
104: class2Name.put(java.lang.Byte.class, "java.lang.Byte");
105: class2Name
106: .put(java.lang.Character.class, "java.lang.Character");
107: class2Name.put(java.lang.Double.class, "java.lang.Double");
108: class2Name.put(java.lang.Float.class, "java.lang.Float");
109: class2Name.put(java.lang.Integer.class, "java.lang.Integer");
110: class2Name.put(java.lang.Long.class, "java.lang.Long");
111: class2Name.put(java.lang.Short.class, "java.lang.Short");
112:
113: class2Name.put(null, "void");
114: name2Class.put(java.lang.String.class, "java.lang.String");
115: }
116:
117: /* ------------------------------------------------------------ */
118: private static final HashMap class2Value = new HashMap();
119: static {
120: try {
121: Class[] s = { java.lang.String.class };
122:
123: class2Value.put(java.lang.Boolean.TYPE,
124: java.lang.Boolean.class.getMethod("valueOf", s));
125: class2Value.put(java.lang.Byte.TYPE, java.lang.Byte.class
126: .getMethod("valueOf", s));
127: class2Value.put(java.lang.Double.TYPE,
128: java.lang.Double.class.getMethod("valueOf", s));
129: class2Value.put(java.lang.Float.TYPE, java.lang.Float.class
130: .getMethod("valueOf", s));
131: class2Value.put(java.lang.Integer.TYPE,
132: java.lang.Integer.class.getMethod("valueOf", s));
133: class2Value.put(java.lang.Long.TYPE, java.lang.Long.class
134: .getMethod("valueOf", s));
135: class2Value.put(java.lang.Short.TYPE, java.lang.Short.class
136: .getMethod("valueOf", s));
137:
138: class2Value.put(java.lang.Boolean.class,
139: java.lang.Boolean.class.getMethod("valueOf", s));
140: class2Value.put(java.lang.Byte.class, java.lang.Byte.class
141: .getMethod("valueOf", s));
142: class2Value.put(java.lang.Double.class,
143: java.lang.Double.class.getMethod("valueOf", s));
144: class2Value.put(java.lang.Float.class,
145: java.lang.Float.class.getMethod("valueOf", s));
146: class2Value.put(java.lang.Integer.class,
147: java.lang.Integer.class.getMethod("valueOf", s));
148: class2Value.put(java.lang.Long.class, java.lang.Long.class
149: .getMethod("valueOf", s));
150: class2Value.put(java.lang.Short.class,
151: java.lang.Short.class.getMethod("valueOf", s));
152: } catch (Exception e) {
153: e.printStackTrace();
154: }
155: }
156:
157: /* ------------------------------------------------------------ */
158: private static Class[] stringArg = { java.lang.String.class };
159:
160: /* ------------------------------------------------------------ */
161: private static int intCacheSize = Integer.getInteger(
162: "org.mortbay.util.TypeUtil.IntegerCacheSize", 600)
163: .intValue();
164: private static Integer[] integerCache = new Integer[intCacheSize];
165: private static String[] integerStrCache = new String[intCacheSize];
166: private static Integer minusOne = new Integer(-1);
167:
168: /* ------------------------------------------------------------ */
169: /** Class from a canonical name for a type.
170: * @param name A class or type name.
171: * @return A class , which may be a primitive TYPE field..
172: */
173: public static Class fromName(String name) {
174: return (Class) name2Class.get(name);
175: }
176:
177: /* ------------------------------------------------------------ */
178: /** Canonical name for a type.
179: * @param type A class , which may be a primitive TYPE field.
180: * @return Canonical name.
181: */
182: public static String toName(Class type) {
183: return (String) class2Name.get(type);
184: }
185:
186: /* ------------------------------------------------------------ */
187: /** Convert String value to instance.
188: * @param type The class of the instance, which may be a primitive TYPE field.
189: * @param value The value as a string.
190: * @return The value as an Object.
191: */
192: public static Object valueOf(Class type, String value) {
193: try {
194: if (type.equals(java.lang.String.class))
195: return value;
196:
197: Method m = (Method) class2Value.get(type);
198: if (m != null)
199: return m.invoke(null, new Object[] { value });
200:
201: if (type.equals(java.lang.Character.TYPE)
202: || type.equals(java.lang.Character.class))
203: return new Character(value.charAt(0));
204:
205: Constructor c = type.getConstructor(stringArg);
206: return c.newInstance(new Object[] { value });
207: } catch (NoSuchMethodException e) {
208: // LogSupport.ignore(log,e);
209: } catch (IllegalAccessException e) {
210: // LogSupport.ignore(log,e);
211: } catch (InstantiationException e) {
212: // LogSupport.ignore(log,e);
213: } catch (InvocationTargetException e) {
214: if (e.getTargetException() instanceof Error)
215: throw (Error) (e.getTargetException());
216: // LogSupport.ignore(log,e);
217: }
218: return null;
219: }
220:
221: /* ------------------------------------------------------------ */
222: /** Convert String value to instance.
223: * @param type classname or type (eg int)
224: * @param value The value as a string.
225: * @return The value as an Object.
226: */
227: public static Object valueOf(String type, String value) {
228: return valueOf(fromName(type), value);
229: }
230:
231: /* ------------------------------------------------------------ */
232: /** Convert int to Integer using cache.
233: */
234: public static Integer newInteger(int i) {
235: if (i >= 0 && i < intCacheSize) {
236: if (integerCache[i] == null)
237: integerCache[i] = new Integer(i);
238: return integerCache[i];
239: } else if (i == -1)
240: return minusOne;
241: return new Integer(i);
242: }
243:
244: /* ------------------------------------------------------------ */
245: /** Convert int to String using cache.
246: */
247: public static String toString(int i) {
248: if (i >= 0 && i < intCacheSize) {
249: if (integerStrCache[i] == null)
250: integerStrCache[i] = Integer.toString(i);
251: return integerStrCache[i];
252: } else if (i == -1)
253: return "-1";
254: return Integer.toString(i);
255: }
256:
257: /* ------------------------------------------------------------ */
258: /** Convert long to String using cache.
259: */
260: public static String toString(long i) {
261: if (i >= 0 && i < intCacheSize) {
262: if (integerStrCache[(int) i] == null)
263: integerStrCache[(int) i] = Long.toString(i);
264: return integerStrCache[(int) i];
265: } else if (i == -1)
266: return "-1";
267: return Long.toString(i);
268: }
269:
270: /* ------------------------------------------------------------ */
271: /** Parse an int from a substring.
272: * Negative numbers are not handled.
273: * @param s String
274: * @param offset Offset within string
275: * @param length Length of integer or -1 for remainder of string
276: * @param base base of the integer
277: * @exception NumberFormatException
278: */
279: public static int parseInt(String s, int offset, int length,
280: int base) throws NumberFormatException {
281: int value = 0;
282:
283: if (length < 0)
284: length = s.length() - offset;
285:
286: for (int i = 0; i < length; i++) {
287: char c = s.charAt(offset + i);
288:
289: int digit = c - '0';
290: if (digit < 0 || digit >= base || digit >= 10) {
291: digit = 10 + c - 'A';
292: if (digit < 10 || digit >= base)
293: digit = 10 + c - 'a';
294: }
295: if (digit < 0 || digit >= base)
296: throw new NumberFormatException(s.substring(offset,
297: offset + length));
298: value = value * base + digit;
299: }
300: return value;
301: }
302:
303: /* ------------------------------------------------------------ */
304: /** Parse an int from a byte array of ascii characters.
305: * Negative numbers are not handled.
306: * @param b byte array
307: * @param offset Offset within string
308: * @param length Length of integer or -1 for remainder of string
309: * @param base base of the integer
310: * @exception NumberFormatException
311: */
312: public static int parseInt(byte[] b, int offset, int length,
313: int base) throws NumberFormatException {
314: int value = 0;
315:
316: if (length < 0)
317: length = b.length - offset;
318:
319: for (int i = 0; i < length; i++) {
320: char c = (char) (0xff & b[offset + i]);
321:
322: int digit = c - '0';
323: if (digit < 0 || digit >= base || digit >= 10) {
324: digit = 10 + c - 'A';
325: if (digit < 10 || digit >= base)
326: digit = 10 + c - 'a';
327: }
328: if (digit < 0 || digit >= base)
329: throw new NumberFormatException(new String(b, offset,
330: length));
331: value = value * base + digit;
332: }
333: return value;
334: }
335:
336: /* ------------------------------------------------------------ */
337: public static byte[] parseBytes(String s, int base) {
338: byte[] bytes = new byte[s.length() / 2];
339: for (int i = 0; i < s.length(); i += 2)
340: bytes[i / 2] = (byte) TypeUtil.parseInt(s, i, 2, base);
341: return bytes;
342: }
343:
344: /* ------------------------------------------------------------ */
345: public static String toString(byte[] bytes, int base) {
346: StringBuffer buf = new StringBuffer();
347: for (int i = 0; i < bytes.length; i++) {
348: int bi = 0xff & bytes[i];
349: int c = '0' + (bi / base) % base;
350: if (c > '9')
351: c = 'a' + (c - '0' - 10);
352: buf.append((char) c);
353: c = '0' + bi % base;
354: if (c > '9')
355: c = 'a' + (c - '0' - 10);
356: buf.append((char) c);
357: }
358: return buf.toString();
359: }
360:
361: /* ------------------------------------------------------------ */
362: /**
363: * @param b An ASCII encoded character 0-9 a-f A-F
364: * @return The byte value of the character 0-16.
365: */
366: public static byte convertHexDigit(byte b) {
367: if ((b >= '0') && (b <= '9'))
368: return (byte) (b - '0');
369: if ((b >= 'a') && (b <= 'f'))
370: return (byte) (b - 'a' + 10);
371: if ((b >= 'A') && (b <= 'F'))
372: return (byte) (b - 'A' + 10);
373: return 0;
374: }
375:
376: /* ------------------------------------------------------------ */
377: public static String toHexString(byte[] b) {
378: StringBuffer buf = new StringBuffer();
379: for (int i = 0; i < b.length; i++) {
380: int bi = 0xff & b[i];
381: int c = '0' + (bi / 16) % 16;
382: if (c > '9')
383: c = 'A' + (c - '0' - 10);
384: buf.append((char) c);
385: c = '0' + bi % 16;
386: if (c > '9')
387: c = 'a' + (c - '0' - 10);
388: buf.append((char) c);
389: }
390: return buf.toString();
391: }
392:
393: /* ------------------------------------------------------------ */
394: public static String toHexString(byte[] b, int offset, int length) {
395: StringBuffer buf = new StringBuffer();
396: for (int i = offset; i < offset + length; i++) {
397: int bi = 0xff & b[i];
398: int c = '0' + (bi / 16) % 16;
399: if (c > '9')
400: c = 'A' + (c - '0' - 10);
401: buf.append((char) c);
402: c = '0' + bi % 16;
403: if (c > '9')
404: c = 'a' + (c - '0' - 10);
405: buf.append((char) c);
406: }
407: return buf.toString();
408: }
409:
410: /* ------------------------------------------------------------ */
411: public static byte[] fromHexString(String s) {
412: if (s.length() % 2 != 0)
413: throw new IllegalArgumentException(s);
414: byte[] array = new byte[s.length() / 2];
415: for (int i = 0; i < array.length; i++) {
416: int b = Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16);
417: array[i] = (byte) (0xff & b);
418: }
419: return array;
420: }
421:
422: public static void dump(Class c) {
423: System.err.println("Dump: " + c);
424: dump(c.getClassLoader());
425: }
426:
427: public static void dump(ClassLoader cl) {
428: System.err.println("Dump Loaders:");
429: while (cl != null) {
430: System.err.println(" loader " + cl);
431: cl = cl.getParent();
432: }
433: }
434:
435: /* ------------------------------------------------------------ */
436: public static byte[] readLine(InputStream in) throws IOException {
437: byte[] buf = new byte[256];
438:
439: int i = 0;
440: int loops = 0;
441: int ch = 0;
442:
443: while (true) {
444: ch = in.read();
445: if (ch < 0)
446: break;
447: loops++;
448:
449: // skip a leading LF's
450: if (loops == 1 && ch == LF)
451: continue;
452:
453: if (ch == CR || ch == LF)
454: break;
455:
456: if (i >= buf.length) {
457: byte[] old_buf = buf;
458: buf = new byte[old_buf.length + 256];
459: System.arraycopy(old_buf, 0, buf, 0, old_buf.length);
460: }
461: buf[i++] = (byte) ch;
462: }
463:
464: if (ch == -1 && i == 0)
465: return null;
466:
467: // skip a trailing LF if it exists
468: if (ch == CR && in.available() >= 1 && in.markSupported()) {
469: in.mark(1);
470: ch = in.read();
471: if (ch != LF)
472: in.reset();
473: }
474:
475: byte[] old_buf = buf;
476: buf = new byte[i];
477: System.arraycopy(old_buf, 0, buf, 0, i);
478:
479: return buf;
480: }
481:
482: public static URL jarFor(String className) {
483: try {
484: className = className.replace('.', '/') + ".class";
485: // hack to discover jstl libraries
486: URL url = Loader.getResource(null, className, false);
487: String s = url.toString();
488: if (s.startsWith("jar:file:"))
489: return new URL(s.substring(4, s.indexOf("!/")));
490: } catch (Exception e) {
491: Log.ignore(e);
492: }
493: return null;
494: }
495: }
|