001: /******************************************************************************
002: * JBoss, a division of Red Hat *
003: * Copyright 2006, Red Hat Middleware, LLC, and individual *
004: * contributors as indicated by the @authors tag. See the *
005: * copyright.txt in the distribution for a full listing of *
006: * individual contributors. *
007: * *
008: * This is free software; you can redistribute it and/or modify it *
009: * under the terms of the GNU Lesser General Public License as *
010: * published by the Free Software Foundation; either version 2.1 of *
011: * the License, or (at your option) any later version. *
012: * *
013: * This software is distributed in the hope that it will be useful, *
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of *
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
016: * Lesser General Public License for more details. *
017: * *
018: * You should have received a copy of the GNU Lesser General Public *
019: * License along with this software; if not, write to the Free *
020: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA *
021: * 02110-1301 USA, or see the FSF site: http://www.fsf.org. *
022: ******************************************************************************/package org.jboss.portal.migration.helper;
023:
024: import org.apache.log4j.Level;
025: import org.apache.log4j.Logger;
026:
027: import java.io.IOException;
028: import java.io.InputStream;
029: import java.io.OutputStream;
030: import java.io.PrintWriter;
031: import java.io.Reader;
032: import java.io.StringWriter;
033: import java.io.UnsupportedEncodingException;
034: import java.io.Writer;
035: import java.lang.reflect.InvocationTargetException;
036: import java.lang.reflect.Method;
037: import java.lang.reflect.Modifier;
038: import java.math.BigInteger;
039: import java.net.URL;
040: import java.net.URLClassLoader;
041: import java.net.URLDecoder;
042: import java.net.URLEncoder;
043: import java.net.UnknownHostException;
044: import java.security.MessageDigest;
045: import java.security.NoSuchAlgorithmException;
046: import java.util.ArrayList;
047: import java.util.Calendar;
048: import java.util.Enumeration;
049: import java.util.HashSet;
050: import java.util.Iterator;
051: import java.util.List;
052: import java.util.NoSuchElementException;
053: import java.util.ResourceBundle;
054: import java.util.Set;
055: import java.util.regex.Pattern;
056:
057: /**
058: * @author <a href="mailto:julien@jboss.org">Julien Viet</a>
059: * @author <a href="mailto:theute@jboss.org">Thomas Heute</a>
060: * @version $Revision: 8784 $
061: */
062: public class Tools {
063:
064: public static final int DEFAULT_BUFFER_SIZE = 512;
065:
066: public static final Logger log = Logger.getLogger(Tools.class);
067:
068: private static final Object[] EMPTY_ARGS = new Object[0];
069:
070: private static final Class[] EMPTY_PARAMETER_TYPES = new Class[0];
071:
072: public static final String RE_EMAIL_VALIDATION = "^([a-zA-Z0-9]+(([\\.\\-\\_]?[a-zA-Z0-9]+)+)?)\\@(([a-zA-Z0-9]+[\\.\\-\\_])+[a-zA-Z]{2,4})$";
073:
074: /**
075: * Close an object that implements a close() method.
076: *
077: * @param closable the object to close
078: */
079: public static void safeClose(Object closable) {
080: if (closable != null) {
081: try {
082: Method m = closable.getClass().getMethod("close",
083: Tools.EMPTY_PARAMETER_TYPES);
084: if (!Modifier.isPublic(m.getModifiers())) {
085: log
086: .warn("close() method on closable object is not public");
087: return;
088: }
089: if (Modifier.isStatic(m.getModifiers())) {
090: log
091: .warn("close() method on closable object is static");
092: return;
093: }
094: m.invoke(closable, EMPTY_ARGS);
095: } catch (NoSuchMethodException e) {
096: log
097: .warn(
098: "The closable object does not have a close() method",
099: e);
100: } catch (IllegalAccessException e) {
101: log
102: .warn(
103: "Cannot access close() method on closable object",
104: e);
105: } catch (InvocationTargetException e) {
106: log.error("The close() method threw an exception", e
107: .getTargetException());
108: }
109: }
110: }
111:
112: /**
113: * Close an output stream safely.
114: *
115: * @param out the stream to close
116: */
117: public static void safeClose(OutputStream out) {
118: if (out != null) {
119: try {
120: out.close();
121: } catch (IOException e) {
122: log.error("Error while closing putstream", e);
123: }
124: }
125: }
126:
127: /**
128: * Close an input stream safely.
129: *
130: * @param in the stream to close
131: */
132: public static void safeClose(InputStream in) {
133: if (in != null) {
134: try {
135: in.close();
136: } catch (IOException e) {
137: log.error("Error while closing inputstream", e);
138: }
139: }
140: }
141:
142: /**
143: * Close a reader safely.
144: *
145: * @param reader the stream to close
146: */
147: public static void safeClose(Reader reader) {
148: if (reader != null) {
149: try {
150: reader.close();
151: } catch (IOException e) {
152: log.error("Error while closing inputstream", e);
153: }
154: }
155: }
156:
157: /**
158: * Pipe an input stream in an output stream.
159: *
160: * @param in the incoming stream
161: * @param out the outcoming stream
162: * @throws NullPointerException if an argument is null
163: * @throws IllegalArgumentException if bufferSize < 1
164: */
165: public static void copy(InputStream in, OutputStream out)
166: throws IOException {
167: copy(in, out, DEFAULT_BUFFER_SIZE);
168: }
169:
170: /**
171: * Pipe an incoming stream in an outcoming stream.
172: *
173: * @param in the incoming stream
174: * @param out the outcoming stream
175: * @param bufferSize the buffer size
176: * @throws NullPointerException if an argument is null
177: * @throws IllegalArgumentException if bufferSize < 1
178: */
179: public static void copy(InputStream in, OutputStream out,
180: int bufferSize) throws IOException {
181: // arguments check
182: if (in == null) {
183: throw new IllegalArgumentException("null in");
184: }
185: if (out == null) {
186: throw new IllegalArgumentException("null out");
187: }
188: if (bufferSize < 1) {
189: throw new IllegalArgumentException(
190: "Buffer size is too small");
191: }
192:
193: // do the job
194: byte[] buffer = new byte[bufferSize];
195: while (true) {
196: int i = in.read(buffer);
197: if (i == 0) {
198: continue;
199: }
200: if (i == -1) {
201: break;
202: }
203: out.write(buffer, 0, i);
204: }
205: }
206:
207: /** 16 chars long VMID. */
208: public static final String VMID = VMID();
209:
210: private static final String VMID() {
211: try {
212: BigInteger bi = BigInteger.valueOf(0);
213: byte[] address = java.net.InetAddress.getLocalHost()
214: .getAddress();
215: for (int i = 0; i < 4; i++) {
216: bi = bi.shiftLeft(8);
217: bi = bi.add(BigInteger.valueOf(address[i]));
218: }
219: bi = bi.shiftLeft(32);
220: int code = System.identityHashCode(new Object());
221: bi = bi.add(BigInteger.valueOf(code));
222: byte[] bytes = bi.toByteArray();
223: StringBuffer buffer = new StringBuffer();
224: char[] chars = "0123456789ABCDEF".toCharArray();
225: for (int i = 0; i < bytes.length; i++) {
226: buffer.append(chars[(bytes[i] & 0xF0) >> 4]).append(
227: chars[bytes[i] & 0xF]);
228: }
229: return buffer.toString();
230: } catch (UnknownHostException e) {
231: e.printStackTrace(System.err);
232: throw new Error("Cannot create VMID");
233: }
234: }
235:
236: public static final Enumeration EMPTY_ENUMERATION = new Enumeration() {
237: public boolean hasMoreElements() {
238: return false;
239: }
240:
241: public Object nextElement() {
242: throw new NoSuchElementException();
243: }
244: };
245:
246: public static final Iterator EMPTY_ITERATOR = new Iterator() {
247: public boolean hasNext() {
248: return false;
249: }
250:
251: public Object next() {
252: throw new NoSuchElementException();
253: }
254:
255: public void remove() {
256: throw new UnsupportedOperationException();
257: }
258: };
259:
260: public static final ResourceBundle EMPTY_BUNDLE = new ResourceBundle() {
261: protected Object handleGetObject(String key) {
262: return null;
263: }
264:
265: public Enumeration getKeys() {
266: return EMPTY_ENUMERATION;
267: }
268: };
269:
270: public static Enumeration toEnumeration(final Iterator iterator) {
271: return new Enumeration() {
272: public boolean hasMoreElements() {
273: return iterator.hasNext();
274: }
275:
276: public Object nextElement() {
277: return iterator.next();
278: }
279: };
280: }
281:
282: public static Set toSet(Enumeration e) {
283: HashSet set = new HashSet();
284: while (e.hasMoreElements()) {
285: set.add(e.nextElement());
286: }
287: return set;
288: }
289:
290: public static List toList(Enumeration e) {
291: List list = new ArrayList();
292: while (e.hasMoreElements()) {
293: list.add(e.nextElement());
294: }
295: return list;
296: }
297:
298: public static Set toSet(Object[] objects) {
299: HashSet set = new HashSet();
300: for (int i = 0; i < objects.length; i++) {
301: set.add(objects[i]);
302: }
303: return set;
304: }
305:
306: public static Set toSet(final Iterator iterator) {
307: HashSet set = new HashSet();
308: while (iterator.hasNext()) {
309: set.add(iterator.next());
310: }
311: return set;
312: }
313:
314: public static List toList(final Iterator iterator) {
315: List list = new ArrayList();
316: while (iterator.hasNext()) {
317: list.add(iterator.next());
318: }
319: return list;
320: }
321:
322: public static Iterator iterator(final Object o) {
323: return new Iterator() {
324: boolean done = false;
325:
326: public boolean hasNext() {
327: return !done;
328: }
329:
330: public Object next() {
331: if (done) {
332: throw new NoSuchElementException("Already iterated");
333: }
334: done = true;
335: return o;
336: }
337:
338: public void remove() {
339: throw new UnsupportedOperationException("read only");
340: }
341: };
342: }
343:
344: public static Iterator iterator(final Object[] objects) {
345: return new Iterator() {
346: int index = 0;
347:
348: public boolean hasNext() {
349: return objects != null && index < objects.length;
350: }
351:
352: public Object next() {
353: if (objects == null) {
354: throw new NoSuchElementException(
355: "Wrapped array is null");
356: }
357: if (index >= objects.length) {
358: throw new NoSuchElementException(
359: "Index is greater than the array length");
360: }
361: return objects[index++];
362: }
363:
364: public void remove() {
365: throw new UnsupportedOperationException("read only");
366: }
367: };
368: }
369:
370: public static int computeStringHash(int hash, String s) {
371: char[] chars = s.toCharArray();
372: int length = chars.length;
373: for (int i = 0; i < length; i++) {
374: char c = chars[i];
375: hash = 31 * hash + c;
376: }
377: return hash;
378: }
379:
380: public static String encodeXWWWFormURL(String s) {
381: try {
382: return URLEncoder.encode(s, "UTF-8");
383: } catch (UnsupportedEncodingException e) {
384: throw new Error("UTF-8 encoding missing");
385: }
386: }
387:
388: public static String decodeXWWWFormURL(String s) {
389: try {
390: return URLDecoder.decode(s, "UTF-8");
391: } catch (UnsupportedEncodingException e) {
392: throw new Error("UTF-8 encoding missing");
393: }
394: }
395:
396: /** Return true is the address is not null and matches the email validation regular expression. */
397: public static boolean isEmailValid(String address) {
398: return address == null ? false : Pattern.matches(
399: RE_EMAIL_VALIDATION, address);
400: }
401:
402: /**
403: * Computes an md5 hash of a string.
404: *
405: * @param text the hashed string
406: * @return the string hash
407: * @throws NullPointerException if text is null
408: */
409: public static byte[] md5(String text) {
410: // arguments check
411: if (text == null) {
412: throw new NullPointerException("null text");
413: }
414:
415: try {
416: MessageDigest md = MessageDigest.getInstance("MD5");
417: md.update(text.getBytes());
418: return md.digest();
419: } catch (NoSuchAlgorithmException e) {
420: log.error("Cannot find MD5 algorithm", e);
421: throw new RuntimeException("Cannot find MD5 algorithm");
422: }
423: }
424:
425: /**
426: * Computes an md5 hash and returns the result as a string in hexadecimal format.
427: *
428: * @param text the hashed string
429: * @return the string hash
430: * @throws NullPointerException if text is null
431: */
432: public static String md5AsHexString(String text) {
433: return toHexString(md5(text));
434: }
435:
436: /**
437: * Returns a string in the hexadecimal format.
438: *
439: * @param bytes the converted bytes
440: * @return the hexadecimal string representing the bytes data
441: * @throws IllegalArgumentException if the byte array is null
442: */
443: public static String toHexString(byte[] bytes) {
444: if (bytes == null) {
445: throw new IllegalArgumentException(
446: "byte array must not be null");
447: }
448: StringBuffer hex = new StringBuffer(bytes.length * 2);
449: for (int i = 0; i < bytes.length; i++) {
450: hex.append(Character.forDigit((bytes[i] & 0XF0) >> 4, 16));
451: hex.append(Character.forDigit((bytes[i] & 0X0F), 16));
452: }
453: return hex.toString();
454: }
455:
456: /**
457: * Returns a byte array converted from the hexadecimal format.
458: *
459: * @param hex the string to convert
460: * @return the byte array corresponding
461: * @throws IllegalArgumentException if the string is null or does not have the good format
462: */
463: public static byte[] fromHexString(String hex) {
464: if (hex == null) {
465: throw new IllegalArgumentException(
466: "Hex string must not be null");
467: }
468: if (hex.length() % 2 == 1) {
469: throw new IllegalArgumentException(
470: "Hex string length is not even : " + hex.length());
471: }
472: int index = 0;
473: byte[] bytes = new byte[hex.length() / 2];
474: for (int i = 0; i < bytes.length; i++) {
475: char chigh = hex.charAt(index++);
476: int high = Character.digit(chigh, 16);
477: if (high == -1) {
478: throw new IllegalArgumentException(
479: "Hex string contains a bad char : " + chigh);
480: }
481: char clow = hex.charAt(index++);
482: int low = Character.digit(clow, 16);
483: if (low == -1) {
484: throw new IllegalArgumentException(
485: "Hex string contains a bad char : " + clow);
486: }
487: byte value = (byte) ((high << 4) + low);
488: bytes[i] = value;
489: }
490: return bytes;
491: }
492:
493: /**
494: *
495: */
496: public static String generateTemporaryHash(String value, long time) {
497: if (value == null) {
498: throw new IllegalArgumentException("id must not be null");
499: }
500:
501: Calendar calendar = Calendar.getInstance();
502: calendar.setTimeInMillis(time);
503: calendar.set(Calendar.MINUTE, 0);
504: calendar.set(Calendar.SECOND, 0);
505: calendar.set(Calendar.MILLISECOND, 0);
506: return md5AsHexString(value + calendar.getTimeInMillis());
507: }
508:
509: /**
510: *
511: */
512: public static boolean confirmTemporaryHash(String hash,
513: String value, long time) {
514: if (hash == null) {
515: return false;
516: }
517: if (value == null) {
518: throw new IllegalArgumentException("value must not be null");
519: }
520:
521: Calendar calendar = Calendar.getInstance();
522: calendar.setTimeInMillis(time);
523: calendar.set(Calendar.MINUTE, 0);
524: calendar.set(Calendar.SECOND, 0);
525: calendar.set(Calendar.MILLISECOND, 0);
526: String expected = md5AsHexString(value
527: + calendar.getTimeInMillis());
528: if (expected.equals(hash)) {
529: return true;
530: }
531: calendar.add(Calendar.HOUR_OF_DAY, -1);
532: expected = md5AsHexString(value + calendar.getTimeInMillis());
533: return expected.equals(hash);
534: }
535:
536: public static String buildClassLoaderInfo(ClassLoader loader) {
537: if (loader == null) {
538: throw new IllegalArgumentException("no loader");
539: }
540: StringBuffer buffer = new StringBuffer();
541: buffer.append("ClassLoader[Name=").append(
542: loader.getClass().getName());
543: buffer.append(",HashCode=").append(loader.hashCode());
544: buffer.append(",IdentityHashCode=").append(
545: System.identityHashCode(loader));
546: if (loader instanceof URLClassLoader) {
547: URLClassLoader urlLoader = (URLClassLoader) loader;
548: URL[] urls = urlLoader.getURLs();
549: for (int i = 0; i < urls.length; i++) {
550: URL url = urls[i];
551: buffer.append(",URL(").append(i).append(")=").append(
552: url);
553: }
554: }
555: try {
556: Class uclClass = Thread.currentThread()
557: .getContextClassLoader().loadClass(
558: "org.jboss.mx.loading.UnifiedClassLoader");
559: Class loaderClass = loader.getClass();
560: if (uclClass.isAssignableFrom(loaderClass)) {
561: URL url = (URL) loaderClass.getMethod("getURL",
562: new Class[0]).invoke(loader, new Object[0]);
563: buffer.append(",GetURL=").append(url);
564: }
565: } catch (Exception e) {
566: log.error("Cannot get UCL infos", e);
567: }
568: buffer.append("]");
569: return buffer.toString();
570: }
571:
572: public static String dumpClassLoaderHierarchyInfo(ClassLoader loader) {
573: StringWriter writer = new StringWriter();
574: dumpClassLoaderHierarchyInfo(writer, loader);
575: return writer.toString();
576: }
577:
578: public static void dumpClassLoaderHierarchyInfo(Writer writer,
579: ClassLoader loader) {
580: if (writer == null) {
581: throw new IllegalArgumentException("no writer");
582: }
583: if (loader == null) {
584: throw new IllegalArgumentException("no loader");
585: }
586:
587: //
588: PrintWriter pw = null;
589: if (writer instanceof PrintWriter) {
590: pw = (PrintWriter) writer;
591: } else {
592: pw = new PrintWriter(writer);
593: }
594:
595: pw.println("<classloader-dump>");
596: while (loader != null) {
597: pw.println(buildClassLoaderInfo(loader));
598: loader = loader.getParent();
599: }
600: pw.print("</classloader-dump>");
601: pw.flush();
602: }
603:
604: public static void dumpClassLoaderHierarchyInfo(Logger log,
605: ClassLoader loader) {
606: Writer writer = new Log4JWriter(log, Level.DEBUG);
607: dumpClassLoaderHierarchyInfo(writer, loader);
608: }
609:
610: public static void dumpClassLoaderHierarchyInfo(Logger log,
611: Level level, ClassLoader loader) {
612: Writer writer = new Log4JWriter(log, level);
613: dumpClassLoaderHierarchyInfo(writer, loader);
614: }
615:
616: /**
617: * Replace occurence in a string.
618: *
619: * @param string the source string
620: * @param pattern the replaced pattern
621: * @param replacement the replacement text
622: * @return the new string
623: */
624: public static String replace(String string, String pattern,
625: String replacement) {
626: StringBuffer buffer = new StringBuffer(string.length());
627: int previous = 0;
628: int current = string.indexOf(pattern);
629: while (current != -1) {
630: buffer.append(string.substring(previous, current));
631: buffer.append(replacement);
632: previous = current + pattern.length();
633: current = string.indexOf(pattern, previous);
634: }
635: buffer.append(string.substring(previous));
636: return buffer.toString();
637: }
638:
639: public static boolean exists(URL url) {
640: if (url == null) {
641: throw new IllegalArgumentException("No null urls allowed");
642: }
643: InputStream in = null;
644: try {
645: in = url.openStream();
646: return true;
647: } catch (IOException e) {
648: return false;
649: } finally {
650: safeClose(in);
651: }
652: }
653: }
|