juzu.impl.common.Tools Maven / Gradle / Ivy
/*
* Copyright 2013 eXo Platform SAS
*
* 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.
*/
package juzu.impl.common;
import juzu.UndeclaredIOException;
import javax.annotation.processing.Completion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.xml.bind.DatatypeConverter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Pattern;
/** @author Julien Viet */
public class Tools {
/** . */
public static final Charset UTF_8 = Charset.forName("UTF-8");
/** . */
private static final Iterator EMPTY_ITERATOR = new Iterator() {
public boolean hasNext() {
return false;
}
public Object next() {
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
/** . */
public static final Comparator COMPLETION_COMPARATOR = new Comparator() {
public int compare(Completion o1, Completion o2) {
return o1.getValue().compareTo(o2.getValue());
}
};
/** . */
private static final Iterable EMPTY_ITERABLE = new Iterable() {
public Iterator iterator() {
return EMPTY_ITERATOR;
}
};
/** . */
public static Pattern EMPTY_NO_RECURSE = Pattern.compile("");
/** . */
public static Pattern EMPTY_RECURSE = Pattern.compile(".*");
public static Pattern getPackageMatcher(String packageName, boolean recurse) {
// PackageName -> Identifier
// PackageName -> PackageName . Identifier
// Identifier -> IdentifierChars but not a Keyword or BooleanLiteral or NullLiteral
// IdentifierChars -> JavaLetter
// IdentifierChars -> IdentifierChars JavaLetterOrDigit
// JavaLetter -> any Unicode character that is a Java letter
// JavaLetterOrDigit -> any Unicode character that is a Java letter-or-digit
if (packageName.length() == 0) {
return recurse ? EMPTY_RECURSE : EMPTY_NO_RECURSE;
}
else {
String regex;
if (recurse) {
regex = Pattern.quote(packageName) + "(\\..*)?";
}
else {
regex = Pattern.quote(packageName);
}
return Pattern.compile(regex);
}
}
/**
* Returns the parent package of the provided package. Null is returned if the provided package
* was a top level package.
*
* @param pkgName the package name
* @return the parent package
*/
public static String parentPackageOf(String pkgName) {
int index = pkgName.lastIndexOf('.');
if (index == -1) {
return null;
} else {
return pkgName.substring(0, index);
}
}
public static void escape(CharSequence s, StringBuilder appendable) {
for (int i = 0;i < s.length();i++) {
char c = s.charAt(i);
if (c == '\n') {
appendable.append("\\n");
}
else if (c == '\'') {
appendable.append("\\\'");
}
else if (c == '\r') {
// Skip carriage return
} else {
appendable.append(c);
}
}
}
public static boolean safeEquals(Object o1, Object o2) {
return o1 == null ? o2 == null : (o2 != null && o1.equals(o2));
}
public static void safeClose(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
}
catch (IOException ignore) {
}
}
}
public static Method safeGetMethod(Class> type, String name, Class>... parameterTypes) {
try {
return type.getDeclaredMethod(name, parameterTypes);
}
catch (NoSuchMethodException e) {
return null;
}
}
public static void addAll(Collection super E> collection, Iterable elements) {
for (E element : elements) {
collection.add(element);
}
}
public static List safeUnmodifiableList(T... list) {
return safeUnmodifiableList(Arrays.asList(list));
}
public static List safeUnmodifiableList(List list) {
if (list == null || list.isEmpty()) {
return Collections.emptyList();
}
else {
return Collections.unmodifiableList(new ArrayList(list));
}
}
public static byte[] bytes(InputStream in) throws IOException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(in.available());
copy(in, baos);
return baos.toByteArray();
}
finally {
safeClose(in);
}
}
public static void write(String content, File f) throws IOException {
write(content.getBytes(), f);
}
public static void write(byte[] content, File f) throws IOException {
FileOutputStream out = new FileOutputStream(f);
try {
copy(new ByteArrayInputStream(content), out);
}
finally {
safeClose(out);
}
}
public static Map responseHeaders(HttpURLConnection conn) {
Map headers = Collections.emptyMap();
for (int i=0; ; i++) {
String name = conn.getHeaderFieldKey(i);
String value = conn.getHeaderField(i);
if (name == null && value == null) {
break;
}
if (name != null) {
if (headers.isEmpty()) {
headers = new HashMap();
}
headers.put(name, value);
}
}
return headers;
}
public static String read(URL url) throws IOException {
return read(url.openStream());
}
public static String read(File f) throws IOException {
return read(new FileInputStream(f));
}
public static String read(InputStream in) throws IOException {
return read(in, "UTF-8");
}
public static String read(InputStream in, String charsetName) throws IOException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy(in, baos);
return baos.toString();
}
finally {
safeClose(in);
}
}
public static void copy(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[256];
for (int l;(l = in.read(buffer)) != -1;) {
out.write(buffer, 0, l);
}
}
public static String unquote(String s) throws NullPointerException {
if (s == null) {
throw new NullPointerException("Can't unquote null string");
}
if (s.length() > 1) {
char c1 = s.charAt(0);
char c2 = s.charAt(s.length() - 1);
if ((c1 == '\'' || c1 == '"') && c1 == c2) {
return s.substring(1, s.length() - 1);
}
}
return s;
}
public static String join(char separator, String... names) {
return join(separator, names, 0, names.length);
}
public static String join(char separator, String[] names, int from, int end) {
int length = 0;
for (int i = from;i < end;i++) {
if (i > from) {
length++;
}
length += names[i].length();
}
return join(new StringBuilder(length), separator, names, from, end).toString();
}
public static String join(char separator, Iterator names) {
return join(new StringBuilder(), separator, names).toString();
}
public static String join(char separator, Iterable names) {
return join(separator, names.iterator());
}
public static StringBuilder join(StringBuilder sb, char separator, String... names) {
return join(sb, separator, names, 0, names.length);
}
public static StringBuilder join(StringBuilder sb, char separator, String[] names, int from, int end) {
try {
join((Appendable)sb, separator, names, from, end);
return sb;
}
catch (IOException e) {
throw new UndeclaredIOException(e);
}
}
public static StringBuilder join(StringBuilder sb, char separator, Iterator names) {
try {
join((Appendable)sb, separator, names);
return sb;
}
catch (IOException e) {
throw new UndeclaredIOException(e);
}
}
public static StringBuilder join(StringBuilder sb, char separator, Iterable names) {
try {
join((Appendable)sb, separator, names);
return sb;
}
catch (IOException e) {
throw new UndeclaredIOException(e);
}
}
public static Appendable join(A appendable, char separator, String... names) throws IOException {
return join(appendable, separator, names, 0, names.length);
}
public static Appendable join(A appendable, char separator, String[] names, int from, int end) throws IOException {
int length = end - from;
switch (length) {
case 0:
break;
case 1:
appendable.append(names[from]);
break;
default:
for (int i = from;i < end;i++) {
if (i > from) {
appendable.append(separator);
}
appendable.append(names[i]);
}
break;
}
return appendable;
}
public static Appendable join(A appendable, char separator, Iterable names) throws IOException {
return join(appendable, separator, names.iterator());
}
public static Appendable join(A appendable, char separator, Iterator names) throws IOException {
if (names.hasNext()) {
appendable.append(names.next());
while (names.hasNext()) {
appendable.append(separator);
appendable.append(names.next());
}
}
return appendable;
}
public static A nameOf(Class> clazz, A appendable) throws IOException {
if (clazz.isMemberClass()) {
nameOf(clazz.getEnclosingClass(), appendable).append('.').append(clazz.getSimpleName());
} else {
appendable.append(clazz.getSimpleName());
}
return appendable;
}
public static String getName(Class> clazz) {
if (clazz.isLocalClass() || clazz.isAnonymousClass()) {
throw new IllegalArgumentException("Cannot use local or anonymous class");
}
else {
try {
return nameOf(clazz, new StringBuilder()).toString();
}
catch (IOException e) {
throw new AssertionError(e);
}
}
}
public static String getImport(Class> clazz) {
if (clazz.isLocalClass() || clazz.isAnonymousClass()) {
throw new IllegalArgumentException("Cannot use local or anonymous class");
}
else if (clazz.isMemberClass()) {
StringBuilder sb = new StringBuilder();
while (clazz.isMemberClass()) {
sb.insert(0, clazz.getSimpleName());
sb.insert(0, '.');
clazz = clazz.getEnclosingClass();
}
sb.insert(0, clazz.getSimpleName());
String pkg = clazz.getPackage().getName();
if (pkg.length() > 0) {
sb.insert(0, '.');
sb.insert(0, pkg);
}
return sb.toString();
}
else {
return clazz.getName();
}
}
/**
* Add the specified to the specified set and returns the result. When the set
argument is an
* instance of {@link HashSet} the element is directly added, otherwise a new HashSet
is created by
* cloning the set
argument and the e
argument is added.
*
* Usage pattern : adding a set to a non modifiable set
*
* Set<String> set = Collections.emptySet();
* set = addToHashSet(set, "foo");
*
*
* @param set the set
* @param e the element
* @param the set generic type
* @return an HashSet
containing the element
*/
public static HashSet addToHashSet(Set set, E e) {
HashSet hashSet;
if (set instanceof HashSet) {
hashSet = (HashSet)set;
}
else {
hashSet = new HashSet(set);
}
hashSet.add(e);
return hashSet;
}
/**
* Add the specified to the specified list and returns the result. When the list
argument is an
* instance of {@link ArrayList} the element is directly added, otherwise a new ArrayList
is created by
* cloning the list
argument and the e
argument is added.
*
* Usage pattern : adding a list to a non modifiable list
*
* List<String> list = Collections.emptyList();
* list = addToArrayList(list, "foo");
*
*
* @param list the list
* @param e the element
* @param the set generic type
* @return an ArrayList
containing the element
*/
public static ArrayList addToArrayList(List list, E e) {
ArrayList arrayList;
if (list instanceof ArrayList) {
arrayList = (ArrayList)list;
}
else {
arrayList = new ArrayList(list);
}
arrayList.add(e);
return arrayList;
}
public static HashSet set() {
return new HashSet();
}
public static HashSet set(E element) {
HashSet set = new HashSet();
set.add(element);
return set;
}
public static HashSet set(E... elements) {
HashSet set = new HashSet(elements.length);
Collections.addAll(set, elements);
return set;
}
public static HashSet set(Iterable elements) {
return set(elements.iterator());
}
public static HashSet set(Iterator elements) {
HashSet list = new HashSet();
while (elements.hasNext()) {
list.add(elements.next());
}
return list;
}
public static HashSet set(Enumeration elements) {
HashSet list = new HashSet();
while (elements.hasMoreElements()) {
list.add(elements.nextElement());
}
return list;
}
public static ArrayList list(Iterable elements) {
return list(elements.iterator());
}
public static ArrayList list(Iterator elements) {
ArrayList list = new ArrayList();
while (elements.hasNext()) {
list.add(elements.next());
}
return list;
}
public static ArrayList list(Enumeration elements) {
ArrayList list = new ArrayList();
while (elements.hasMoreElements()) {
list.add(elements.nextElement());
}
return list;
}
public static ArrayList list(E... elements) {
ArrayList set = new ArrayList(elements.length);
Collections.addAll(set, elements);
return set;
}
public static Iterable iterable(final Enumeration elements) throws NullPointerException {
return new Iterable() {
public Iterator iterator() {
return Tools.iterator(elements);
}
};
}
public static Iterator iterator(final Enumeration elements) throws NullPointerException {
return new Iterator() {
public boolean hasNext() {
return elements.hasMoreElements();
}
public E next() {
return elements.nextElement();
}
public void remove() {
throw new UnsupportedOperationException("Read only");
}
};
}
public static Iterable iterable(final E element) throws NullPointerException {
return new Iterable() {
public Iterator iterator() {
return Tools.iterator(element);
}
};
}
public static Iterator iterator(final E element) throws NullPointerException {
return new Iterator() {
boolean hasNext = true;
public boolean hasNext() {
return hasNext;
}
public E next() {
if (hasNext) {
hasNext = false;
return element;
} else {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public static Iterable iterable(final E... elements) throws NullPointerException {
return new Iterable() {
public Iterator iterator() {
return Tools.iterator(0, elements);
}
};
}
public static Iterator iterator(E... elements) throws NullPointerException {
return iterator(0, elements);
}
public static Iterator iterator(int from, final E... elements) throws NullPointerException, IndexOutOfBoundsException {
if (elements == null) {
throw new NullPointerException("No null element array accepted");
}
return iterator(from, elements.length, elements);
}
public static Iterable iterable(final int from, final int to, final E... elements) throws NullPointerException, IndexOutOfBoundsException {
return new Iterable() {
public Iterator iterator() {
return Tools.iterator(from, to, elements);
}
};
}
public static Iterator iterator(final int from, final int to, final E... elements) throws NullPointerException, IndexOutOfBoundsException {
if (elements == null) {
throw new NullPointerException("No null element array accepted");
}
if (from < 0) {
throw new IndexOutOfBoundsException("From value " + from + " cannot be negative");
}
if (to > elements.length) {
throw new IndexOutOfBoundsException("To value " + from + " cannot be greater than the array length " + elements.length);
}
if (from > to) {
throw new IndexOutOfBoundsException("From value " + from + " cannot be greater than the from value " + elements.length);
}
if (from == to) {
return Collections.emptyList().iterator();
}
else {
return new Iterator() {
/** . */
private int index = from;
public boolean hasNext() {
return index < to;
}
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return elements[index++];
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
public static Iterator emptyIterator() {
@SuppressWarnings("unchecked")
Iterator iterator = EMPTY_ITERATOR;
return iterator;
}
public static Iterable emptyIterable() {
@SuppressWarnings("unchecked")
Iterable iterable = EMPTY_ITERABLE;
return iterable;
}
public static Iterator append(final Iterator iterator, final E... elements) {
return new Iterator() {
/** -1 means the iterator should be used, otherwise it's the index. */
int index = -1;
public boolean hasNext() {
if (index == -1) {
if (iterator.hasNext()) {
return true;
}
else {
index = 0;
}
}
return index < elements.length;
}
public E next() {
if (index == -1) {
if (iterator.hasNext()) {
return iterator.next();
}
else {
index = 0;
}
}
if (index < elements.length) {
return elements[index++];
}
else {
throw new NoSuchElementException();
}
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
/**
* Append an object to an array of objects. The original array is not modified. The returned array will be of the
* same component type of the provided array and its first n elements where n is the size of the provided array will
* be the elements of the provided array. The last element of the array will be the provided object to append.
*
* @param array the array to augment
* @param o the object to append
* @return a new array
* @throws IllegalArgumentException if the array is null
* @throws ClassCastException if the appended object class prevents it from being added to the array
*/
public static E[] appendTo(E[] array, E o) throws IllegalArgumentException, ClassCastException
{
if (array == null)
{
throw new IllegalArgumentException();
}
//
Class componentType = array.getClass().getComponentType();
if (o != null && !componentType.isAssignableFrom(o.getClass()))
{
throw new ClassCastException("Object with class " + o.getClass().getName() + " cannot be casted to class " + componentType.getName());
}
//
E[] copy = (E[])Array.newInstance(componentType, array.length + 1);
System.arraycopy(array, 0, copy, 0, array.length);
copy[array.length] = o;
//
return copy;
}
public static S unserialize(Class expectedType, File f) throws IOException, ClassNotFoundException {
return unserialize(expectedType, new FileInputStream(f));
}
public static S unserialize(Class expectedType, InputStream in) throws IOException, ClassNotFoundException {
try {
ObjectInputStream ois = new ObjectInputStream(in);
Object o = ois.readObject();
return expectedType.cast(o);
}
finally {
safeClose(in);
}
}
public static void serialize(S value, File f) throws IOException {
serialize(value, new FileOutputStream(f));
}
public static void serialize(T value, OutputStream out) throws IOException {
ObjectOutputStream ois = new ObjectOutputStream(out);
try {
ois.writeObject(value);
}
finally {
safeClose(out);
}
}
public static T clone(T value) throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Tools.serialize(value, baos);
byte[] bytes = baos.toByteArray();
return (T)unserialize(Object.class, new ByteArrayInputStream(bytes));
}
public static int unsignedByteToInt(byte b) {
return (int)b & 0xFF;
}
/**
* Parses a date formatted as ISO 8601.
*
* @param date the date
* @return the time in millis corresponding to the date
*/
public static long parseISO8601(String date) {
return DatatypeConverter.parseDateTime(date).getTimeInMillis();
}
/**
* Format the time millis as an ISO 8601 date.
*
* @param timeMillis the time to format
* @return the ISO 8601 corresponding dat
*/
public static String formatISO8601(long timeMillis) {
Calendar c = Calendar.getInstance();
c.setTimeInMillis(timeMillis);
return DatatypeConverter.printDateTime(c);
}
public static long handle(Element te) {
long hash = 0;
for (Element enclosed : te.getEnclosedElements()) {
hash = 31 * hash + handle(enclosed);
}
hash = 31 * hash + te.getSimpleName().toString().hashCode();
return hash;
}
public static int indexOf(CharSequence s, char c, int from) {
return indexOf(s, c, from, s.length());
}
public static int indexOf(CharSequence s, char c, int from, int end) {
if (from < end) {
if (from < 0) {
from = 0;
}
while (from < end) {
if (s.charAt(from) == c) {
return from;
}
from++;
}
}
return -1;
}
public static int lastIndexOf(CharSequence s, char c) {
return lastIndexOf(s, c, s.length() - 1);
}
public static int lastIndexOf(CharSequence s, char c, int from) {
from = Math.min(from, s.length() - 1);
while (from >= 0) {
if (s.charAt(from) == c) {
return from;
} else {
from--;
}
}
return -1;
}
/**
* Count the occurence of the separator string in the specified string with no overlapping.
*
* @param s the string to count in
* @param separator the separator
* @return the number of occurence
*/
public static int count(String s, String separator) {
if (separator.length() == 0) {
return s.length() + 1;
} else {
int count = 0;
int prev = 0;
while (true) {
int pos = s.indexOf(separator, prev);
if (pos == -1) {
break;
} else {
count++;
prev = pos + separator.length();
}
}
return count;
}
}
public static String[] split(CharSequence s, char separator) {
return foo(s, separator, 0, 0, 0);
}
public static String[] split(CharSequence s, char separator, int rightPadding) {
if (rightPadding < 0) {
throw new IllegalArgumentException("Right padding cannot be negative");
}
return foo(s, separator, 0, 0, rightPadding);
}
private static String[] foo(CharSequence s, char separator, int count, int from, int rightPadding) {
int len = s.length();
if (from < len) {
int to = from;
while (to < len && s.charAt(to) != separator) {
to++;
}
String[] ret;
if (to == len - 1) {
ret = new String[count + 2 + rightPadding];
ret[count + 1] = "";
}
else {
ret = to == len ? new String[count + 1 + rightPadding] : foo(s, separator, count + 1, to + 1, rightPadding);
}
ret[count] = from == to ? "" : s.subSequence(from, to).toString();
return ret;
}
else if (from == len) {
return new String[count + rightPadding];
}
else {
throw new AssertionError();
}
}
public static AnnotationMirror getAnnotation(Element element, String annotationFQN) {
for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
if (mirror.getAnnotationType().toString().equals(annotationFQN)) {
return mirror;
}
}
return null;
}
public static StringBuilder toString(Iterable> entries, StringBuilder sb) {
sb.append('{');
for (Iterator> i = entries.iterator();i.hasNext();) {
Map.Entry entry = i.next();
sb.append(entry.getKey()).append("=[");
String[] value = entry.getValue();
for (int j = 0;j < value.length;j++) {
if (j > 0) {
sb.append(',');
}
sb.append(value[j]);
}
sb.append(']');
if (i.hasNext()) {
sb.append(',');
}
}
sb.append('}');
return sb;
}
public static String nextUUID() {
return UUID.randomUUID().toString();
}
}