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
020 package org.crsh.util;
021
022 import javax.naming.Context;
023 import java.io.ByteArrayOutputStream;
024 import java.io.Closeable;
025 import java.io.Flushable;
026 import java.io.IOException;
027 import java.io.InputStream;
028 import java.io.OutputStream;
029 import java.lang.reflect.ParameterizedType;
030 import java.lang.reflect.Type;
031 import java.lang.reflect.TypeVariable;
032 import java.net.Socket;
033 import java.sql.*;
034 import java.io.File;
035 import java.net.URISyntaxException;
036 import java.net.URL;
037 import java.util.ArrayList;
038 import java.util.Arrays;
039 import java.util.Collections;
040 import java.util.HashMap;
041 import java.util.HashSet;
042 import java.util.Iterator;
043 import java.util.List;
044 import java.util.Map;
045 import java.util.NoSuchElementException;
046 import java.util.regex.Matcher;
047 import java.util.regex.Pattern;
048
049 public 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 }