All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.rapidoid.u.U Maven / Gradle / Ivy

There is a newer version: 5.0.12
Show newest version
package org.rapidoid.u;

/*
 * #%L
 * rapidoid-u
 * %%
 * Copyright (C) 2014 - 2015 Nikolche Mihajlovski and contributors
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.io.File;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.script.SimpleBindings;

import org.rapidoid.lambda.Dynamic;
import org.rapidoid.lambda.Mapper;

/**
 * @author Nikolche Mihajlovski
 * @since 2.0.0
 */
public class U {

	public static String str(Object obj) {
		if (obj == null) {
			return "null";
		} else if (obj instanceof byte[]) {
			return Arrays.toString((byte[]) obj);
		} else if (obj instanceof short[]) {
			return Arrays.toString((short[]) obj);
		} else if (obj instanceof int[]) {
			return Arrays.toString((int[]) obj);
		} else if (obj instanceof long[]) {
			return Arrays.toString((long[]) obj);
		} else if (obj instanceof float[]) {
			return Arrays.toString((float[]) obj);
		} else if (obj instanceof double[]) {
			return Arrays.toString((double[]) obj);
		} else if (obj instanceof boolean[]) {
			return Arrays.toString((boolean[]) obj);
		} else if (obj instanceof char[]) {
			return Arrays.toString((char[]) obj);
		} else if (obj instanceof Object[]) {
			return str((Object[]) obj);
		} else {
			return String.valueOf(obj);
		}
	}

	public static String str(Object[] objs) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");

		for (int i = 0; i < objs.length; i++) {
			if (i > 0) {
				sb.append(", ");
			}
			sb.append(str(objs[i]));
		}

		sb.append("]");

		return sb.toString();
	}

	public static String str(Iterable coll) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");

		boolean first = true;

		for (Object obj : coll) {
			if (!first) {
				sb.append(", ");
			}

			sb.append(str(obj));
			first = false;
		}

		sb.append("]");
		return sb.toString();
	}

	public static String str(Iterator it) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");

		boolean first = true;

		while (it.hasNext()) {
			if (first) {
				sb.append(", ");
				first = false;
			}

			sb.append(str(it.next()));
		}

		sb.append("]");

		return sb.toString();
	}

	public static String frmt(String format, Object... args) {
		for (int i = 0; i < args.length; i++) {
			if (!(args[i] instanceof Number)) {
				args[i] = str(args[i]);
			}
		}

		return String.format(format, args);
	}

	public static String replace(String s, String[][] repls) {
		for (String[] repl : repls) {
			s = s.replaceAll(Pattern.quote(repl[0]), repl[1]);
		}
		return s;
	}

	public static String replace(String s, String regex, Mapper replacer) {
		StringBuffer output = new StringBuffer();
		Pattern p = Pattern.compile(regex);
		Matcher matcher = p.matcher(s);

		while (matcher.find()) {
			int len = matcher.groupCount() + 1;
			String[] groups = new String[len];

			for (int i = 0; i < groups.length; i++) {
				groups[i] = matcher.group(i);
			}

			Object value;
			try {
				value = replacer.map(groups);
			} catch (Exception e) {
				throw rte(e);
			}

			matcher.appendReplacement(output, str(value));
		}

		matcher.appendTail(output);
		return output.toString();
	}

	public static void print(Object... values) {
		String text;

		if (values != null) {
			text = values.length == 1 ? str(values[0]) : str(values);
		} else {
			text = "null";
		}

		System.out.println(text);
	}

	@SuppressWarnings({ "varargs" })
	public static  String join(String sep, T... items) {
		return render(items, "%s", sep);
	}

	public static String join(String sep, Iterable items) {
		return render(items, "%s", sep);
	}

	public static String join(String sep, char[][] items) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < items.length; i++) {
			if (i > 0) {
				sb.append(sep);
			}
			sb.append(items[i]);
		}

		return sb.toString();
	}

	public static String render(Object[] items, String itemFormat, String sep) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < items.length; i++) {
			if (i > 0) {
				sb.append(sep);
			}
			sb.append(frmt(itemFormat, items[i]));
		}

		return sb.toString();
	}

	public static String render(Iterable items, String itemFormat, String sep) {
		StringBuilder sb = new StringBuilder();

		int i = 0;
		Iterator it = items.iterator();
		while (it.hasNext()) {
			Object item = it.next();
			if (i > 0) {
				sb.append(sep);
			}

			sb.append(frmt(itemFormat, item));
			i++;
		}

		return sb.toString();
	}

	public static  Iterator iterator(T[] arr) {
		return Arrays.asList(arr).iterator();
	}

	@SuppressWarnings({ "varargs" })
	public static  T[] array(T... items) {
		return items;
	}

	public static Object[] array(Iterable items) {
		return (items instanceof Collection) ? ((Collection) items).toArray() : list(items).toArray();
	}

	@SuppressWarnings("unchecked")
	public static  Set synchronizedSet() {
		return (Set) Collections.synchronizedSet(set());
	}

	public static  Set set() {
		return new LinkedHashSet();
	}

	public static  Set set(Iterable values) {
		Set set = set();

		for (T val : values) {
			set.add(val);
		}

		return set;
	}

	@SuppressWarnings({ "varargs" })
	public static  Set set(T... values) {
		Set set = set();

		for (T val : values) {
			set.add(val);
		}

		return set;
	}

	@SuppressWarnings("unchecked")
	public static  List synchronizedList() {
		return (List) Collections.synchronizedList(list());
	}

	public static  List list() {
		return new ArrayList();
	}

	public static  List list(Iterable values) {
		List list = list();

		for (T item : values) {
			list.add(item);
		}

		return list;
	}

	@SuppressWarnings({ "varargs" })
	public static  List list(T... values) {
		List list = list();

		for (T item : values) {
			list.add(item);
		}

		return list;
	}

	public static  Map map() {
		return new LinkedHashMap();
	}

	public static  Map map(Map src) {
		Map map = map();
		map.putAll(src);
		return map;
	}

	public static  Map map(K key, V value) {
		Map map = map();
		map.put(key, value);
		return map;
	}

	public static  Map map(K key1, V value1, K key2, V value2) {
		Map map = map(key1, value1);
		map.put(key2, value2);
		return map;
	}

	public static  Map map(K key1, V value1, K key2, V value2, K key3, V value3) {
		Map map = map(key1, value1, key2, value2);
		map.put(key3, value3);
		return map;
	}

	public static  Map map(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4) {
		Map map = map(key1, value1, key2, value2, key3, value3);
		map.put(key4, value4);
		return map;
	}

	public static  Map map(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4, K key5,
			V value5) {
		Map map = map(key1, value1, key2, value2, key3, value3, key4, value4);
		map.put(key5, value5);
		return map;
	}

	@SuppressWarnings("unchecked")
	public static  Map map(Object... keysAndValues) {
		must(keysAndValues.length % 2 == 0, "Incorrect number of arguments (expected key-value pairs)!");

		Map map = map();

		for (int i = 0; i < keysAndValues.length / 2; i++) {
			map.put((K) keysAndValues[i * 2], (V) keysAndValues[i * 2 + 1]);
		}

		return map;
	}

	public static  ConcurrentMap concurrentMap() {
		return new ConcurrentHashMap();
	}

	public static  ConcurrentMap concurrentMap(Map src, boolean ignoreNullValues) {
		ConcurrentMap map = concurrentMap();

		for (Entry e : src.entrySet()) {
			if (!ignoreNullValues || e.getValue() != null) {
				map.put(e.getKey(), e.getValue());
			}
		}

		return map;
	}

	public static  ConcurrentMap concurrentMap(K key, V value) {
		ConcurrentMap map = concurrentMap();
		map.put(key, value);
		return map;
	}

	public static  ConcurrentMap concurrentMap(K key1, V value1, K key2, V value2) {
		ConcurrentMap map = concurrentMap(key1, value1);
		map.put(key2, value2);
		return map;
	}

	public static  ConcurrentMap concurrentMap(K key1, V value1, K key2, V value2, K key3, V value3) {
		ConcurrentMap map = concurrentMap(key1, value1, key2, value2);
		map.put(key3, value3);
		return map;
	}

	public static  ConcurrentMap concurrentMap(K key1, V value1, K key2, V value2, K key3, V value3,
			K key4, V value4) {
		ConcurrentMap map = concurrentMap(key1, value1, key2, value2, key3, value3);
		map.put(key4, value4);
		return map;
	}

	public static  ConcurrentMap concurrentMap(K key1, V value1, K key2, V value2, K key3, V value3,
			K key4, V value4, K key5, V value5) {
		ConcurrentMap map = concurrentMap(key1, value1, key2, value2, key3, value3, key4, value4);
		map.put(key5, value5);
		return map;
	}

	@SuppressWarnings("unchecked")
	public static  ConcurrentMap concurrentMap(Object... keysAndValues) {
		must(keysAndValues.length % 2 == 0, "Incorrect number of arguments (expected key-value pairs)!");

		ConcurrentMap map = concurrentMap();

		for (int i = 0; i < keysAndValues.length / 2; i++) {
			map.put((K) keysAndValues[i * 2], (V) keysAndValues[i * 2 + 1]);
		}

		return map;
	}

	public static  Map orderedMap() {
		return new LinkedHashMap();
	}

	public static  Map orderedMap(Map src, boolean ignoreNullValues) {
		Map map = orderedMap();

		for (Entry e : src.entrySet()) {
			if (!ignoreNullValues || e.getValue() != null) {
				map.put(e.getKey(), e.getValue());
			}
		}

		return map;
	}

	public static  Map orderedMap(K key, V value) {
		Map map = orderedMap();
		map.put(key, value);
		return map;
	}

	public static  Map orderedMap(K key1, V value1, K key2, V value2) {
		Map map = orderedMap(key1, value1);
		map.put(key2, value2);
		return map;
	}

	public static  Map orderedMap(K key1, V value1, K key2, V value2, K key3, V value3) {
		Map map = orderedMap(key1, value1, key2, value2);
		map.put(key3, value3);
		return map;
	}

	public static  Map orderedMap(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4) {
		Map map = orderedMap(key1, value1, key2, value2, key3, value3);
		map.put(key4, value4);
		return map;
	}

	public static  Map orderedMap(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4,
			K key5, V value5) {
		Map map = orderedMap(key1, value1, key2, value2, key3, value3, key4, value4);
		map.put(key5, value5);
		return map;
	}

	@SuppressWarnings("unchecked")
	public static  Map orderedMap(Object... keysAndValues) {
		must(keysAndValues.length % 2 == 0, "Incorrect number of arguments (expected key-value pairs)!");

		Map map = orderedMap();

		for (int i = 0; i < keysAndValues.length / 2; i++) {
			map.put((K) keysAndValues[i * 2], (V) keysAndValues[i * 2 + 1]);
		}

		return map;
	}

	public static  Map synchronizedMap() {
		return Collections.synchronizedMap(U. map());
	}

	public static  Queue queue() {
		return new ConcurrentLinkedQueue();
	}

	public static  BlockingQueue queue(int maxSize) {
		argMust(maxSize > 0, "Maximum queue size must be > 0!");
		return new ArrayBlockingQueue(maxSize);
	}

	public static  T or(T value, T fallback) {
		return value != null ? value : fallback;
	}

	public static String safe(String s) {
		return or(s, "");
	}

	public static boolean safe(Boolean b) {
		return or(b, false);
	}

	public static int safe(Integer num) {
		return or(num, 0);
	}

	public static long safe(Long num) {
		return or(num, 0L);
	}

	public static byte safe(Byte num) {
		return or(num, (byte) 0);
	}

	public static float safe(Float num) {
		return or(num, 0.0f);
	}

	public static double safe(Double num) {
		return or(num, 0.0);
	}

	public static Object[] safe(Object[] arr) {
		return arr != null ? arr : new Object[0];
	}

	public static  List safe(List list) {
		return list != null ? list : U. list();
	}

	public static  Set safe(Set set) {
		return set != null ? set : U. set();
	}

	public static  Map safe(Map map) {
		return map != null ? map : U. map();
	}

	public static long time() {
		return System.currentTimeMillis();
	}

	public static boolean xor(boolean a, boolean b) {
		return a && !b || b && !a;
	}

	public static boolean eq(Object a, Object b) {
		return a == null ? b == null : a.equals(b);
	}

	public static RuntimeException rte(String message) {
		return new RuntimeException(message);
	}

	public static RuntimeException rte(String message, Throwable cause) {
		return new RuntimeException(message, cause);
	}

	public static RuntimeException rte(Throwable cause) {
		return rte("", cause);
	}

	public static RuntimeException rte(String message, Object... args) {
		return rte(frmt(message, args));
	}

	public static RuntimeException notExpected() {
		return rte("This operation is not expected to be called!");
	}

	public static RuntimeException notReady() {
		return rte("Not yet implemented!");
	}

	public static RuntimeException notSupported() {
		return rte("This operation is not supported by this implementation!");
	}

	public static void rteIf(boolean failureCondition, String msg) {
		if (failureCondition) {
			throw rte(msg);
		}
	}

	public static boolean must(boolean expectedCondition, String message) {
		if (!expectedCondition) {
			throw rte(message);
		}
		return true;
	}

	public static RuntimeException rte(String message, Throwable cause, Object... args) {
		return rte(frmt(message, args), cause);
	}

	public static boolean must(boolean expectedCondition) {
		if (!expectedCondition) {
			throw rte("Expectation failed!");
		}
		return true;
	}

	public static boolean must(boolean expectedCondition, String message, long arg) {
		if (!expectedCondition) {
			throw rte(message, arg);
		}
		return true;
	}

	public static boolean must(boolean expectedCondition, String message, Object arg) {
		if (!expectedCondition) {
			throw rte(message, str(arg));
		}
		return true;
	}

	public static boolean must(boolean expectedCondition, String message, Object arg1, Object arg2) {
		if (!expectedCondition) {
			throw rte(message, str(arg1), str(arg2));
		}
		return true;
	}

	public static boolean must(boolean expectedCondition, String message, Object arg1, Object arg2, Object arg3) {
		if (!expectedCondition) {
			throw rte(message, str(arg1), str(arg2), str(arg3));
		}
		return true;
	}

	public static IllegalArgumentException illegalArg(String message, Object... args) {
		return new IllegalArgumentException(frmt(message, args));
	}

	public static void secure(boolean condition, String msg) {
		if (!condition) {
			throw new SecurityException(str(msg));
		}
	}

	public static void secure(boolean condition, String msg, Object arg) {
		if (!condition) {
			throw new SecurityException(frmt(msg, arg));
		}
	}

	public static void secure(boolean condition, String msg, Object arg1, Object arg2) {
		if (!condition) {
			throw new SecurityException(frmt(msg, arg1, arg2));
		}
	}

	public static void bounds(int value, int min, int max) {
		must(value >= min && value <= max, "%s is not in the range [%s, %s]!", value, min, max);
	}

	public static  T notNull(T value, String msgOrDesc, Object... descArgs) {
		if (value == null) {
			throw rte("%s must NOT be null!", frmt(msgOrDesc, descArgs));
		}

		return value;
	}

	public static boolean isEmpty(String value) {
		return value == null || value.isEmpty();
	}

	public static boolean isEmpty(Object[] arr) {
		return arr == null || arr.length == 0;
	}

	public static boolean isEmpty(Collection coll) {
		return coll == null || coll.isEmpty();
	}

	public static boolean isEmpty(Iterable iter) {
		return iter.iterator().hasNext();
	}

	public static boolean isEmpty(Map map) {
		return map == null || map.isEmpty();
	}

	public static boolean isEmpty(Object value) {
		if (value == null) {
			return true;
		} else if (value instanceof String) {
			return isEmpty((String) value);
		} else if (value instanceof byte[]) {
			return ((byte[]) value).length == 0;
		} else if (value instanceof short[]) {
			return ((short[]) value).length == 0;
		} else if (value instanceof int[]) {
			return ((int[]) value).length == 0;
		} else if (value instanceof long[]) {
			return ((long[]) value).length == 0;
		} else if (value instanceof float[]) {
			return ((float[]) value).length == 0;
		} else if (value instanceof double[]) {
			return ((double[]) value).length == 0;
		} else if (value instanceof boolean[]) {
			return ((boolean[]) value).length == 0;
		} else if (value instanceof char[]) {
			return ((char[]) value).length == 0;
		} else if (value instanceof Object[]) {
			return ((Object[]) value).length == 0;
		} else if (value instanceof Collection) {
			return isEmpty((Collection) value);
		} else if (value instanceof Map) {
			return isEmpty((Map) value);
		} else if (value instanceof Iterable) {
			return isEmpty((Iterable) value);
		}
		return false;
	}

	public static boolean notEmpty(String value) {
		return !isEmpty(value);
	}

	public static boolean notEmpty(Object[] arr) {
		return !isEmpty(arr);
	}

	public static boolean notEmpty(Collection coll) {
		return !isEmpty(coll);
	}

	public static boolean notEmpty(Iterable iter) {
		return !isEmpty(iter);
	}

	public static boolean notEmpty(Map map) {
		return !isEmpty(map);
	}

	public static boolean notEmpty(Object value) {
		return !isEmpty(value);
	}

	public static String capitalized(String s) {
		return s.isEmpty() ? s : s.substring(0, 1).toUpperCase() + s.substring(1);
	}

	public static String uncapitalized(String s) {
		return s.isEmpty() ? s : s.substring(0, 1).toLowerCase() + s.substring(1);
	}

	public static String mul(String s, int n) {
		StringBuffer sb = new StringBuffer();

		for (int i = 0; i < n; i++) {
			sb.append(s);
		}

		return sb.toString();
	}

	public static String mid(String s, int beginIndex, int endIndex) {
		if (endIndex < 0) {
			endIndex = s.length() + endIndex;
		}
		return s.substring(beginIndex, endIndex);
	}

	public static String insert(String target, int atIndex, String insertion) {
		return target.substring(0, atIndex) + insertion + target.substring(atIndex);
	}

	public static int num(String s) {
		return Integer.parseInt(s);
	}

	public static int bounded(int min, int value, int max) {
		return Math.min(Math.max(min, value), max);
	}

	public static  T single(Iterable coll) {
		Iterator it = coll.iterator();
		must(it.hasNext(), "Expected exactly 1 item, but didn't find any!");
		T item = it.next();
		must(!it.hasNext(), "Expected exactly 1 item, but found more than 1!");
		return item;
	}

	public static  T singleOrNone(Iterable coll) {
		Iterator it = coll.iterator();
		T item = it.hasNext() ? it.next() : null;
		must(!it.hasNext(), "Expected 0 or 1 items, but found more than 1!");
		return item;
	}

	public static  T first(T[] values) {
		return values != null && values.length > 0 ? values[0] : null;
	}

	public static  T first(List values) {
		return values != null && values.size() > 0 ? values.get(0) : null;
	}

	public static  T last(T[] values) {
		return values != null && values.length > 0 ? values[values.length - 1] : null;
	}

	public static  T last(List values) {
		return values != null && values.size() > 0 ? values.get(values.size() - 1) : null;
	}

	@SuppressWarnings("unchecked")
	public static  int compare(T val1, T val2) {
		if (val1 == null && val2 == null) {
			return 0;
		} else if (val1 == null) {
			return -1;
		} else if (val2 == null) {
			return 1;
		} else {
			return ((Comparable) val1).compareTo(val2);
		}
	}

	public static  List range(Iterable items, int fromIndex, int toIndex) {
		// TODO more efficient implementation
		List list = list(items);

		fromIndex = bounded(0, fromIndex, list.size());
		toIndex = bounded(fromIndex, toIndex, list.size());

		return list(list.subList(fromIndex, toIndex));
	}

	public static  List page(Iterable items, int page, int pageSize) {
		return range(items, (page - 1) * pageSize, page * pageSize);
	}

	public static String trimr(String s, char suffix) {
		return (!s.isEmpty() && s.charAt(s.length() - 1) == suffix) ? mid(s, 0, -1) : s;
	}

	public static String trimr(String s, String suffix) {
		return s.endsWith(suffix) ? mid(s, 0, -suffix.length()) : s;
	}

	public static String triml(String s, char prefix) {
		return (!s.isEmpty() && s.charAt(0) == prefix) ? s.substring(1) : s;
	}

	public static String triml(String s, String prefix) {
		return s.startsWith(prefix) ? s.substring(prefix.length()) : s;
	}

	public static void argMust(boolean expectedCondition, String message, Object... args) {
		if (!expectedCondition) {
			throw illegalArg(message, args);
		}
	}

	/**
	 * Sleeps (calling Thread.sleep) for the specified period.
	 * 
	 * If the thread is interrupted while sleeping, throws {@link CancellationException} to propagate the interruption.
	 * 
	 * @param millis
	 *            the length of time to sleep in milliseconds.
	 */
	public static void sleep(long millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			throw new CancellationException();
		}
	}

	public static  Map autoExpandingMap(final Class clazz) {
		return autoExpandingMap(new Mapper() {

			@SuppressWarnings("unchecked")
			@Override
			public V map(K src) throws Exception {
				try {
					return (V) clazz.newInstance();
				} catch (Exception e) {
					throw rte(e);
				}
			}
		});
	}

	@SuppressWarnings("serial")
	public static  Map autoExpandingMap(final Mapper valueFactory) {
		return Collections.synchronizedMap(new HashMap() {

			@SuppressWarnings("unchecked")
			@Override
			public synchronized V get(Object key) {
				V val = super.get(key);

				if (val == null) {
					try {
						val = valueFactory.map((K) key);
					} catch (Exception e) {
						throw rte(e);
					}

					put((K) key, val);
				}

				return val;
			}

		});
	}

	public static  Map> mapOfMaps() {
		return autoExpandingMap(new Mapper>() {

			@Override
			public Map map(K1 src) throws Exception {
				return synchronizedMap();
			}

		});
	}

	public static  Map> mapOfLists() {
		return autoExpandingMap(new Mapper>() {

			@Override
			public List map(K src) throws Exception {
				return Collections.synchronizedList(U. list());
			}

		});
	}

	public static  Map> mapOfSets() {
		return autoExpandingMap(new Mapper>() {

			@Override
			public Set map(K src) throws Exception {
				return Collections.synchronizedSet(U. set());
			}

		});
	}

	/**
	 * Simpler casts, less warnings.
	 */
	@SuppressWarnings("unchecked")
	public static  T cast(Object value) {
		return (T) value;
	}

	public static void wait(CountDownLatch latch) {
		try {
			latch.await();
		} catch (InterruptedException e) {
			throw new CancellationException();
		}
	}

	public static void wait(CountDownLatch latch, long timeout, TimeUnit unit) {
		try {
			latch.await(timeout, unit);
		} catch (InterruptedException e) {
			throw new CancellationException();
		}
	}

	@SuppressWarnings("unchecked")
	public static  T dynamic(final Class targetInterface, final Dynamic dynamic) {
		final Object obj = new Object();

		InvocationHandler handler = new InvocationHandler() {

			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

				if (method.getDeclaringClass().equals(Object.class)) {
					if (method.getName().equals("toString")) {
						return targetInterface.getSimpleName() + "@" + Integer.toHexString(obj.hashCode());
					}
					return method.invoke(obj, args);
				}

				return dynamic.call(method, safe(args));
			}

		};

		return ((T) Proxy.newProxyInstance(targetInterface.getClassLoader(), new Class[] { targetInterface }, handler));
	}

	@SuppressWarnings({ "varargs" })
	public static  boolean isIn(T value, T... candidates) {
		for (T candidate : candidates) {
			if (eq(value, candidate)) {
				return true;
			}
		}
		return false;
	}

	public static  Is is(T value) {
		return new Is(value);
	}

	public static boolean exists(Callable accessChain) {
		try {
			return accessChain != null && accessChain.call() != null;
		} catch (NullPointerException e) {
			return false;
		} catch (Exception e) {
			throw U.rte(e);
		}
	}

	public static String uri(String... parts) {
		return "/" + constructPath("/", false, parts);
	}

	public static String path(String... parts) {
		return constructPath(File.separator, true, parts);
	}

	private static String constructPath(String separator, boolean preserveFirstSegment, String... parts) {
		String s = "";

		for (int i = 0; i < parts.length; i++) {
			String part = U.safe(parts[i]);

			// trim '/'s and '\'s
			if (!preserveFirstSegment || i > 0) {
				part = triml(part, "/");
			}

			if (!preserveFirstSegment || part.length() > 1 || i > 0) {
				part = trimr(part, "/");
				part = trimr(part, "\\");
			}

			if (!U.isEmpty(part)) {
				if (!s.isEmpty() && !s.endsWith(separator)) {
					s += separator;
				}
				s += part;
			}
		}

		return s;
	}

	public static boolean isMap(Object obj) {
		return obj instanceof Map;
	}

	public static boolean isList(Object obj) {
		return obj instanceof List;
	}

	public static boolean isSet(Object obj) {
		return obj instanceof Set;
	}

	public static boolean isCollection(Object obj) {
		return obj instanceof Collection;
	}

	public static  void assign(Collection destination, Collection source) {
		if (destination != null && source != null) {
			destination.clear();
			destination.addAll(source);
		}
	}

	public static  void assign(Map destination, Map source) {
		if (destination != null && source != null) {
			destination.clear();
			destination.putAll(source);
		}
	}

	public static  V get(Map map, K key) {
		V value = map.get(key);
		notNull(value, "map[%s]", key);
		return value;
	}

	public static  V get(Map map, K key, V defaultValue) {
		V value = map.get(key);
		return value != null ? value : defaultValue;
	}

}