http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/ByteArrayCache.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/ByteArrayCache.java
 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/ByteArrayCache.java
new file mode 100644
index 0000000..9747902
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/ByteArrayCache.java
@@ -0,0 +1,106 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * A utility class for caching byte arrays in memory so that duplicate arrays 
can be reused.
+ * <p>
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ */
+public class ByteArrayCache {
+
+       /**
+        * Default global byte array cache.
+        * Note that this can't ever get garbage collected so don't add really 
large arrays!
+        */
+       public static final ByteArrayCache DEFAULT = new ByteArrayCache();
+
+       private final ConcurrentHashMap<ByteArray,byte[]> cache = new 
ConcurrentHashMap<ByteArray,byte[]>();
+
+       /**
+        * Add the specified byte array to this cache.
+        *
+        * @param contents The byte array to add to this cache.
+        * @return Either the same byte array or a previously cached byte array 
depending on whether the byte array
+        *      already exists in the cache.
+        */
+       public byte[] cache(byte[] contents) {
+               if (contents == null)
+                       return null;
+               ByteArray ba = new ByteArray(contents);
+               cache.putIfAbsent(ba, ba.contents);
+               return cache.get(ba);
+       }
+
+       /**
+        * Add the specified input stream to this cache.
+        *
+        * @param contents The input stream whose contents are to be added to 
this cache.
+        * @return Either the same byte array or a previously cached byte array 
depending on whether the byte array
+        *      already exists in the cache.
+        * @throws IOException
+        */
+       public byte[] cache(InputStream contents) throws IOException {
+               if (contents == null)
+                       return null;
+               ByteArray ba = new ByteArray(IOUtils.readBytes(contents, 1024));
+               cache.putIfAbsent(ba, ba.contents);
+               return cache.get(ba);
+       }
+
+       /**
+        * Returns the number of byte arrays in this cache.
+        *
+        * @return The number of byte arrays in this cache.
+        */
+       public int size() {
+               return cache.size();
+       }
+
+       private static class ByteArray {
+               private int hashCode;
+               private byte[] contents;
+
+               private ByteArray(byte[] contents) {
+                       this.contents = contents;
+                       int multiplier = 1;
+                       for (int i = 0; i < contents.length; i++) {
+                               hashCode += contents[i] * multiplier;
+                               int shifted = multiplier << 5;
+                               multiplier = shifted - multiplier;
+                       }
+               }
+
+               @Override /* Object */
+               public int hashCode() {
+                       if (hashCode == 0) {
+                       }
+                       return hashCode;
+               }
+
+               @Override /* Object */
+               public boolean equals(Object o) {
+                       if (o instanceof ByteArray) {
+                               ByteArray ba = (ByteArray)o;
+                               if (ba.hashCode == hashCode)
+                                       return Arrays.equals(ba.contents, 
contents);
+                       }
+                       return false;
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/ByteArrayInOutStream.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/ByteArrayInOutStream.java
 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/ByteArrayInOutStream.java
new file mode 100644
index 0000000..d104c77
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/ByteArrayInOutStream.java
@@ -0,0 +1,32 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import java.io.*;
+
+/**
+ * Subclass of a ByteArrayOutputStream that avoids a byte array copy when 
reading from an input stream.
+ * <p>
+ * @author James Bognar (james.bog...@salesforce.com)
+ */
+public class ByteArrayInOutStream extends ByteArrayOutputStream {
+
+       /**
+        * Creates a new input stream from this object.
+        *
+        * @return A new input stream from this object.
+        */
+       public ByteArrayInputStream getInputStream() {
+               return new ByteArrayInputStream(this.buf, 0, this.count);
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/CharSequenceReader.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/CharSequenceReader.java
 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/CharSequenceReader.java
new file mode 100644
index 0000000..fe89635
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/CharSequenceReader.java
@@ -0,0 +1,100 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import java.io.*;
+
+/**
+ * Similar to {@link StringReader} except reads from a generic {@link 
CharSequenceReader}.
+ *
+ * @author jbognar
+ */
+public final class CharSequenceReader extends BufferedReader {
+
+       private final CharSequence cs;
+       private String s;
+       private StringBuffer sb;
+       private StringBuilder sb2;
+       private int length;
+       private int next = 0;
+
+       /**
+        * Constructor.
+        *
+        * @param cs The char sequence to read from.  Can be <jk>null</jk>.
+        */
+       public CharSequenceReader(CharSequence cs) {
+               super(new StringReader(""), 1);   // Does not actually use a 
reader.
+               if (cs == null)
+                       cs = "";
+               this.cs = cs;
+               if (cs instanceof String)
+                       s = (String)cs;
+               else if (cs instanceof StringBuffer)
+                       sb = (StringBuffer)cs;
+               else if (cs instanceof StringBuilder)
+                       sb2 = (StringBuilder)cs;
+               this.length = cs.length();
+       }
+
+       @Override /* Reader */
+       public int read() {
+               if (next >= length)
+                       return -1;
+               return cs.charAt(next++);
+       }
+
+       @Override /* Reader */
+       public boolean markSupported() {
+               return false;
+       }
+
+       @Override /* Reader */
+       public int read(final char[] cbuf, final int off, final int len) {
+               if (next >= length)
+                       return -1;
+               int n = Math.min(length - next, len);
+               if (s != null)
+                       s.getChars(next, next + n, cbuf, off);
+               else if (sb != null)
+                       sb.getChars(next, next + n, cbuf, off);
+               else if (sb2 != null)
+                       sb2.getChars(next, next + n, cbuf, off);
+               else {
+                       for (int i = 0; i < n; i++)
+                               cbuf[off+i] = cs.charAt(next+i);
+               }
+               next += n;
+               return n;
+       }
+
+       @Override /* Reader */
+       public long skip(long ns) {
+               if (next >= length)
+                       return 0;
+               long n = Math.min(length - next, ns);
+               n = Math.max(-next, n);
+               next += n;
+               return n;
+       }
+
+       @Override /* Reader */
+       public void close() {
+               // no-op
+       }
+
+       @Override /* Object */
+       public String toString() {
+               return cs.toString();
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/ClassUtils.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/ClassUtils.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/ClassUtils.java
new file mode 100644
index 0000000..fce5caf
--- /dev/null
+++ b/org.apache.juneau/src/main/java/org/apache/juneau/internal/ClassUtils.java
@@ -0,0 +1,323 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import org.apache.juneau.*;
+
+/**
+ * Class-related utility methods.
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ */
+public final class ClassUtils {
+
+       /**
+        * Given the specified list of objects, return readable names for the 
class types of the objects.
+        *
+        * @param o The objects.
+        * @return An array of readable class type strings.
+        */
+       public static ObjectList getReadableClassNames(Object[] o) {
+               ObjectList l = new ObjectList();
+               for (int i = 0; i < o.length; i++)
+                       l.add(o[i] == null ? "null" : 
getReadableClassName(o[i].getClass()));
+               return l;
+       }
+
+       /**
+        * Shortcut for calling 
<code><jsm>getReadableClassName</jsm>(c.getName())</code>
+        *
+        * @param c The class.
+        * @return A readable class type name, or <jk>null</jk> if parameter is 
<jk>null</jk>.
+        */
+       public static String getReadableClassName(Class<?> c) {
+               if (c == null)
+                       return null;
+               return getReadableClassName(c.getName());
+       }
+
+       /**
+        * Shortcut for calling 
<code><jsm>getReadableClassName</jsm>(c.getClass().getName())</code>
+        *
+        * @param o The object whose class we want to render.
+        * @return A readable class type name, or <jk>null</jk> if parameter is 
<jk>null</jk>.
+        */
+       public static String getReadableClassNameForObject(Object o) {
+               if (o == null)
+                       return null;
+               return getReadableClassName(o.getClass().getName());
+       }
+
+       /**
+        * Converts the specified class name to a readable form when class name 
is a special construct like <js>"[[Z"</js>.
+        * <p>
+        * Examples:
+        * <p class='bcode'>
+        *      <jsm>getReadableClassName</jsm>(<js>"java.lang.Object"</js>);  
<jc>// Returns "java.lang.Object"</jc>
+        *      <jsm>getReadableClassName</jsm>(<js>"boolean"</js>);  <jc>// 
Returns "boolean"</jc>
+        *      <jsm>getReadableClassName</jsm>(<js>"[Z"</js>);  <jc>// Returns 
"boolean[]"</jc>
+        *      <jsm>getReadableClassName</jsm>(<js>"[[Z"</js>);  <jc>// 
Returns "boolean[][]"</jc>
+        *      
<jsm>getReadableClassName</jsm>(<js>"[Ljava.lang.Object;"</js>);  <jc>// 
Returns "java.lang.Object[]"</jc>
+        *      <jsm>getReadableClassName</jsm>(<jk>null</jk>);  <jc>// Returns 
null</jc>
+        * </p>
+        *
+        * @param className The class name.
+        * @return A readable class type name, or <jk>null</jk> if parameter is 
<jk>null</jk>.
+        */
+       public static String getReadableClassName(String className) {
+               if (className == null)
+                       return null;
+               if (! StringUtils.startsWith(className, '['))
+                       return className;
+               int depth = 0;
+               for (int i = 0; i < className.length(); i++) {
+                       if (className.charAt(i) == '[')
+                               depth++;
+                       else
+                               break;
+               }
+               char type = className.charAt(depth);
+               String c;
+               switch (type) {
+                       case 'Z': c = "boolean"; break;
+                       case 'B': c = "byte"; break;
+                       case 'C': c = "char"; break;
+                       case 'D': c = "double"; break;
+                       case 'F': c = "float"; break;
+                       case 'I': c = "int"; break;
+                       case 'J': c = "long"; break;
+                       case 'S': c = "short"; break;
+                       default: c = className.substring(depth+1, 
className.length()-1);
+               }
+               StringBuilder sb = new StringBuilder(c.length() + 
2*depth).append(c);
+               for (int i = 0; i < depth; i++)
+                       sb.append("[]");
+               return sb.toString();
+       }
+
+       /**
+        * Converts the string generated by {@link 
#getReadableClassName(Class)} back into a {@link Class}.
+        * <p>
+        * Generics are stripped from the string since they cannot be converted 
to a class.
+        *
+        * @param cl The classloader to use to load the class.
+        * @param name The readable class name.
+        * @return The class object.
+        * @throws ClassNotFoundException
+        */
+       public static Class<?> getClassFromReadableName(ClassLoader cl, String 
name) throws ClassNotFoundException {
+               return cl.loadClass(name);
+       }
+
+       /**
+        * Returns <jk>true</jk> if <code>parent</code> is a parent class of 
<code>child</code>.
+        *
+        * @param parent The parent class.
+        * @param child The child class.
+        * @param strict If <jk>true</jk> returns <jk>false</jk> if the classes 
are the same.
+        * @return <jk>true</jk> if <code>parent</code> is a parent class of 
<code>child</code>.
+        */
+       public static boolean isParentClass(Class<?> parent, Class<?> child, 
boolean strict) {
+               return parent.isAssignableFrom(child) && ((!strict) || ! 
parent.equals(child));
+       }
+
+       /**
+        * Returns <jk>true</jk> if <code>parent</code> is a parent class or 
the same as <code>child</code>.
+        *
+        * @param parent The parent class.
+        * @param child The child class.
+        * @return <jk>true</jk> if <code>parent</code> is a parent class or 
the same as <code>child</code>.
+        */
+       public static boolean isParentClass(Class<?> parent, Class<?> child) {
+               return isParentClass(parent, child, false);
+       }
+
+       /**
+        * Comparator for use with {@link TreeMap TreeMaps} with {@link Class} 
keys.
+        *
+        * @author James Bognar (james.bog...@salesforce.com)
+        */
+       public final static class ClassComparator implements 
Comparator<Class<?>>, Serializable {
+
+               private static final long serialVersionUID = 1L;
+
+               @Override /* Comparator */
+               public int compare(Class<?> object1, Class<?> object2) {
+                       return object1.getName().compareTo(object2.getName());
+               }
+       }
+
+       /**
+        * Returns the signature of the specified method.
+        * For no-arg methods, the signature will be a simple string such as 
<js>"toString"</js>.
+        * For methods with one or more args, the arguments will be 
fully-qualified class names (e.g. 
<js>"append(java.util.StringBuilder,boolean)"</js>)
+        *
+        * @param m The methods to get the signature on.
+        * @return The methods signature.
+        */
+       public static String getMethodSignature(Method m) {
+               StringBuilder sb = new StringBuilder(m.getName());
+               Class<?>[] pt = m.getParameterTypes();
+               if (pt.length > 0) {
+                       sb.append('(');
+                       for (int i = 0; i < pt.length; i++) {
+                               if (i > 0)
+                                       sb.append(',');
+                               sb.append(getReadableClassName(pt[i]));
+                       }
+                       sb.append(')');
+               }
+               return sb.toString();
+       }
+
+       private final static Map<Class<?>, Class<?>> pmap1 = new 
HashMap<Class<?>, Class<?>>(), pmap2 = new HashMap<Class<?>, Class<?>>();
+       static {
+               pmap1.put(boolean.class, Boolean.class);
+               pmap1.put(byte.class, Byte.class);
+               pmap1.put(short.class, Short.class);
+               pmap1.put(char.class, Character.class);
+               pmap1.put(int.class, Integer.class);
+               pmap1.put(long.class, Long.class);
+               pmap1.put(float.class, Float.class);
+               pmap1.put(double.class, Double.class);
+               pmap2.put(Boolean.class, boolean.class);
+               pmap2.put(Byte.class, byte.class);
+               pmap2.put(Short.class, short.class);
+               pmap2.put(Character.class, char.class);
+               pmap2.put(Integer.class, int.class);
+               pmap2.put(Long.class, long.class);
+               pmap2.put(Float.class, float.class);
+               pmap2.put(Double.class, double.class);
+       }
+
+       /**
+        * If the specified class is a primitive (e.g. 
<code><jk>int</jk>.<jk>class</jk></code>)
+        *      returns it's wrapper class (e.g. 
<code>Integer.<jk>class</jk></code>).
+        *
+        * @param c The class.
+        * @return The wrapper class, or <jk>null</jk> if class is not a 
primitive.
+        */
+       public static Class<?> getPrimitiveWrapper(Class<?> c) {
+               return pmap1.get(c);
+       }
+
+       /**
+        * If the specified class is a primitive wrapper (e.g. 
<code><jk>Integer</jk>.<jk>class</jk></code>)
+        *      returns it's primitive class (e.g. 
<code>int.<jk>class</jk></code>).
+        *
+        * @param c The class.
+        * @return The primitive class, or <jk>null</jk> if class is not a 
primitive wrapper.
+        */
+       public static Class<?> getPrimitiveForWrapper(Class<?> c) {
+               return pmap2.get(c);
+       }
+
+       /**
+        * If the specified class is a primitive (e.g. 
<code><jk>int</jk>.<jk>class</jk></code>)
+        *      returns it's wrapper class (e.g. 
<code>Integer.<jk>class</jk></code>).
+        *
+        * @param c The class.
+        * @return The wrapper class if it's primitive, or the same class if 
class is not a primitive.
+        */
+       public static Class<?> getWrapperIfPrimitive(Class<?> c) {
+               if (! c.isPrimitive())
+                       return c;
+               return pmap1.get(c);
+       }
+
+       /**
+        * Returns <jk>true</jk> if the specified class has the {@link 
Deprecated @Deprecated} annotation on it.
+        *
+        * @param c The class.
+        * @return <jk>true</jk> if the specified class has the {@link 
Deprecated @Deprecated} annotation on it.
+        */
+       public static boolean isNotDeprecated(Class<?> c) {
+               return ! c.isAnnotationPresent(Deprecated.class);
+       }
+
+       /**
+        * Returns <jk>true</jk> if the specified method has the {@link 
Deprecated @Deprecated} annotation on it.
+        *
+        * @param m The method.
+        * @return <jk>true</jk> if the specified method has the {@link 
Deprecated @Deprecated} annotation on it.
+        */
+       public static boolean isNotDeprecated(Method m) {
+               return ! m.isAnnotationPresent(Deprecated.class);
+
+       }
+
+       /**
+        * Returns <jk>true</jk> if the specified constructor has the {@link 
Deprecated @Deprecated} annotation on it.
+        *
+        * @param c The constructor.
+        * @return <jk>true</jk> if the specified constructor has the {@link 
Deprecated @Deprecated} annotation on it.
+        */
+       public static boolean isNotDeprecated(Constructor<?> c) {
+               return ! c.isAnnotationPresent(Deprecated.class);
+       }
+
+       /**
+        * Returns <jk>true</jk> if the specified class is public.
+        *
+        * @param c The class.
+        * @return <jk>true</jk> if the specified class is public.
+        */
+       public static boolean isPublic(Class<?> c) {
+               return Modifier.isPublic(c.getModifiers());
+       }
+
+       /**
+        * Returns <jk>true</jk> if the specified class is public.
+        *
+        * @param c The class.
+        * @return <jk>true</jk> if the specified class is public.
+        */
+       public static boolean isStatic(Class<?> c) {
+               return Modifier.isStatic(c.getModifiers());
+       }
+
+       /**
+        * Returns <jk>true</jk> if the specified method is public.
+        *
+        * @param m The method.
+        * @return <jk>true</jk> if the specified method is public.
+        */
+       public static boolean isPublic(Method m) {
+               return Modifier.isPublic(m.getModifiers());
+       }
+
+       /**
+        * Returns <jk>true</jk> if the specified method is static.
+        *
+        * @param m The method.
+        * @return <jk>true</jk> if the specified method is static.
+        */
+       public static boolean isStatic(Method m) {
+               return Modifier.isStatic(m.getModifiers());
+       }
+
+       /**
+        * Returns <jk>true</jk> if the specified constructor is public.
+        *
+        * @param c The constructor.
+        * @return <jk>true</jk> if the specified constructor is public.
+        */
+       public static boolean isPublic(Constructor<?> c) {
+               return Modifier.isPublic(c.getModifiers());
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/CollectionUtils.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/CollectionUtils.java
 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/CollectionUtils.java
new file mode 100644
index 0000000..9c8ad8f
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/CollectionUtils.java
@@ -0,0 +1,57 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import java.util.*;
+
+/**
+ * Utility methods for collections.
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ */
+public class CollectionUtils {
+
+       /**
+        * Reverses the order of a {@link LinkedHashMap}.
+        *
+        * @param in The map to reverse the order on.
+        * @return A new {@link LinkedHashMap} with keys in reverse order.
+        */
+       public static <K,V> LinkedHashMap<K,V> reverse(LinkedHashMap<K,V> in) {
+               if (in == null)
+                       return null;
+               LinkedHashMap<K,V> m = new LinkedHashMap<K,V>();
+
+               // Note:  Entry objects are reusable in an entry set, so we 
simply can't
+               // create a reversed iteration of that set.
+               List<K> keys = new ArrayList<K>(in.keySet());
+               List<V> values = new ArrayList<V>(in.values());
+               for (int i = in.size()-1; i >= 0; i--)
+                       m.put(keys.get(i), values.get(i));
+
+               return m;
+       }
+
+       /**
+        * Add a value to a list if the value is not null.
+        *
+        * @param l The list to add to.
+        * @param o The element to add.
+        * @return The same list.
+        */
+       public static <T> List<T> addIfNotNull(List<T> l, T o) {
+               if (o != null)
+                       l.add(o);
+               return l;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateBeanMap.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateBeanMap.java
 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateBeanMap.java
new file mode 100644
index 0000000..6110f2a
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateBeanMap.java
@@ -0,0 +1,127 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+
+/**
+ * Represents a wrapped {@link BeanMap} where property values can be 
overridden, removed, or reordered
+ *     without affecting the underlying bean.
+ * <p>
+ *     Provides the {@link #filterKeys(List)} method for specifying the keys 
to keep in the bean map
+ *             and in what order they should appear.
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ * @param <T> The class type of the wrapped bean.
+ */
+@SuppressWarnings("hiding")
+public class DelegateBeanMap<T> extends BeanMap<T> {
+
+       private Set<String> keys = Collections.newSetFromMap(new 
LinkedHashMap<String,Boolean>());
+       private ObjectMap overrideValues = new ObjectMap();
+
+       /**
+        * Constructor.
+        *
+        * @param bean The bean being wrapped.
+        * @param bc The bean context that created this bean map.
+        */
+       @SuppressWarnings("unchecked")
+       public
+       DelegateBeanMap(T bean, BeanContext bc) {
+               super(bean, bc.getBeanMeta((Class<T>)bean.getClass()));
+       }
+
+       /**
+        * Add a key in the next position.
+        *
+        * @param key The key to add.
+        */
+       public void addKey(String key) {
+               this.keys.add(key);
+       }
+
+       @Override /* Map */
+       public Object put(String key, Object val) {
+               this.overrideValues.put(key, val);
+               this.keys.add(key);
+               return null;
+       }
+
+       @Override /* Map */
+       public Object get(Object key) {
+               if (overrideValues.containsKey(key))
+                       return overrideValues.get(key);
+               return super.get(key);
+       }
+
+       @Override /* Map */
+       public Set<String> keySet() {
+               return keys;
+       }
+
+       /**
+        * Remove all but the specified properties from this bean map.
+        * <p>
+        * This does not affect the underlying bean.
+        *
+        * @param keys The remaining keys in the bean map (in the specified 
order).
+        */
+       public void filterKeys(List<String> keys) {
+               this.keys.clear();
+               this.keys.addAll(keys);
+       }
+
+       @Override /* Map */
+       public Object remove(Object key) {
+               keys.remove(key);
+               return null;
+       }
+
+       @Override /* BeanMap */
+       public BeanMeta<T> getMeta() {
+               return new BeanMetaFiltered<T>(super.getMeta(), keys);
+       }
+
+       @Override /* Map */
+       public Set<Entry<String,Object>> entrySet() {
+               Set<Entry<String,Object>> s = Collections.newSetFromMap(new 
LinkedHashMap<Map.Entry<String,Object>,Boolean>());
+               for (final String key : keys) {
+                       BeanMapEntry<T> bme;
+                       if (overrideValues.containsKey(key))
+                               bme = new BeanMapEntryOverride<T>(this, 
this.getPropertyMeta(key), overrideValues.get(key));
+                       else
+                               bme = this.getProperty(key);
+                       if (bme == null)
+                               throw new 
BeanRuntimeException(super.getClassMeta().getInnerClass(), "Property ''{0}'' 
not found on class.", key);
+                       s.add(bme);
+               }
+               return s;
+       }
+
+       private class BeanMapEntryOverride<T2> extends BeanMapEntry<T2> {
+               Object value;
+
+               private BeanMapEntryOverride(BeanMap<T2> bm, 
BeanPropertyMeta<T2> bpm, Object value) {
+                       super(bm, bpm);
+                       this.value = value;
+               }
+
+               @Override /* Map.Entry */
+               public Object getValue() {
+                       return value;
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateList.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateList.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateList.java
new file mode 100644
index 0000000..bde29c7
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateList.java
@@ -0,0 +1,44 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+
+/**
+ * Represents a wrapped {@link Collection} where entries in the list can be 
removed or reordered without
+ *     affecting the underlying list.
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ * @param <T> The class type of the wrapped bean.
+ */
+public class DelegateList<T extends Collection<?>> extends ObjectList 
implements Delegate<T> {
+       private static final long serialVersionUID = 1L;
+
+       private transient ClassMeta<T> classMeta;
+
+       /**
+        * Constructor.
+        *
+        * @param classMeta The metadata object that created this delegate list.
+        */
+       public DelegateList(ClassMeta<T> classMeta) {
+               this.classMeta = classMeta;
+       }
+
+       @Override /* Delegate */
+       public ClassMeta<T> getClassMeta() {
+               return classMeta;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateMap.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateMap.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateMap.java
new file mode 100644
index 0000000..0b9a4f4
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/DelegateMap.java
@@ -0,0 +1,59 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+
+/**
+ * Represents a wrapped {@link Map} where entries in the map can be removed 
without
+ *     affecting the underlying map.
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ * @param <T> The class type of the wrapped bean.
+ */
+public class DelegateMap<T> extends ObjectMap implements Delegate<T> {
+       private static final long serialVersionUID = 1L;
+
+       private transient ClassMeta<T> classMeta;
+
+       /**
+        * Constructor.
+        *
+        * @param classMeta The metadata object that created this delegate 
object.
+        */
+       public DelegateMap(ClassMeta<T> classMeta) {
+               this.classMeta = classMeta;
+       }
+
+       @Override /* Delegate */
+       public ClassMeta<T> getClassMeta() {
+               return classMeta;
+       }
+
+       /**
+        * Remove all but the specified keys from this map.
+        * <p>
+        * This does not affect the underlying map.
+        *
+        * @param keys The remaining keys in the map (in the specified order).
+        */
+       public void filterKeys(List<String> keys) {
+               ObjectMap m2 = new ObjectMap();
+               for (String k : keys)
+                       m2.put(k, get(k));
+               this.clear();
+               this.putAll(m2);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/FileUtils.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/FileUtils.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/FileUtils.java
new file mode 100644
index 0000000..c01ab20
--- /dev/null
+++ b/org.apache.juneau/src/main/java/org/apache/juneau/internal/FileUtils.java
@@ -0,0 +1,134 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import static org.apache.juneau.internal.ThrowableUtils.*;
+
+import java.io.*;
+
+/**
+ * File utilities.
+ */
+public class FileUtils {
+
+       /**
+        * Same as {@link File#mkdirs()} except throws a RuntimeExeption if 
directory could not be created.
+        *
+        * @param f The directory to create.  Must not be <jk>null</jk>.
+        * @param clean If <jk>true</jk>, deletes the contents of the directory 
if it already exists.
+        * @return The same file.
+        * @throws RuntimeException if directory could not be created.
+        */
+       public static File mkdirs(File f, boolean clean) {
+               assertFieldNotNull(f, "f");
+               if (f.exists()) {
+                       if (clean) {
+                               if (! delete(f))
+                                       throw new RuntimeException("Could not 
clean directory '"+f.getAbsolutePath()+"'");
+                       } else {
+                               return f;
+                       }
+               }
+               if (! f.mkdirs())
+                       throw new RuntimeException("Could not create directory 
'" + f.getAbsolutePath() + "'");
+               return f;
+       }
+
+       /**
+        * Same as {@link #mkdirs(String, boolean)} but uses String path.
+        *
+        * @param path The path of the directory to create.  Must not be 
<jk>null</jk>
+        * @param clean If <jk>true</jk>, deletes the contents of the directory 
if it already exists.
+        * @return The directory.
+        */
+       public static File mkdirs(String path, boolean clean) {
+               assertFieldNotNull(path, "path");
+               return mkdirs(new File(path), clean);
+       }
+
+       /**
+        * Recursively deletes a file or directory.
+        *
+        * @param f The file or directory to delete.
+        * @return <jk>true</jk> if file or directory was successfully deleted.
+        */
+       public static boolean delete(File f) {
+               if (f == null)
+                       return true;
+               if (f.isDirectory()) {
+                       File[] cf = f.listFiles();
+                       if (cf != null)
+                               for (File c : cf)
+                                       delete(c);
+               }
+               return f.delete();
+       }
+
+       /**
+        * Creates a file if it doesn't already exist using {@link 
File#createNewFile()}.
+        * Throws a {@link RuntimeException} if the file could not be created.
+        *
+        * @param f The file to create.
+        */
+       public static void create(File f) {
+               if (f.exists())
+                       return;
+               try {
+                       if (! f.createNewFile())
+                               throw new RuntimeException("Could not create 
file '"+f.getAbsolutePath()+"'");
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       /**
+        * Updates the modified timestamp on the specified file.
+        * Method ensures that the timestamp changes even if it's been modified 
within the past millisecond.
+        *
+        * @param f The file to modify the modified timestamp on.
+        */
+       public static void modifyTimestamp(File f) {
+               long lm = f.lastModified();
+               long l = System.currentTimeMillis();
+               if (lm == l)
+                       l++;
+               if (! f.setLastModified(l))
+                       throw new RuntimeException("Could not modify timestamp 
on file '"+f.getAbsolutePath()+"'");
+
+               // Linux only gives 1s precision, so set the date 1s into the 
future.
+               if (lm == f.lastModified()) {
+                       l += 1000;
+                       if (! f.setLastModified(l))
+                               throw new RuntimeException("Could not modify 
timestamp on file '"+f.getAbsolutePath()+"'");
+               }
+       }
+
+       /**
+        * Create a temporary file with the specified name.
+        * <p>
+        * The name is broken into file name and suffix, and the parts
+        * are passed to {@link File#createTempFile(String, String)}.
+        * <p>
+        * {@link File#deleteOnExit()} is called on the resulting file before 
being returned by this method.
+        *
+        * @param name The file name
+        * @return A newly-created temporary file.
+        * @throws IOException
+        */
+       public static File createTempFile(String name) throws IOException {
+               String[] parts = name.split("\\.");
+               File f = File.createTempFile(parts[0], "." + parts[1]);
+               f.deleteOnExit();
+               return f;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/FilteredMap.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/FilteredMap.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/FilteredMap.java
new file mode 100644
index 0000000..b4ce73b
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/FilteredMap.java
@@ -0,0 +1,96 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import static org.apache.juneau.internal.ThrowableUtils.*;
+
+import java.util.*;
+
+/**
+ * Wrapper around a map where the key names are overridden.
+ *
+ * @param <K> The key class type.
+ * @param <V> The value class type.
+ * @author James Bognar (james.bog...@salesforce.com)
+ */
+public final class FilteredMap<K,V> extends AbstractMap<K,V> {
+
+       private Map<K,V> innerMap;
+       private Set<Map.Entry<K,V>> entries;
+
+       /**
+        * Constructor.
+        *
+        * @param innerMap The map being wrapped.  Must not be <jk>null</jk>.
+        * @param keys The keys in the new map.  Must not be <jk>null</jk>.
+        */
+       public FilteredMap(Map<K,V> innerMap, K[] keys) {
+               assertFieldNotNull(innerMap, "innerMap");
+               assertFieldNotNull(keys, "keys");
+
+               this.innerMap = innerMap;
+                       List<Map.Entry<K,V>> l = new 
ArrayList<Map.Entry<K,V>>(keys.length);
+                       for (K k : keys)
+                               if (innerMap.containsKey(k))
+                                       l.add(createEntry(k));
+                       entries = new ListSet<Map.Entry<K,V>>(l);
+               }
+
+       private Map.Entry<K,V> createEntry(final K key) {
+               return new Map.Entry<K,V>() {
+
+                       @Override /* Map.Entry */
+                       public K getKey() {
+                               return key;
+                       }
+
+                       @Override /* Map.Entry */
+                       public V getValue() {
+                               return innerMap.get(key);
+                       }
+
+                       @Override /* Map.Entry */
+                       public V setValue(V v) {
+                               return innerMap.put(key, v);
+                       }
+               };
+       }
+
+
+       @Override /* Map */
+       public Set<Map.Entry<K,V>> entrySet() {
+               return entries;
+       }
+
+       /**
+        * A set with ordered entries (i.e. a List with a Set API).
+        */
+       private static class ListSet<E> extends AbstractSet<E> {
+
+               private List<E> entries;
+
+               public ListSet(List<E> entries) {
+                       this.entries = entries;
+               }
+
+               @Override /* Set */
+               public Iterator<E> iterator() {
+                       return entries.iterator();
+               }
+
+               @Override /* Set */
+               public int size() {
+                       return entries.size();
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/HashCode.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/HashCode.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/HashCode.java
new file mode 100644
index 0000000..5bdfb80
--- /dev/null
+++ b/org.apache.juneau/src/main/java/org/apache/juneau/internal/HashCode.java
@@ -0,0 +1,71 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+/**
+ * Utility class for generating integer hash codes.
+ * <p>
+ *     General usage:
+ * <p class='bcode'>
+ *     int hashCode = new 
HashCode().add("foobar").add(myobject).add(123).get();
+ * </p>
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ */
+public final class HashCode {
+
+       private int hashCode = 1;
+
+       /**
+        * Create a new HashCode object.
+        *
+        * @return A new HashCode object.
+        */
+       public static final HashCode create() {
+               return new HashCode();
+       }
+
+
+       /**
+        * Hashes the hashcode of the specified object into this object.
+        *
+        * @param o The object whose hashcode will be hashed with this object.
+        * @return This object (for method chaining).
+        */
+       public HashCode add(Object o) {
+               add(o == null ? 1 : o.hashCode());
+               return this;
+       }
+
+       /**
+        * Hashes the hashcode into this object.
+        * <p>
+        * The formula is simply <code>hashCode = 31*hashCode + i;</code>
+        *
+        * @param i The hashcode to hash into this object's hashcode.
+        * @return This object (for method chaining).
+        */
+       public HashCode add(int i) {
+      hashCode = 31*hashCode + i;
+               return this;
+       }
+
+       /**
+        * Return the calculated hashcode value.
+        *
+        * @return The calculated hashcode.
+        */
+       public int get() {
+      return hashCode;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/IOUtils.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/IOUtils.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/IOUtils.java
new file mode 100644
index 0000000..e37134c
--- /dev/null
+++ b/org.apache.juneau/src/main/java/org/apache/juneau/internal/IOUtils.java
@@ -0,0 +1,349 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import static org.apache.juneau.internal.ThrowableUtils.*;
+
+import java.io.*;
+import java.nio.charset.*;
+
+import org.apache.juneau.utils.*;
+
+/**
+ * Various I/O related utility methods.
+ *
+ * @author jbognar
+ */
+public final class IOUtils {
+
+       /** UTF-8 charset */
+       public static final Charset UTF8 = Charset.forName("UTF-8");
+
+       /**
+        * Reads the contents of a file into a string.
+        *
+        * @param path The path of the file to read using default character 
encoding.
+        * @return The contents of the reader as a string, or <jk>null</jk> if 
file does not exist.
+        * @throws IOException If a problem occurred trying to read from the 
reader.
+        */
+       public static String readFile(String path) throws IOException {
+               return read(new File(path));
+       }
+
+       /**
+        * Reads the contents of a file into a string.
+        *
+        * @param in The file to read using default character encoding.
+        * @return The contents of the reader as a string, or <jk>null</jk> if 
file does not exist.
+        * @throws IOException If a problem occurred trying to read from the 
reader.
+        */
+       public static String read(File in) throws IOException {
+               if (in == null || ! in.exists())
+                       return null;
+               Reader r = new InputStreamReader(new FileInputStream(in), 
Charset.defaultCharset());
+               return read(r, 0, 1024);
+       }
+
+       /**
+        * Writes the contents of the specified <code>Reader</code> to the 
specified file.
+        *
+        * @param out The file to write the output to.
+        * @param in The reader to pipe from.
+        * @return The number of characters written to the file.
+        * @throws IOException
+        */
+       public static int write(File out, Reader in) throws IOException {
+               assertFieldNotNull(out, "out");
+               assertFieldNotNull(in, "in");
+               Writer w = new OutputStreamWriter(new FileOutputStream(out), 
Charset.defaultCharset());
+               try {
+                       return IOPipe.create(in, w).closeOut().run();
+               } finally {
+                       w.close();
+               }
+       }
+
+       /**
+        * Writes the contents of the specified <code>InputStream</code> to the 
specified file.
+        *
+        * @param out The file to write the output to.
+        * @param in The input stream to pipe from.
+        * @return The number of characters written to the file.
+        * @throws IOException
+        */
+       public static int write(File out, InputStream in) throws IOException {
+               assertFieldNotNull(out, "out");
+               assertFieldNotNull(in, "in");
+               OutputStream os = new FileOutputStream(out);
+               try {
+                       return IOPipe.create(in, os).closeOut().run();
+               } finally {
+                       os.close();
+               }
+       }
+
+       /**
+        * Reads the contents of a reader into a string.
+        *
+        * @param in The input reader.
+        * @return The contents of the reader as a string.
+        * @throws IOException If a problem occurred trying to read from the 
reader.
+        */
+       public static String read(Reader in) throws IOException {
+               return read(in, 0, 1024);
+       }
+
+       /**
+        * Reads the contents of an input stream into a string using the 
specified charset.
+        *
+        * @param in The input stream.
+        * @param cs The charset of the contents of the input stream.
+        * @return The contents of the reader as a string.  <jk>null</jk> if 
input stream was null.
+        * @throws IOException If a problem occurred trying to read from the 
input stream.
+        */
+       public static String read(InputStream in, Charset cs) throws 
IOException {
+               if (in == null)
+                       return null;
+               return read(new InputStreamReader(in, cs));
+       }
+
+       /**
+        * Reads the contents of an input stream into a string using the system 
default charset.
+        *
+        * @param in The input stream.
+        * @return The contents of the reader as a string, or <jk>null</jk> if 
the input stream is null.
+        * @throws IOException If a problem occurred trying to read from the 
input stream.
+        */
+       public static String read(InputStream in) throws IOException {
+               if (in == null)
+                       return null;
+               return read(new InputStreamReader(in, 
Charset.defaultCharset()));
+       }
+
+       /**
+        * Read the specified input stream into a byte array and closes the 
stream.
+        *
+        * @param in The input stream.
+        * @param bufferSize The expected size of the buffer.
+        * @return The contents of the stream as a byte array.
+        * @throws IOException Thrown by underlying stream.
+        */
+       public static byte[] readBytes(InputStream in, int bufferSize) throws 
IOException {
+               if (in == null)
+                       return null;
+               ByteArrayOutputStream buff = new 
ByteArrayOutputStream(bufferSize);
+               int nRead;
+               byte[] b = new byte[Math.min(bufferSize, 8192)];
+
+               try {
+                       while ((nRead = in.read(b, 0, b.length)) != -1)
+                                 buff.write(b, 0, nRead);
+
+                               buff.flush();
+
+                               return buff.toByteArray();
+               } finally {
+                       in.close();
+               }
+       }
+
+
+       /**
+        * Reads the specified input into a {@link String} until the end of the 
input is reached.
+        * <p>
+        *      The {@code Reader} is automatically closed.
+        * <p>
+        *      If the {@code Reader} is not an instance of a {@code 
BufferedReader}, then it gets wrapped in a {@code BufferedReader}.
+        *
+        * @param in The input reader.
+        * @param length Specify a positive number if the length of the input 
is known.
+        * @param bufferSize Specify the buffer size to use.
+        * @return The contents of the reader as a string.  <jk>null</jk> if 
reader was null.
+        * @throws IOException If a problem occurred trying to read from the 
reader.
+        */
+       public static String read(Reader in, int length, int bufferSize) throws 
IOException {
+               if (in == null)
+                       return null;
+               length = (length <= 0 ? bufferSize : length);
+               StringBuilder sb = new StringBuilder(length); // Assume they're 
ASCII characters.
+               try {
+                       char[] buf = new char[Math.min(bufferSize, length)];
+                       int i = 0;
+                       while ((i = in.read(buf)) != -1)
+                               sb.append(buf, 0, i);
+                       return sb.toString();
+               } finally {
+                       in.close();
+               }
+       }
+
+       /**
+        * Pipes the contents of the specified reader into the writer.
+        * The reader is closed, the writer is not.
+        *
+        * @param in The reader to pipe from.
+        * @param out The writer to pipe to.
+        * @throws IOException
+        */
+   public static void pipe(Reader in, Writer out) throws IOException {
+               assertFieldNotNull(out, "out");
+               assertFieldNotNull(in, "in");
+      IOPipe.create(in, out).run();
+   }
+
+       /**
+        * Wraps the specified reader in a buffered reader.
+        *
+        * @param r The reader being wrapped.
+        * @return The reader wrapped in a {@link BufferedReader}, or the 
original {@link Reader} if it's already
+        *      a buffered reader.
+        */
+       public static Reader getBufferedReader(Reader r) {
+               if (r instanceof BufferedReader || r instanceof StringReader)
+                       return r;
+               return new BufferedReader(r);
+       }
+
+       /**
+        * Counts the number of bytes in the input stream and then closes the 
stream.
+        *
+        * @param is The input stream to read from.
+        * @return The number of bytes read.
+        * @throws IOException
+        */
+       public static long count(InputStream is) throws IOException {
+               assertFieldNotNull(is, "is");
+               long c = 0;
+               long i;
+               try {
+                       while ((i = is.skip(1024)) != 0)
+                               c += i;
+               } finally {
+                       is.close();
+               }
+               return c;
+       }
+
+       /**
+        * Counts the number of characters in the reader and then closes the 
reader.
+        *
+        * @param r The reader to read from.
+        * @return The number of characters read.
+        * @throws IOException
+        */
+       public static long count(Reader r) throws IOException {
+               assertFieldNotNull(r, "r");
+               long c = 0;
+               long i;
+               try {
+                       while ((i = r.skip(1024)) != 0)
+                               c += i;
+               } finally {
+                       r.close();
+               }
+               return c;
+       }
+
+       /**
+        * Given the specified <js>"Content-Length"</js> header value, return 
an appropriate buffer size.
+        * The maximum buffer size is 1MB.
+        *
+        * @param contentLength The value of the <js>"Content-Length"</js> 
header.
+        * @return The appropriate buffer size.
+        */
+       public static int getBufferSize(String contentLength) {
+               try {
+                       if (! StringUtils.isEmpty(contentLength)) {
+                               long l = Long.decode(contentLength);
+                               if (l > 1048576)
+                                       return 1048576;
+                               if (l <= 0)
+                                       return 8192;
+                               return (int)l;
+                       }
+               } catch (Exception e) {
+                       return 8192;
+               }
+               return 8192;
+       }
+
+       /**
+        * Close input stream and ignore any exceptions.
+        * No-op if input stream is <jk>null</jk>.
+        *
+        * @param is The input stream to close.
+        */
+       public static void closeQuietly(InputStream is) {
+               try {
+                       if (is != null)
+                               is.close();
+               } catch (IOException e) {}
+       }
+
+       /**
+        * Close output stream and ignore any exceptions.
+        * No-op if output stream is <jk>null</jk>.
+        *
+        * @param os The output stream to close.
+        */
+       public static void closeQuietly(OutputStream os) {
+               try {
+                       if (os != null)
+                               os.close();
+               } catch (IOException e) {}
+       }
+
+       /**
+        * Close reader and ignore any exceptions.
+        * No-op if reader is <jk>null</jk>.
+        *
+        * @param r The reader to close.
+        */
+       public static void closeQuietly(Reader r) {
+               try {
+                       if (r != null)
+                               r.close();
+               } catch (IOException e) {}
+       }
+
+       /**
+        * Close writer and ignore any exceptions.
+        * No-op if writer is <jk>null</jk>.
+        *
+        * @param w The writer to close.
+        */
+       public static void closeQuietly(Writer w) {
+               try {
+                       if (w != null)
+                               w.close();
+               } catch (IOException e) {}
+       }
+
+       /**
+        * Quietly close all specified input streams, output streams, readers, 
and writers.
+        *
+        * @param o The list of all objects to quietly close.
+        */
+       public static void closeQuietly(Object...o) {
+               for (Object o2 : o) {
+                       if (o2 instanceof InputStream)
+                               closeQuietly((InputStream)o2);
+                       if (o2 instanceof OutputStream)
+                               closeQuietly((OutputStream)o2);
+                       if (o2 instanceof Reader)
+                               closeQuietly((Reader)o2);
+                       if (o2 instanceof Writer)
+                               closeQuietly((Writer)o2);
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/IdentityList.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/IdentityList.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/IdentityList.java
new file mode 100644
index 0000000..2d9345d
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/IdentityList.java
@@ -0,0 +1,49 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import java.util.*;
+
+/**
+ * Combination of a {@link LinkedList} and <code>IdentitySet</code>.
+ * <ul class='spaced-list'>
+ *     <li>Duplicate objects (by identity) will be skipped during insertion.
+ *     <li>Order of insertion maintained.
+ * </ul>
+ * <p>
+ *     Note:  This class is NOT thread safe, and is intended for use on small 
lists.
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ * @param <T> Entry type.
+ */
+public class IdentityList<T> extends LinkedList<T> {
+
+       private static final long serialVersionUID = 1L;
+
+       @Override /* List */
+       public boolean add(T t) {
+               for (T t2 : this)
+                       if (t2 == t)
+                               return false;
+               super.add(t);
+               return true;
+       }
+
+       @Override /* List */
+       public boolean contains(Object t) {
+               for (T t2 : this)
+                       if (t2 == t)
+                               return true;
+               return false;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/JuneauLogger.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/JuneauLogger.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/JuneauLogger.java
new file mode 100644
index 0000000..4bd90ef
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/JuneauLogger.java
@@ -0,0 +1,295 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import static java.util.logging.Level.*;
+
+import java.text.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.logging.*;
+
+import org.apache.juneau.json.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.transforms.*;
+
+/**
+ * Wraps and extends the {@link java.util.logging.Logger} class to provide 
some additional convenience methods.
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ */
+public class JuneauLogger extends java.util.logging.Logger {
+
+       private static final WriterSerializer serializer = 
JsonSerializer.DEFAULT_LAX.clone()
+               .addTransforms(
+                       CalendarTransform.ISO8601DTZ.class,
+                       DateTransform.ISO8601DTZ.class,
+                       EnumerationTransform.class,
+                       IteratorTransform.class
+               );
+
+       private static final ConcurrentHashMap<Class<?>,String> rbMap = new 
ConcurrentHashMap<Class<?>,String>();
+
+       private final ResourceBundle rb;
+       private final java.util.logging.Logger innerLogger;
+
+       /**
+        * Get logger for specified class.
+        *
+        * @param forClass The class to create a logger for.
+        * @return A new <l>Logger</l>.
+        */
+       public static JuneauLogger getLogger(Class<?> forClass) {
+               return new 
JuneauLogger(java.util.logging.Logger.getLogger(forClass.getName()));
+       }
+
+       /**
+        * Get logger for specified class using the specified resource bundle 
name.
+        *
+        * @param forClass The class to create a logger for.
+        * @param resourceBundleName The name of the resource bundle.
+        *      Can be any of the following formats:
+        *      <ol>
+        *              <li>An absolute path.  E.g. 
<js>"com/ibm/nls/Messages"</js>.
+        *              <li>A path relative to the package of the class.  E.g. 
<js>"nls/Messages"</js>.
+        *      </ol>
+        *      Both <js>'.'</js> and <js>'/'</js> can be used as path 
delimiters.
+        * @return A new <l>Logger</l>.
+        */
+       public static JuneauLogger getLogger(Class<?> forClass, String 
resourceBundleName) {
+               return new 
JuneauLogger(java.util.logging.Logger.getLogger(forClass.getName(), 
resolveResourceBundleName(forClass, resourceBundleName)));
+       }
+
+       /**
+        * Get logger with specified name using the specified resource bundle 
name.
+        *
+        * @param name The name of the logger to use.
+        * @param resourceBundleName The name of the resource bundle.
+        *      Can be any of the following formats:
+        *      <ol>
+        *              <li>An absolute path.  E.g. 
<js>"com/ibm/nls/Messages"</js>.
+        *              <li>A path relative to the package of the class.  E.g. 
<js>"nls/Messages"</js>.
+        *      </ol>
+        *      Both <js>'.'</js> and <js>'/'</js> can be used as path 
delimiters.
+        * @return A new <l>Logger</l>.
+        */
+       public static JuneauLogger getLogger(String name, String 
resourceBundleName) {
+               return new 
JuneauLogger(java.util.logging.Logger.getLogger(name, resourceBundleName));
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param innerLogger The wrapped logger.
+        */
+       protected JuneauLogger(java.util.logging.Logger innerLogger) {
+               super(innerLogger.getName(), 
innerLogger.getResourceBundleName());
+               this.innerLogger = innerLogger;
+               this.rb = getResourceBundle();
+       }
+
+       /**
+     * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#SEVERE} level.
+     *
+     * @param msg The message to log.
+     * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void severe(String msg, Object...args) {
+               if (isLoggable(SEVERE))
+                       log(SEVERE, msg, args);
+       }
+
+       /**
+    * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#WARNING} level.
+    *
+    * @param msg The message to log.
+    * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void warning(String msg, Object...args) {
+               if (isLoggable(WARNING))
+                       log(WARNING, msg, args);
+       }
+
+       /**
+    * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#INFO} level.
+    *
+    * @param msg The message to log.
+    * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void info(String msg, Object...args) {
+               if (isLoggable(INFO))
+                       log(INFO, msg, args);
+       }
+
+       /**
+    * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#CONFIG} level.
+    *
+    * @param msg The message to log.
+    * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void config(String msg, Object...args) {
+               if (isLoggable(CONFIG))
+                       log(CONFIG, msg, args);
+       }
+
+       /**
+    * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#FINE} level.
+    *
+    * @param msg The message to log.
+    * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void fine(String msg, Object...args) {
+               if (isLoggable(FINE))
+                       log(FINE, msg, args);
+       }
+
+       /**
+    * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#FINER} level.
+    *
+    * @param msg The message to log.
+    * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void finer(String msg, Object...args) {
+               if (isLoggable(FINER))
+                       log(FINER, msg, args);
+       }
+
+       /**
+    * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#FINEST} level.
+    *
+    * @param msg The message to log.
+    * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void finest(String msg, Object...args) {
+               if (isLoggable(FINEST))
+                       log(FINEST, msg, args);
+       }
+
+       /**
+    * Logs an exception as {@link Level#SEVERE} level.
+        *
+        * @param t The Throwable object to log.
+        */
+       public void severe(Throwable t) {
+               if (isLoggable(SEVERE))
+                       log(SEVERE, t.getLocalizedMessage(), t);
+       }
+
+       /**
+    * Logs an exception as {@link Level#WARNING} level.
+        *
+        * @param t The Throwable object to log.
+        */
+       public void warning(Throwable t) {
+               if (isLoggable(WARNING))
+                       log(WARNING, t.getLocalizedMessage(), t);
+       }
+
+       /**
+    * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#SEVERE} level.
+        *
+        * @param t The Throwable object associated with the event that needs 
to be logged.
+    * @param msg The message to log.
+    * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void severe(Throwable t, String msg, Object...args) {
+               if (isLoggable(SEVERE))
+                       log(SEVERE, getMessage(msg, args), t);
+       }
+
+       /**
+    * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#WARNING} level.
+        *
+        * @param t The Throwable object associated with the event that needs 
to be logged.
+    * @param msg The message to log.
+    * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void warning(Throwable t, String msg, Object...args) {
+               if (isLoggable(WARNING))
+                       log(WARNING, getMessage(msg, args), t);
+       }
+
+       /**
+    * Logs a message with the specified {@link MessageFormat}-style arguments 
at {@link Level#INFO} level.
+        *
+        * @param t The Throwable object associated with the event that needs 
to be logged.
+    * @param msg The message to log.
+    * @param args The {@link MessageFormat}-style arguments.
+        */
+       public void info(Throwable t, String msg, Object...args) {
+               if (isLoggable(INFO))
+                       log(INFO, getMessage(msg, args), t);
+       }
+
+   @Override /* Logger */
+       public void log(LogRecord record) {
+       innerLogger.log(record);
+   }
+
+   @Override /* Logger */
+       public boolean isLoggable(Level level) {
+       return innerLogger.isLoggable(level);
+   }
+
+       /**
+    * Similar to {@link #log(Level, String, Object[])}, except arguments are 
converted to objects
+    *  that are serialized using the {@link 
JsonSerializer#toStringObject(Object)} method.
+    * This allows arbitrary POJOs to be serialized as message parameters.
+        *
+        * @param level The level of the given message.
+    * @param msg The message to log.
+    * @param args The POJO arguments.
+        */
+       public void logObjects(Level level, String msg, Object...args) {
+               if (isLoggable(level)) {
+                       for (int i = 0; i < args.length; i++)
+                               args[i] = serializer.toStringObject(args[i]);
+                       log(level, msg, args);
+               }
+       }
+
+       private String getMessage(String msg, Object...args) {
+               if (args.length == 0)
+                       return msg;
+               if (rb != null && rb.containsKey(msg))
+                       msg = rb.getString(msg);
+               return MessageFormat.format(msg, args);
+       }
+
+       private static String resolveResourceBundleName(Class<?> forClass, 
String path) {
+               if (StringUtils.isEmpty(path))
+                       return null;
+               String rb = rbMap.get(forClass);
+               if (rb == null) {
+                       path = path.replace('/', '.');
+                       if (path.startsWith("."))
+                               path = path.substring(1);
+                       ClassLoader cl = forClass.getClassLoader();
+                       try {
+                               ResourceBundle.getBundle(path, 
Locale.getDefault(), cl);
+                               rbMap.putIfAbsent(forClass, path);
+                       } catch (MissingResourceException e) {
+                               try {
+                                       path = forClass.getPackage().getName() 
+ '.' + path;
+                                       ResourceBundle.getBundle(path, 
Locale.getDefault(), cl);
+                                       rbMap.putIfAbsent(forClass, path);
+                               } catch (MissingResourceException e2) {
+                                       rbMap.putIfAbsent(forClass, "");
+                               }
+                       }
+                       rb = rbMap.get(forClass);
+               }
+               return ("".equals(rb) ? null : rb);
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/KeywordSet.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/KeywordSet.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/KeywordSet.java
new file mode 100644
index 0000000..c23a912
--- /dev/null
+++ b/org.apache.juneau/src/main/java/org/apache/juneau/internal/KeywordSet.java
@@ -0,0 +1,90 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import static org.apache.juneau.internal.ThrowableUtils.*;
+
+/**
+ * Stores a set of language keywords for quick lookup.
+ * <p>
+ * Keywords must be:
+ * <ul class='spaced-list'>
+ *     <li>2 or more characters in length.
+ *     <li>Lowercase ASCII.
+ * </ul>
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ */
+public final class KeywordSet {
+       final char[][][][] store;
+
+       /**
+        * Constructor.
+        *
+        * @param keywords The list of keywords.
+        */
+       public KeywordSet(String... keywords) {
+               this.store = new char[26][][][];
+
+               for (String keyword : keywords) {
+                       if (keyword.length() < 2)
+                               illegalArg("Invalid keyword '{0}' passed to 
KeywordStore.", keyword);
+                       int c0 = keyword.charAt(0) - 'a';
+                       int c1 = keyword.charAt(1) - 'a';
+                       if (c0 < 0 || c0 > 25 || c1 < 0 || c1 > 25)
+                               illegalArg("Invalid keyword '{0}' passed to 
KeywordStore.", keyword);
+                       if (this.store[c0] == null)
+                               this.store[c0] = new char[26][][];
+                       char[][][] x1 = this.store[c0];
+                       char[][] x2;
+                       if (x1[c1] == null)
+                               x2 = new char[1][];
+                       else {
+                               x2 = new char[x1[c1].length+1][];
+                               System.arraycopy(x1[c1], 0, x2, 0, 
x1[c1].length);
+                       }
+                       x2[x2.length-1] = keyword.toCharArray();
+                       x1[c1] = x2;
+               }
+       }
+
+       /**
+        * Returns <jk>true</jk> if the specified string exists in this store.
+        *
+        * @param s The string to check.
+        * @return <jk>true</jk> if the specified string exists in this store.
+        */
+       public boolean contains(String s) {
+               if (s == null || s.length() < 2)
+                       return false;
+               int c0 = s.charAt(0) - 'a', c1 = s.charAt(1) - 'a';
+               if (c0 < 0 || c0 > 25 || c1 < 0 || c1 > 25)
+                       return false;
+               char[][][] x1 = store[c0];
+               if (x1 == null)
+                       return false;
+               char[][] x2 = x1[c1];
+               if (x2 == null)
+                       return false;
+               for (int i = 0; i < x2.length; i++) {
+                       char[] keyword = x2[i];
+                       if (keyword.length == s.length()) {
+                               for (int j = 0; j < keyword.length; j++)
+                                       if (keyword[j] != s.charAt(j))
+                                               return false;
+                               return true;
+                       }
+               }
+               return false;
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/MultiIterable.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/MultiIterable.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/MultiIterable.java
new file mode 100644
index 0000000..19f5078
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/MultiIterable.java
@@ -0,0 +1,78 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import static org.apache.juneau.internal.ThrowableUtils.*;
+
+import java.util.*;
+
+/**
+ * Utility class for defining an iterator over one or more iterables.
+ * @param <E> The element class type.
+ */
+public class MultiIterable<E> implements Iterable<E> {
+
+       final List<Iterator<E>> iterators = new LinkedList<Iterator<E>>();
+
+       /**
+        * Constructor.
+        *
+        * @param iterators The list of iterators to iterate over.
+        */
+       public MultiIterable(Iterator<E>...iterators) {
+               for (Iterator<E> i : iterators)
+                       append(i);
+       }
+
+       /**
+        * Appends the specified iterator to this list of iterators.
+        *
+        * @param iterator The iterator to append.
+        * @return This object (for method chaining).
+        */
+       public MultiIterable<E> append(Iterator<E> iterator) {
+               assertFieldNotNull(iterator, "iterator");
+               this.iterators.add(iterator);
+               return this;
+       }
+
+       @Override /* Iterable */
+       public Iterator<E> iterator() {
+               return new Iterator<E>() {
+                       Iterator<Iterator<E>> i1 = iterators.iterator();
+                       Iterator<E> i2 = i1.hasNext() ? i1.next() : null;
+
+                       @Override /* Iterator */
+                       public boolean hasNext() {
+                               while (i2 != null && ! i2.hasNext())
+                                       i2 = (i1.hasNext() ? i1.next() : null);
+                               return (i2 != null);
+                       }
+
+                       @Override /* Iterator */
+                       public E next() {
+                               hasNext();
+                               if (i2 == null)
+                                       throw new NoSuchElementException();
+                               return i2.next();
+                       }
+
+                       @Override /* Iterator */
+                       public void remove() {
+                               if (i2 == null)
+                                       throw new NoSuchElementException();
+                               i2.remove();
+                       }
+               };
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/MultiSet.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/MultiSet.java 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/MultiSet.java
new file mode 100644
index 0000000..49b84f0
--- /dev/null
+++ b/org.apache.juneau/src/main/java/org/apache/juneau/internal/MultiSet.java
@@ -0,0 +1,111 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import static org.apache.juneau.internal.ThrowableUtils.*;
+
+import java.util.*;
+
+/**
+ * Encapsulates multiple collections so they can be iterated over as if they
+ * were all part of the same collection.
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ * @param <E> The object type of this set.
+ */
+public class MultiSet<E> extends AbstractSet<E> {
+
+       /** Inner collections. */
+       private List<Collection<E>> l = new ArrayList<Collection<E>>();
+
+       /**
+        * Create a new Set that consists as a coalesced set of the specified 
collections.
+        *
+        * @param c Zero or more collections to add to this set.
+        */
+       public MultiSet(Collection<E>...c) {
+               for (Collection<E> cc : c)
+                       append(cc);
+       }
+
+       /**
+        * Appends the specified collection to this set of collections.
+        *
+        * @param c The collection to append to this set of collections.
+        * @return This object (for method chaining).
+        */
+       public MultiSet<E> append(Collection<E> c) {
+               assertFieldNotNull(c, "c");
+               l.add(c);
+               return this;
+       }
+
+       /**
+        * Iterates over all entries in all collections.
+        */
+       @Override /* Set */
+       public Iterator<E> iterator() {
+               return new Iterator<E>() {
+                       int i = 0;
+                       Iterator<E> i2 = (l.size() > 0 ? l.get(i++).iterator() 
: null);
+
+                       @Override /* Iterator */
+                       public boolean hasNext() {
+                               if (i2 == null)
+                                       return false;
+                               if (i2.hasNext())
+                                       return true;
+                               for (int j = i; j < l.size(); j++)
+                                       if (l.get(j).size() > 0)
+                                               return true;
+                               return false;
+                       }
+
+                       @Override /* Iterator */
+                       public E next() {
+                               if (i2 == null)
+                                       throw new NoSuchElementException();
+                               while (! i2.hasNext()) {
+                                       if (i >= l.size())
+                                               throw new 
NoSuchElementException();
+                                       i2 = l.get(i++).iterator();
+                               }
+                               return i2.next();
+                       }
+
+                       @Override /* Iterator */
+                       public void remove() {
+                               if (i2 == null)
+                                       throw new NoSuchElementException();
+                               i2.remove();
+                       }
+               };
+       }
+
+       /**
+        * Enumerates over all entries in all collections.
+        *
+        * @return An enumeration wrapper around this set.
+        */
+       public Enumeration<E> enumerator() {
+               return Collections.enumeration(this);
+       }
+
+       @Override /* Set */
+       public int size() {
+               int i = 0;
+               for (Collection<E> c : l)
+                       i += c.size();
+               return i;
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/1b4f98a0/org.apache.juneau/src/main/java/org/apache/juneau/internal/ReflectionUtils.java
----------------------------------------------------------------------
diff --git 
a/org.apache.juneau/src/main/java/org/apache/juneau/internal/ReflectionUtils.java
 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/ReflectionUtils.java
new file mode 100644
index 0000000..0936d91
--- /dev/null
+++ 
b/org.apache.juneau/src/main/java/org/apache/juneau/internal/ReflectionUtils.java
@@ -0,0 +1,163 @@
+/***************************************************************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file
+ * to you 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 org.apache.juneau.internal;
+
+import static org.apache.juneau.internal.CollectionUtils.*;
+
+import java.io.*;
+import java.lang.annotation.*;
+import java.util.*;
+
+/**
+ * Reflection utilities.
+ *
+ * @author James Bognar (james.bog...@salesforce.com)
+ */
+public final class ReflectionUtils {
+
+       /**
+        * Similar to {@link Class#getAnnotation(Class)} except also searches 
annotations on interfaces.
+        *
+        * @param <T> The annotation class type.
+        * @param a The annotation class.
+        * @param c The annotated class.
+        * @return The annotation, or <jk>null</jk> if not found.
+        */
+       public static <T extends Annotation> T getAnnotation(Class<T> a, 
Class<?> c) {
+               if (c == null)
+                       return null;
+
+               T t = getDeclaredAnnotation(a, c);
+               if (t != null)
+                       return t;
+
+               t = getAnnotation(a, c.getSuperclass());
+               if (t != null)
+                       return t;
+
+               for (Class<?> c2 : c.getInterfaces()) {
+                       t = getAnnotation(a, c2);
+                       if (t != null)
+                               return t;
+               }
+               return null;
+       }
+
+       /**
+        * Returns the specified annotation only if it's been declared on the 
specified class.
+        * <p>
+        *      More efficient than calling {@link Class#getAnnotation(Class)} 
since it doesn't
+        *      recursively look for the class up the parent chain.
+        *
+        * @param <T> The annotation class type.
+        * @param a The annotation class.
+        * @param c The annotated class.
+        * @return The annotation, or <jk>null</jk> if not found.
+        */
+       @SuppressWarnings("unchecked")
+       public static <T extends Annotation> T getDeclaredAnnotation(Class<T> 
a, Class<?> c) {
+               for (Annotation a2 : c.getDeclaredAnnotations())
+                       if (a2.annotationType() == a)
+                               return (T)a2;
+               return null;
+       }
+
+       /**
+        * Returns all instances of the specified annotation on the specified 
class.
+        * <p>
+        * Searches all superclasses and superinterfaces.
+        * <p>
+        * Results are ordered child-to-parent.
+        *
+        * @param <T> The annotation class type.
+        * @param a The annotation class type.
+        * @param c The class being searched.
+        * @return The found matches, or an empty array if annotation was not 
found.
+        */
+       public static <T extends Annotation> List<T> findAnnotations(Class<T> 
a, Class<?> c) {
+               List<T> l = new LinkedList<T>();
+               appendAnnotations(a, c, l);
+               return l;
+       }
+
+       /**
+        * Sames as {@link #findAnnotations(Class, Class)} except returns the 
annotations as a map
+        * with the keys being the class on which the annotation was found.
+        * <p>
+        * Results are ordered child-to-parent.
+        *
+        * @param <T> The annotation class type.
+        * @param a The annotation class type.
+        * @param c The class being searched.
+        * @return The found matches, or an empty array if annotation was not 
found.
+        */
+       public static <T extends Annotation> LinkedHashMap<Class<?>,T> 
findAnnotationsMap(Class<T> a, Class<?> c) {
+               LinkedHashMap<Class<?>,T> m = new LinkedHashMap<Class<?>,T>();
+               findAnnotationsMap(a, c, m);
+               return m;
+       }
+
+       private static <T extends Annotation> void findAnnotationsMap(Class<T> 
a, Class<?> c, Map<Class<?>,T> m) {
+               if (c == null)
+                       return;
+
+               T t = getDeclaredAnnotation(a, c);
+               if (t != null)
+                       m.put(c, t);
+
+               findAnnotationsMap(a, c.getSuperclass(), m);
+
+               for (Class<?> c2 : c.getInterfaces())
+                       findAnnotationsMap(a, c2, m);
+       }
+
+       /**
+        * Finds and appends the specified annotation on the specified class 
and superclasses/interfaces to the specified list.
+        *
+        * @param a The annotation.
+        * @param c The class.
+        * @param l The list of annotations.
+        */
+       public static <T extends Annotation> void appendAnnotations(Class<T> a, 
Class<?> c, List<T> l) {
+               if (c == null)
+                       return;
+
+               addIfNotNull(l, getDeclaredAnnotation(a, c));
+
+               if (c.getPackage() != null)
+                       addIfNotNull(l, c.getPackage().getAnnotation(a));
+
+               appendAnnotations(a, c.getSuperclass(), l);
+
+               for (Class<?> c2 : c.getInterfaces())
+                       appendAnnotations(a, c2, l);
+       }
+
+       /**
+        * Similar to {@link Class#getResourceAsStream(String)} except looks up 
the
+        * parent hierarchy for the existence of the specified resource.
+        *
+        * @param c The class to return the resource on.
+        * @param name The resource name.
+        * @return An input stream on the specified resource, or <jk>null</jk> 
if the resource could not be found.
+        */
+       public static InputStream getResource(Class<?> c, String name) {
+               while (c != null) {
+                       InputStream is = c.getResourceAsStream(name);
+                       if (is != null)
+                               return is;
+                       c = c.getSuperclass();
+               }
+               return null;
+       }
+}

Reply via email to