001/* 002 * Copyright (C) 2012 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020package org.crsh.util; 021 022import javax.naming.Context; 023import java.io.ByteArrayOutputStream; 024import java.io.Closeable; 025import java.io.Flushable; 026import java.io.IOException; 027import java.io.InputStream; 028import java.io.OutputStream; 029import java.lang.reflect.ParameterizedType; 030import java.lang.reflect.Type; 031import java.lang.reflect.TypeVariable; 032import java.net.Socket; 033import java.sql.*; 034import java.io.File; 035import java.net.URISyntaxException; 036import java.net.URL; 037import java.util.ArrayList; 038import java.util.Arrays; 039import java.util.Collections; 040import java.util.HashMap; 041import java.util.HashSet; 042import java.util.Iterator; 043import java.util.List; 044import java.util.Map; 045import java.util.NoSuchElementException; 046import java.util.regex.Matcher; 047import java.util.regex.Pattern; 048 049public class Utils { 050 051 /** . */ 052 private static final Iterator EMPTY_ITERATOR = Collections.emptyList().iterator(); 053 /** . */ 054 private static final Pattern p = Pattern.compile("\\S+"); 055 056 public static <E> Iterator<E> iterator() { 057 @SuppressWarnings("unchecked") 058 Iterator<E> iterator = (Iterator<E>)EMPTY_ITERATOR; 059 return iterator; 060 } 061 062 public static <E> Iterator<E> iterator(final E element) { 063 return new BaseIterator<E>() { 064 boolean hasNext = true; 065 @Override 066 public boolean hasNext() { 067 return hasNext; 068 } 069 @Override 070 public E next() { 071 if (hasNext) { 072 hasNext = false; 073 return element; 074 } else { 075 throw new NoSuchElementException(); 076 } 077 } 078 }; 079 } 080 081 public static <E> E first(Iterable<E> elements) { 082 Iterator<E> i = elements.iterator(); 083 return i.hasNext() ? i.next() : null; 084 } 085 086 public static <K, V, M extends Map<K, V>> M map(M map, K key, V value) { 087 map.put(key, value); 088 return map; 089 } 090 091 public static <K, V> HashMap<K, V> map(K key, V value) { 092 HashMap<K, V> map = new HashMap<K, V>(); 093 map.put(key, value); 094 return map; 095 } 096 097 public static <E> HashSet<E> set(E... elements) { 098 HashSet<E> set = new HashSet<E>(elements.length); 099 Collections.addAll(set, elements); 100 return set; 101 } 102 103 public static <E> List<E> list(E... elements) { 104 return Arrays.asList(elements); 105 } 106 107 public static <E> List<E> list(Iterable<E> iterable) { 108 return list(iterable.iterator()); 109 } 110 111 public static <E> List<E> list(Iterator<E> iterator) { 112 ArrayList<E> list = new ArrayList<E>(); 113 while (iterator.hasNext()) { 114 list.add(iterator.next()); 115 } 116 return list; 117 } 118 119 public static int indexOf(CharSequence s, int off, char c) { 120 for (int len = s.length();off < len;off++) { 121 if (s.charAt(off) == c) { 122 return off; 123 } 124 } 125 return -1; 126 } 127 128 public static String trimLeft(String s) { 129 if (s == null) { 130 throw new NullPointerException("No null string accepted"); 131 } 132 int index = 0; 133 int len = s.length(); 134 while (index < len) { 135 if (s.charAt(index) == ' ') { 136 index++; 137 } else { 138 break; 139 } 140 } 141 if (index > 0) { 142 return s.substring(index); 143 } else { 144 return s; 145 } 146 } 147 148 private static final Pattern blankPattern = Pattern.compile("^\\s*$"); 149 150 public static boolean notBlank(String s) { 151 return !blankPattern.matcher(s).find(); 152 } 153 154 public static <E> E notNull(E e1, E e2) { 155 if (e1 != null) { 156 return e1; 157 } else { 158 return e2; 159 } 160 } 161 162 private static final Pattern FOO = Pattern.compile("" + 163 "(\\*)" + // Wildcard * 164 "|" + 165 "(\\?)" + // Wildcard ? 166 "|" + 167 "(?:\\[([^)]+)\\])" + // Range 168 "|" + 169 "(\\\\.)" // Escape 170 ); 171 172 /** 173 * Create a pattern that transforms a glob expression into a regular expression, the following task are supported 174 * <ul> 175 * <li>* : Match any number of unknown characters</li> 176 * <li>? : Match one unknown character</li> 177 * <li>[characters] : Match a character as part of a group of characters</li> 178 * <li>\ : Escape character</li> 179 * </ul> 180 * 181 * @param globex the glob expression 182 * @return the regular expression 183 * @throws NullPointerException when the globex argument is null 184 */ 185 public static String globexToRegex(String globex) throws NullPointerException { 186 if (globex == null) { 187 throw new NullPointerException("No null globex accepted"); 188 } 189 StringBuilder regex = new StringBuilder(); 190 int prev = 0; 191 Matcher matcher = FOO.matcher(globex); 192 while (matcher.find()) { 193 int next = matcher.start(); 194 if (next > prev) { 195 regex.append(Pattern.quote(globex.substring(prev, next))); 196 } 197 if (matcher.group(1) != null) { 198 regex.append(".*"); 199 } else if (matcher.group(2) != null) { 200 regex.append("."); 201 } else if (matcher.group(3) != null) { 202 regex.append("["); 203 regex.append(Pattern.quote(matcher.group(3))); 204 regex.append("]"); 205 } else if (matcher.group(4) != null) { 206 regex.append(Pattern.quote(Character.toString(matcher.group(4).charAt(1)))); 207 } else { 208 throw new UnsupportedOperationException("Not handled yet"); 209 } 210 prev = matcher.end(); 211 } 212 if (prev < globex.length()) { 213 regex.append(Pattern.quote(globex.substring(prev))); 214 } 215 return regex.toString(); 216 } 217 218 /** 219<<<<<<< HEAD 220 * Close the socket and catch any exception thrown. 221 * 222 * @param socket the socket to close 223 * @return any Exception thrown during the <code>close</code> operation 224 */ 225 public static Exception close(Socket socket) { 226 if (socket != null) { 227 try { 228 socket.close(); 229 } 230 catch (Exception e) { 231 return e; 232 } 233 } 234 return null; 235 } 236 237 /** 238 * Close the closeable and catch any exception thrown. 239 * 240 * @param closeable the closeable to close 241 * @return any Exception thrown during the <code>close</code> operation 242 */ 243 public static Exception close(Closeable closeable) { 244 if (closeable != null) { 245 try { 246 closeable.close(); 247 } 248 catch (Exception e) { 249 return e; 250 } 251 } 252 return null; 253 } 254 255 /** 256 * Close the connection and catch any exception thrown. 257 * 258 * @param connection the socket to close 259 * @return any Exception thrown during the <code>close</code> operation 260 */ 261 public static Exception close(Connection connection) { 262 if (connection != null) { 263 try { 264 connection.close(); 265 } 266 catch (Exception e) { 267 return e; 268 } 269 } 270 return null; 271 } 272 273 /** 274 * Close the statement and catch any exception thrown. 275 * 276 * @param statement the statement to close 277 * @return any Exception thrown during the <code>close</code> operation 278 */ 279 public static Exception close(java.sql.Statement statement) { 280 if (statement != null) { 281 try { 282 statement.close(); 283 } 284 catch (Exception e) { 285 return e; 286 } 287 } 288 return null; 289 } 290 291 /** 292 * Close the result set and catch any exception thrown. 293 * 294 * @param rs the result set to close 295 * @return any Exception thrown during the <code>close</code> operation 296 */ 297 public static Exception close(ResultSet rs) { 298 if (rs != null) { 299 try { 300 rs.close(); 301 } 302 catch (Exception e) { 303 return e; 304 } 305 } 306 return null; 307 } 308 309 /** 310 * Close the context and catch any exception thrown. 311 * 312 * @param context the context to close 313 * @return any Exception thrown during the <code>close</code> operation 314 */ 315 public static Exception close(Context context) { 316 if (context != null) { 317 try { 318 context.close(); 319 } 320 catch (Exception e) { 321 return e; 322 } 323 } 324 return null; 325 } 326 327 public static <T extends Throwable> void rethrow(Class<T> throwableClass, Throwable cause) throws T { 328 T throwable; 329 330 // 331 try { 332 throwable = throwableClass.newInstance(); 333 } 334 catch (Exception e) { 335 throw new AssertionError(e); 336 } 337 338 // 339 throwable.initCause(cause); 340 341 // 342 throw throwable; 343 } 344 345 public static boolean equals(Object o1, Object o2) { 346 return o1 == null ? o2 == null : (o2 != null && o1.equals(o2)); 347 } 348 349 public static boolean notEquals(Object o1, Object o2) { 350 return !equals(o1, o2); 351 } 352 353 /** 354 * Flush the flushable and catch any exception thrown. 355 * 356 * @param flushable the flushable to flush 357 * @return any Exception thrown during the <code>flush</code> operation 358 */ 359 public static Exception flush(Flushable flushable) { 360 if (flushable != null) { 361 try { 362 flushable.flush(); 363 } 364 catch (Exception e) { 365 return e; 366 } 367 } 368 return null; 369 } 370 371 public static List<String> chunks(CharSequence s) { 372 List<String> chunks = new ArrayList<String>(); 373 Matcher m = p.matcher(s); 374 while (m.find()) { 375 chunks.add(m.group()); 376 } 377 return chunks; 378 } 379 380 public static String join(Iterable<String> strings, String separator) { 381 Iterator<String> i = strings.iterator(); 382 if (i.hasNext()) { 383 String first = i.next(); 384 if (i.hasNext()) { 385 StringBuilder buf = new StringBuilder(); 386 buf.append(first); 387 while (i.hasNext()) { 388 buf.append(separator); 389 buf.append(i.next()); 390 } 391 return buf.toString(); 392 } else { 393 return first; 394 } 395 } else { 396 return ""; 397 } 398 } 399 400 public static String[] split(CharSequence s, char separator) { 401 return foo(s, separator, 0, 0, 0); 402 } 403 404 public static String[] split(CharSequence s, char separator, int rightPadding) { 405 if (rightPadding < 0) { 406 throw new IllegalArgumentException("Right padding cannot be negative"); 407 } 408 return foo(s, separator, 0, 0, rightPadding); 409 } 410 411 private static String[] foo(CharSequence s, char separator, int count, int from, int rightPadding) { 412 int len = s.length(); 413 if (from < len) { 414 int to = from; 415 while (to < len && s.charAt(to) != separator) { 416 to++; 417 } 418 String[] ret; 419 if (to == len - 1) { 420 ret = new String[count + 2 + rightPadding]; 421 ret[count + 1] = ""; 422 } 423 else { 424 ret = to == len ? new String[count + 1 + rightPadding] : foo(s, separator, count + 1, to + 1, rightPadding); 425 } 426 ret[count] = from == to ? "" : s.subSequence(from, to).toString(); 427 return ret; 428 } 429 else if (from == len) { 430 return new String[count + rightPadding]; 431 } 432 else { 433 throw new AssertionError(); 434 } 435 } 436 437 /** 438 * @see #findLongestCommonPrefix(Iterable) 439 */ 440 public static String findLongestCommonPrefix(CharSequence... seqs) { 441 return findLongestCommonPrefix(Arrays.asList(seqs)); 442 } 443 444 /** 445 * Find the longest possible common prefix of the provided char sequence. 446 * 447 * @param seqs the sequences 448 * @return the longest possible prefix 449 */ 450 public static String findLongestCommonPrefix(Iterable<? extends CharSequence> seqs) { 451 String common = ""; 452 out: 453 while (true) { 454 String candidate = null; 455 for (CharSequence s : seqs) { 456 if (common.length() + 1 > s.length()) { 457 break out; 458 } else { 459 if (candidate == null) { 460 candidate = s.subSequence(0, common.length() + 1).toString(); 461 } else if (s.subSequence(0, common.length() + 1).toString().equals(candidate)) { 462 // Ok it is a prefix 463 } else { 464 break out; 465 } 466 } 467 } 468 if (candidate == null) { 469 break; 470 } else { 471 common = candidate; 472 } 473 } 474 return common; 475 } 476 477 public static byte[] readAsBytes(InputStream in) throws IOException { 478 return read(in).toByteArray(); 479 } 480 481 public static String readAsUTF8(InputStream in) { 482 try { 483 ByteArrayOutputStream baos = read(in); 484 return baos.toString("UTF-8"); 485 } 486 catch (IOException e) { 487 e.printStackTrace(); 488 return null; 489 } 490 } 491 492 public static void copy(InputStream in, OutputStream out) throws IOException { 493 if (in == null) { 494 throw new NullPointerException(); 495 } 496 try { 497 byte[] buffer = new byte[256]; 498 for (int l = in.read(buffer); l != -1; l = in.read(buffer)) { 499 out.write(buffer, 0, l); 500 } 501 } 502 finally { 503 close(in); 504 } 505 } 506 507 private static ByteArrayOutputStream read(InputStream in) throws IOException { 508 if (in == null) { 509 throw new NullPointerException(); 510 } 511 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 512 copy(in, baos); 513 return baos; 514 } 515 516 /* 517 * Convert an file URL to a file, avoids issues on windows with whitespaces. 518 * 519 * @param url the URL to convert 520 * @return the related file 521 * @throws java.lang.IllegalArgumentException if the url protocol is not file 522 * @throws java.lang.NullPointerException if the url argument is null 523 */ 524 public static File toFile(URL url) throws IllegalArgumentException, NullPointerException { 525 if (url == null) { 526 throw new NullPointerException("No null URL accepted"); 527 } 528 if (!url.getProtocol().equals("file")) { 529 throw new IllegalArgumentException("Not file protocol"); 530 } 531 try { 532 return new File(url.toURI()); 533 } catch(URISyntaxException e) { 534 return new File(url.getPath()); 535 } 536 } 537 538 public static Class<?> resolveToClass(Type implementation, Class<?> type, int parameterIndex) { 539 if (implementation == null) { 540 throw new NullPointerException("No null type accepted"); 541 } 542 543 // First resolve to type 544 Type resolvedType = resolve(implementation, type, parameterIndex); 545 546 // 547 if (resolvedType != null) { 548 return resolveToClass(resolvedType); 549 } else { 550 return null; 551 } 552 } 553 554 public static Class resolveToClass(Type type) { 555 if (type == null) { 556 throw new NullPointerException("No null type accepted"); 557 } 558 if (type instanceof Class<?>) { 559 return (Class<?>)type; 560 } else if (type instanceof TypeVariable) { 561 TypeVariable resolvedTypeVariable = (TypeVariable)type; 562 return resolveToClass(resolvedTypeVariable.getBounds()[0]); 563 } else { 564 throw new UnsupportedOperationException("Type resolution of " + type + " not yet implemented"); 565 } 566 } 567 568 /** 569 * A simplistic implementation, it may not handle all cases but it should handle enough. 570 * 571 * @param implementation the type for which the parameter requires a resolution 572 * @param type the type that owns the parameter 573 * @param parameterIndex the parameter index 574 * @return the resolved type 575 */ 576 public static Type resolve(Type implementation, Class<?> type, int parameterIndex) { 577 if (implementation == null) { 578 throw new NullPointerException(); 579 } 580 581 // 582 if (implementation == type) { 583 TypeVariable<? extends Class<?>>[] tp = type.getTypeParameters(); 584 if (parameterIndex < tp.length) { 585 return tp[parameterIndex]; 586 } else { 587 throw new IllegalArgumentException(); 588 } 589 } else if (implementation instanceof Class<?>) { 590 Class<?> c = (Class<?>) implementation; 591 Type gsc = c.getGenericSuperclass(); 592 Type resolved = null; 593 if (gsc != null) { 594 resolved = resolve(gsc, type, parameterIndex); 595 if (resolved == null) { 596 // Try with interface 597 } 598 } 599 return resolved; 600 } else if (implementation instanceof ParameterizedType) { 601 ParameterizedType pt = (ParameterizedType) implementation; 602 Type[] typeArgs = pt.getActualTypeArguments(); 603 Type rawType = pt.getRawType(); 604 if (rawType == type) { 605 return typeArgs[parameterIndex]; 606 } else if (rawType instanceof Class<?>) { 607 Class<?> classRawType = (Class<?>)rawType; 608 Type resolved = resolve(classRawType, type, parameterIndex); 609 if (resolved == null) { 610 return null; 611 } else if (resolved instanceof TypeVariable) { 612 TypeVariable resolvedTV = (TypeVariable)resolved; 613 TypeVariable[] a = classRawType.getTypeParameters(); 614 for (int i = 0;i < a.length;i++) { 615 if (a[i].equals(resolvedTV)) { 616 return resolve(implementation, classRawType, i); 617 } 618 } 619 throw new AssertionError(); 620 } else { 621 throw new UnsupportedOperationException("Cannot support resolution of " + resolved); 622 } 623 } else { 624 throw new UnsupportedOperationException(); 625 } 626 } else { 627 throw new UnsupportedOperationException("todo " + implementation + " " + implementation.getClass()); 628 } 629 } 630 631 public static boolean instanceOf(Class c, List<String> types) { 632 633 for (String type: types) { 634 if (instanceOf(c, type)) { 635 return true; 636 } 637 } 638 639 return false; 640 641 } 642 643 public static boolean instanceOf(Class c, String type) { 644 645 if (c.getName().equals(type)) { 646 return true; 647 } 648 649 for (Class i : c.getInterfaces()) { 650 if (instanceOf(i, type)) { 651 return true; 652 } 653 } 654 655 if (c.getSuperclass() != null) { 656 return instanceOf(c.getSuperclass(), type); 657 } 658 659 return false; 660 } 661}