usergrid-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From snoopd...@apache.org
Subject [28/90] [partial] Change package namespace to org.apache.usergrid
Date Wed, 05 Feb 2014 21:28:22 GMT
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/ConversionUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/ConversionUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/ConversionUtils.java
new file mode 100644
index 0000000..567a713
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/ConversionUtils.java
@@ -0,0 +1,765 @@
+/*
+ * 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.usergrid.utils;
+
+
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.commons.lang.math.NumberUtils;
+
+
+/** Convenience methods for converting to and from formats, primarily between byte arrays and UUIDs, Strings,
+ * and Longs. */
+public class ConversionUtils {
+
+    private static final Logger logger = LoggerFactory.getLogger( ConversionUtils.class );
+
+    /**
+     *
+     */
+    public static final String UTF8_ENCODING = "UTF-8";
+
+    /**
+     *
+     */
+    public static final String ASCII_ENCODING = "US-ASCII";
+
+    public static final ByteBuffer HOLDER = ByteBuffer.wrap( new byte[] { 0 } );
+
+
+    /**
+     * @param uuid
+     * @return
+     */
+    public static UUID uuid( byte[] uuid ) {
+        return uuid( uuid, 0 );
+    }
+
+
+    /**
+     * @param uuid
+     * @param offset
+     * @return
+     */
+    public static UUID uuid( byte[] uuid, int offset ) {
+        ByteBuffer bb = ByteBuffer.wrap( uuid, offset, 16 );
+        return new UUID( bb.getLong(), bb.getLong() );
+    }
+
+
+    public static UUID uuid( ByteBuffer bb ) {
+        if ( bb == null ) {
+            return null;
+        }
+        if ( bb.remaining() < 16 ) {
+            return null;
+        }
+        bb = bb.slice();
+        return new UUID( bb.getLong(), bb.getLong() );
+    }
+
+
+    /**
+     * @param uuid
+     * @return
+     */
+    public static UUID uuid( String uuid ) {
+        try {
+            return UUID.fromString( uuid );
+        }
+        catch ( Exception e ) {
+            logger.error( "Bad UUID", e );
+        }
+        return UUIDUtils.ZERO_UUID;
+    }
+
+
+    /**
+     * @param obj
+     * @return
+     */
+    public static UUID uuid( Object obj ) {
+        return uuid( obj, UUIDUtils.ZERO_UUID );
+    }
+
+
+    public static UUID uuid( Object obj, UUID defaultValue ) {
+        if ( obj instanceof UUID ) {
+            return ( UUID ) obj;
+        }
+        else if ( obj instanceof byte[] ) {
+            return uuid( ( byte[] ) obj );
+        }
+        else if ( obj instanceof ByteBuffer ) {
+            return uuid( ( ByteBuffer ) obj );
+        }
+        else if ( obj instanceof String ) {
+            return uuid( ( String ) obj );
+        }
+        return defaultValue;
+    }
+
+
+    /**
+     * @param uuid
+     * @return
+     */
+    public static byte[] bytes( UUID uuid ) {
+        if ( uuid == null ) {
+            return null;
+        }
+        long msb = uuid.getMostSignificantBits();
+        long lsb = uuid.getLeastSignificantBits();
+        byte[] buffer = new byte[16];
+
+        for ( int i = 0; i < 8; i++ ) {
+            buffer[i] = ( byte ) ( msb >>> ( 8 * ( 7 - i ) ) );
+        }
+        for ( int i = 8; i < 16; i++ ) {
+            buffer[i] = ( byte ) ( lsb >>> ( 8 * ( 7 - i ) ) );
+        }
+
+        return buffer;
+    }
+
+
+    public static ByteBuffer bytebuffer( UUID uuid ) {
+        if ( uuid == null ) {
+            return null;
+        }
+        return ByteBuffer.wrap( bytes( uuid ) );
+    }
+
+
+    /**
+     * @param uuid
+     * @return
+     */
+    public static byte[] uuidToBytesNullOk( UUID uuid ) {
+        if ( uuid != null ) {
+            return bytes( uuid );
+        }
+        return new byte[16];
+    }
+
+
+    /**
+     * @param s
+     * @return
+     */
+    public static byte[] bytes( String s ) {
+        return bytes( s, UTF8_ENCODING );
+    }
+
+
+    public static ByteBuffer bytebuffer( String s ) {
+        return ByteBuffer.wrap( bytes( s ) );
+    }
+
+
+    /**
+     * @param s
+     * @return
+     */
+    public static byte[] ascii( String s ) {
+        if ( s == null ) {
+            return new byte[0];
+        }
+        return bytes( s, ASCII_ENCODING );
+    }
+
+
+    public ByteBuffer asciibuffer( String s ) {
+        return ByteBuffer.wrap( ascii( s ) );
+    }
+
+
+    /**
+     * @param s
+     * @param encoding
+     * @return
+     */
+    public static byte[] bytes( String s, String encoding ) {
+        try {
+            return s.getBytes( encoding );
+        }
+        catch ( UnsupportedEncodingException e ) {
+            // logger.log(Level.SEVERE, "UnsupportedEncodingException ", e);
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    public static byte[] bytes( ByteBuffer bb ) {
+        byte[] b = new byte[bb.remaining()];
+        bb.duplicate().get( b );
+        return b;
+    }
+
+
+    public static ByteBuffer bytebuffer( String s, String encoding ) {
+        return ByteBuffer.wrap( bytes( s, encoding ) );
+    }
+
+
+    /**
+     * @param b
+     * @return
+     */
+    public static byte[] bytes( Boolean b ) {
+        byte[] bytes = new byte[1];
+        bytes[0] = b ? ( byte ) 1 : 0;
+        return bytes;
+    }
+
+
+    public static ByteBuffer bytebuffer( Boolean b ) {
+        return ByteBuffer.wrap( bytes( b ) );
+    }
+
+
+    /**
+     * @param val
+     * @return
+     */
+    public static byte[] bytes( Long val ) {
+        ByteBuffer buf = ByteBuffer.allocate( 8 );
+        buf.order( ByteOrder.BIG_ENDIAN );
+        buf.putLong( val );
+        return buf.array();
+    }
+
+
+    public static ByteBuffer bytebuffer( Long val ) {
+        ByteBuffer buf = ByteBuffer.allocate( 8 );
+        buf.order( ByteOrder.BIG_ENDIAN );
+        buf.putLong( val );
+        return ( ByteBuffer ) buf.rewind();
+    }
+
+
+    /**
+     * @param obj
+     * @return
+     */
+    public static byte[] bytes( Object obj ) {
+        if ( obj == null ) {
+            return new byte[0];
+        }
+        else if ( obj instanceof byte[] ) {
+            return ( byte[] ) obj;
+        }
+        else if ( obj instanceof Long ) {
+            return bytes( ( Long ) obj );
+        }
+        else if ( obj instanceof String ) {
+            return bytes( ( String ) obj );
+        }
+        else if ( obj instanceof UUID ) {
+            return bytes( ( UUID ) obj );
+        }
+        else if ( obj instanceof Boolean ) {
+            return bytes( ( Boolean ) obj );
+        }
+        else if ( obj instanceof Date ) {
+            return bytes( ( ( Date ) obj ).getTime() );
+        }
+        else {
+            return bytes( obj.toString() );
+        }
+    }
+
+
+    public static ByteBuffer bytebuffer( byte[] bytes ) {
+        return ByteBuffer.wrap( bytes );
+    }
+
+
+    public static ByteBuffer bytebuffer( ByteBuffer bytes ) {
+        return bytes.duplicate();
+    }
+
+
+    public static ByteBuffer bytebuffer( Object obj ) {
+        if ( obj instanceof ByteBuffer ) {
+            return ( ( ByteBuffer ) obj ).duplicate();
+        }
+        return ByteBuffer.wrap( bytes( obj ) );
+    }
+
+
+    public static List<ByteBuffer> bytebuffers( List<?> l ) {
+        List<ByteBuffer> results = new ArrayList<ByteBuffer>( l.size() );
+        for ( Object o : l ) {
+            results.add( bytebuffer( o ) );
+        }
+        return results;
+    }
+
+
+    /**
+     * @param bytes
+     * @return
+     */
+    public static boolean getBoolean( byte[] bytes ) {
+        return bytes[0] != 0;
+    }
+
+
+    public static boolean getBoolean( ByteBuffer bytes ) {
+        return bytes.slice().get() != 0;
+    }
+
+
+    /**
+     * @param bytes
+     * @param offset
+     * @return
+     */
+    public static boolean getBoolean( byte[] bytes, int offset ) {
+        return bytes[offset] != 0;
+    }
+
+
+    public static boolean getBoolean( Object obj ) {
+        if ( obj instanceof Boolean ) {
+            return ( Boolean ) obj;
+        }
+        else if ( obj instanceof String ) {
+            return Boolean.parseBoolean( ( String ) obj );
+        }
+        else if ( obj instanceof Number ) {
+            return ( ( Number ) obj ).longValue() > 0;
+        }
+
+        return false;
+    }
+
+
+    /**
+     * @param obj
+     * @return
+     */
+    public static String string( Object obj ) {
+        if ( obj instanceof String ) {
+            return ( String ) obj;
+        }
+        else if ( obj instanceof byte[] ) {
+            return string( ( byte[] ) obj );
+        }
+        else if ( obj instanceof ByteBuffer ) {
+            return string( ( ByteBuffer ) obj );
+        }
+        else if ( obj != null ) {
+            return obj.toString();
+        }
+        return null;
+    }
+
+
+    /**
+     * @param bytes
+     * @return
+     */
+    public static String string( byte[] bytes ) {
+        if ( bytes == null ) {
+            return null;
+        }
+        return string( bytes, 0, bytes.length, UTF8_ENCODING );
+    }
+
+
+    public static String string( ByteBuffer bytes ) {
+        if ( bytes == null ) {
+            return null;
+        }
+        return string( bytes.array(), bytes.arrayOffset() + bytes.position(), bytes.remaining(), UTF8_ENCODING );
+    }
+
+
+    /**
+     * @param bytes
+     * @param offset
+     * @param length
+     * @return
+     */
+    public static String string( byte[] bytes, int offset, int length ) {
+        return string( bytes, offset, length, UTF8_ENCODING );
+    }
+
+
+    /**
+     * @param bytes
+     * @param offset
+     * @param length
+     * @param encoding
+     * @return
+     */
+    public static String string( byte[] bytes, int offset, int length, String encoding ) {
+
+        if ( length <= 0 ) {
+            return "";
+        }
+
+        if ( bytes == null ) {
+            return "";
+        }
+
+        try {
+            return new String( bytes, offset, length, encoding );
+        }
+        catch ( UnsupportedEncodingException e ) {
+            // logger.log(Level.SEVERE, "UnsupportedEncodingException ", e);
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    public static <T> List<String> strings( Collection<T> items ) {
+        List<String> strings = new ArrayList<String>();
+        for ( T item : items ) {
+            strings.add( string( item ) );
+        }
+        return strings;
+    }
+
+
+    /**
+     * @param bytes
+     * @param offset
+     * @return
+     */
+    public static String stringFromLong( byte[] bytes, int offset ) {
+        if ( bytes.length == 0 ) {
+            return "";
+        }
+        if ( ( bytes.length - offset ) < 8 ) {
+            throw new IllegalArgumentException( "A long is at least 8 bytes" );
+        }
+        return String.valueOf( ByteBuffer.wrap( bytes, offset, 8 ).getLong() );
+    }
+
+
+    /**
+     * @param bytes
+     * @return
+     */
+    public static long getLong( byte[] bytes ) {
+        return ByteBuffer.wrap( bytes, 0, 8 ).getLong();
+    }
+
+
+    public static long getLong( ByteBuffer bytes ) {
+        return bytes.slice().getLong();
+    }
+
+
+    public static long getLong( Object obj ) {
+        if ( obj instanceof Long ) {
+            return ( Long ) obj;
+        }
+        if ( obj instanceof Number ) {
+            return ( ( Number ) obj ).longValue();
+        }
+        if ( obj instanceof String ) {
+            return NumberUtils.toLong( ( String ) obj );
+        }
+        if ( obj instanceof Date ) {
+            return ( ( Date ) obj ).getTime();
+        }
+        if ( obj instanceof byte[] ) {
+            return getLong( ( byte[] ) obj );
+        }
+        if ( obj instanceof ByteBuffer ) {
+            return getLong( ( ByteBuffer ) obj );
+        }
+        return 0;
+    }
+
+
+    /**
+     * @param bytes
+     * @return
+     */
+    public static int getInt( byte[] bytes ) {
+        return ByteBuffer.wrap( bytes, 0, 4 ).getInt();
+    }
+
+
+    public static int getInt( ByteBuffer bytes ) {
+        return bytes.slice().getInt();
+    }
+
+
+    public static int getInt( Object obj ) {
+        if ( obj instanceof Integer ) {
+            return ( Integer ) obj;
+        }
+        if ( obj instanceof Number ) {
+            return ( ( Number ) obj ).intValue();
+        }
+        if ( obj instanceof String ) {
+            return NumberUtils.toInt( ( String ) obj );
+        }
+        if ( obj instanceof Date ) {
+            return ( int ) ( ( Date ) obj ).getTime();
+        }
+        if ( obj instanceof byte[] ) {
+            return getInt( ( byte[] ) obj );
+        }
+        if ( obj instanceof ByteBuffer ) {
+            return getInt( ( ByteBuffer ) obj );
+        }
+        return 0;
+    }
+
+
+    /**
+     * @param bytes
+     * @return
+     */
+    public static float getFloat( byte[] bytes ) {
+        return ByteBuffer.wrap( bytes, 0, 4 ).getFloat();
+    }
+
+
+    public static float getFloat( ByteBuffer bytes ) {
+        return bytes.slice().getFloat();
+    }
+
+
+    public static float getFloat( Object obj ) {
+        if ( obj instanceof Float ) {
+            return ( Float ) obj;
+        }
+        if ( obj instanceof Number ) {
+            return ( ( Number ) obj ).floatValue();
+        }
+        if ( obj instanceof String ) {
+            return NumberUtils.toFloat( ( String ) obj );
+        }
+        if ( obj instanceof Date ) {
+            return ( ( Date ) obj ).getTime();
+        }
+        if ( obj instanceof byte[] ) {
+            return getFloat( ( byte[] ) obj );
+        }
+        if ( obj instanceof ByteBuffer ) {
+            return getFloat( ( ByteBuffer ) obj );
+        }
+        return 0;
+    }
+
+
+    public static double getDouble( byte[] bytes ) {
+        return ByteBuffer.wrap( bytes, 0, 8 ).getDouble();
+    }
+
+
+    public static double getDouble( ByteBuffer bytes ) {
+        return bytes.slice().getDouble();
+    }
+
+
+    public static double getDouble( Object obj ) {
+        if ( obj instanceof Double ) {
+            return ( Double ) obj;
+        }
+        if ( obj instanceof Number ) {
+            return ( ( Number ) obj ).doubleValue();
+        }
+        if ( obj instanceof String ) {
+            return NumberUtils.toDouble( ( String ) obj );
+        }
+        if ( obj instanceof Date ) {
+            return ( ( Date ) obj ).getTime();
+        }
+        if ( obj instanceof byte[] ) {
+            return getDouble( ( byte[] ) obj );
+        }
+        if ( obj instanceof ByteBuffer ) {
+            return getDouble( ( ByteBuffer ) obj );
+        }
+        return 0;
+    }
+
+
+    /**
+     * @param type
+     * @param bytes
+     * @return
+     */
+    public static Object object( Class<?> type, byte[] bytes ) {
+
+        try {
+            if ( Long.class.isAssignableFrom( type ) ) {
+                return getLong( bytes );
+            }
+            else if ( UUID.class.isAssignableFrom( type ) ) {
+                return uuid( bytes );
+            }
+            else if ( String.class.isAssignableFrom( type ) ) {
+                return string( bytes );
+            }
+            else if ( Boolean.class.isAssignableFrom( type ) ) {
+                return getBoolean( bytes );
+            }
+            else if ( Integer.class.isAssignableFrom( type ) ) {
+                return getInt( bytes );
+            }
+            else if ( Double.class.isAssignableFrom( type ) ) {
+                return getDouble( bytes );
+            }
+            else if ( Float.class.isAssignableFrom( type ) ) {
+                return getFloat( bytes );
+            }
+            else if ( byte[].class.isAssignableFrom( type ) ) {
+                return bytes;
+            }
+        }
+        catch ( Exception e ) {
+            logger.error( "Unable to get object from bytes for type " + type.getName(), e );
+        }
+        return null;
+    }
+
+
+    public static Object object( Class<?> type, ByteBuffer bytes ) {
+
+        try {
+            if ( Long.class.isAssignableFrom( type ) ) {
+                return bytes.slice().getLong();
+            }
+            else if ( UUID.class.isAssignableFrom( type ) ) {
+                return uuid( bytes );
+            }
+            else if ( String.class.isAssignableFrom( type ) ) {
+                return string( bytes );
+            }
+            else if ( Boolean.class.isAssignableFrom( type ) ) {
+                return bytes.slice().get() != 0;
+            }
+            else if ( Integer.class.isAssignableFrom( type ) ) {
+                return bytes.slice().getInt();
+            }
+            else if ( Double.class.isAssignableFrom( type ) ) {
+                return bytes.slice().getDouble();
+            }
+            else if ( Float.class.isAssignableFrom( type ) ) {
+                return bytes.slice().getFloat();
+            }
+            else if ( ByteBuffer.class.isAssignableFrom( type ) ) {
+                return bytes.duplicate();
+            }
+            else if ( byte[].class.isAssignableFrom( type ) ) {
+                byte[] b = new byte[bytes.remaining()];
+                bytes.slice().get( b );
+                return b;
+            }
+        }
+        catch ( Exception e ) {
+            logger.error( "Unable to get object from bytes for type " + type.getName(), e );
+        }
+        return null;
+    }
+
+
+    /**
+     * @param bb
+     * @param bytes
+     * @param len
+     * @return
+     */
+    public static ByteBuffer appendToByteBuffer( ByteBuffer bb, byte[] bytes, int len ) {
+        if ( len > bytes.length ) {
+            int pos = bb.position();
+            bb.put( bytes );
+            bb.position( pos + len );
+        }
+        else {
+            bb.put( bytes, 0, len );
+        }
+        return bb;
+    }
+
+
+    public static Object coerce( Class<?> type, Object obj ) {
+
+        if ( obj == null ) {
+            return null;
+        }
+
+        if ( type == null ) {
+            return obj;
+        }
+
+        try {
+            if ( Long.class.isAssignableFrom( type ) ) {
+                return getLong( obj );
+            }
+            else if ( UUID.class.isAssignableFrom( type ) ) {
+                return uuid( obj );
+            }
+            else if ( String.class.isAssignableFrom( type ) ) {
+                return string( obj );
+            }
+            else if ( Boolean.class.isAssignableFrom( type ) ) {
+                return getBoolean( obj );
+            }
+            else if ( Integer.class.isAssignableFrom( type ) ) {
+                return getInt( obj );
+            }
+            else if ( Double.class.isAssignableFrom( type ) ) {
+                return getDouble( obj );
+            }
+            else if ( Float.class.isAssignableFrom( type ) ) {
+                return getFloat( obj );
+            }
+            else if ( byte[].class.isAssignableFrom( type ) ) {
+                return bytes( obj );
+            }
+            else if ( ByteBuffer.class.isAssignableFrom( type ) ) {
+                return bytebuffer( obj );
+            }
+        }
+        catch ( Exception e ) {
+            logger.error( "Unable to get object from bytes for type " + type.getName(), e );
+        }
+        return null;
+    }
+
+
+    public static Map<String, Object> coerceMap( Map<String, Class<?>> types, Map<String, Object> values ) {
+        for ( Map.Entry<String, Object> entry : values.entrySet() ) {
+            if ( types.containsKey( entry.getKey() ) ) {
+                values.put( entry.getKey(), coerce( types.get( entry.getKey() ), entry.getValue() ) );
+            }
+        }
+        return values;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/DateUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/DateUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/DateUtils.java
new file mode 100644
index 0000000..257722b
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/DateUtils.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+// Copyright 2010-2011 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+//
+// Portions copyright 2006-2009 James Murty. Please see LICENSE.txt
+// for applicable license terms and NOTICE.txt for applicable notices.
+//
+// Licensed under the Apache License, Version 2.0 (the "License").
+// You may not use this file except in compliance with the License.
+// A copy of the License is located at
+//  http://aws.amazon.com/apache2.0
+// or in the "license" file accompanying this file. This file 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.usergrid.utils;
+
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.SimpleTimeZone;
+
+
+/**
+ * Utilities for parsing and formatting dates.
+ * <p/>
+ * Note that this class doesn't use static methods because of the synchronization issues with SimpleDateFormat. This
+ * lets synchronization be done on a per-object level, instead of on a per-class level.
+ */
+public class DateUtils {
+
+    /** ISO 8601 parser */
+    protected final SimpleDateFormat iso8601DateParser = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" );
+
+    /** Alternate ISO 8601 parser without fractional seconds */
+    protected final SimpleDateFormat alternateIo8601DateParser = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'" );
+
+    /** RFC 822 parser */
+    protected final SimpleDateFormat rfc822DateParser =
+            new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss z", Locale.US );
+
+
+    /** Constructs a new DateUtils object, ready to parse/format dates. */
+    public DateUtils() {
+        iso8601DateParser.setTimeZone( new SimpleTimeZone( 0, "GMT" ) );
+        rfc822DateParser.setTimeZone( new SimpleTimeZone( 0, "GMT" ) );
+        alternateIo8601DateParser.setTimeZone( new SimpleTimeZone( 0, "GMT" ) );
+    }
+
+
+    public static DateUtils instance = new DateUtils();
+
+
+    /**
+     * Formats the specified date as an ISO 8601 string.
+     *
+     * @param date The date to format.
+     *
+     * @return The ISO 8601 string representing the specified date.
+     */
+    public String formatIso8601Date( Date date ) {
+        synchronized ( iso8601DateParser ) {
+            return iso8601DateParser.format( date );
+        }
+    }
+
+
+    public String iso8601DateNow() {
+        return formatIso8601Date( new Date() );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/HttpUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/HttpUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/HttpUtils.java
new file mode 100644
index 0000000..314def0
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/HttpUtils.java
@@ -0,0 +1,51 @@
+/*
+ * 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.usergrid.utils;
+
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URLEncodedUtils;
+
+
+public class HttpUtils {
+
+    public static Map<String, List<String>> parseQueryString( String queryString ) {
+        Map<String, List<String>> mapOfLists = new HashMap<String, List<String>>();
+        if ( ( queryString == null ) || ( queryString.length() == 0 ) ) {
+            return mapOfLists;
+        }
+        List<NameValuePair> list = URLEncodedUtils.parse( URI.create( "http://localhost/?" + queryString ), "UTF-8" );
+        for ( NameValuePair pair : list ) {
+            List<String> values = mapOfLists.get( pair.getName() );
+            if ( values == null ) {
+                values = new ArrayList<String>();
+                mapOfLists.put( pair.getName(), values );
+            }
+            if ( pair.getValue() != null ) {
+                values.add( pair.getValue() );
+            }
+        }
+
+        return mapOfLists;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/IndexUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/IndexUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/IndexUtils.java
new file mode 100644
index 0000000..ffc2ba7
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/IndexUtils.java
@@ -0,0 +1,218 @@
+/*
+ * 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.usergrid.utils;
+
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.analysis.tokenattributes.TermAttribute;
+import org.apache.lucene.util.Version;
+
+import static org.apache.usergrid.utils.ClassUtils.cast;
+import static org.apache.usergrid.utils.ClassUtils.isBasicType;
+import static org.apache.usergrid.utils.JsonUtils.quoteString;
+import static org.apache.usergrid.utils.JsonUtils.toJsonNode;
+
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.node.ArrayNode;
+import org.codehaus.jackson.node.ObjectNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class IndexUtils {
+
+    private static final Logger LOG = LoggerFactory.getLogger( IndexUtils.class );
+
+    static Analyzer analyzer = new StandardAnalyzer( Version.LUCENE_30 );
+
+
+    private static void buildKeyValueSet( Object node, Map<String, List<Object>> keyValues, String path,
+                                          boolean fulltextIndex, Object... history ) {
+
+        if ( node == null ) {
+            return;
+        }
+
+        if ( node instanceof Collection ) {
+            Object[] newHistory = Arrays.copyOf( history, history.length + 1 );
+            newHistory[history.length] = node;
+            @SuppressWarnings("unchecked") Collection<Object> c = ( Collection<Object> ) node;
+            for ( Object o : c ) {
+                buildKeyValueSet( o, keyValues, path, fulltextIndex, newHistory );
+            }
+        }
+        else if ( node instanceof Map ) {
+            Object[] newHistory = Arrays.copyOf( history, history.length + 1 );
+            newHistory[history.length] = node;
+            @SuppressWarnings("unchecked") Map<Object, Object> m = ( Map<Object, Object> ) node;
+            for ( Entry<Object, Object> e : m.entrySet() ) {
+                String newPath;
+                String key = e.getKey().toString();
+                key = quoteString( key );
+                if ( key.indexOf( '\\' ) == -1 ) {
+                    if ( path != null ) {
+                        newPath = path + "." + key;
+                    }
+                    else {
+                        newPath = "" + key;
+                    }
+                }
+                else {
+                    if ( path != null ) {
+                        newPath = path + "[\"" + key + "\"]";
+                    }
+                    else {
+                        newPath = "" + "[\"" + key + "\"]";
+                    }
+                }
+                buildKeyValueSet( e.getValue(), keyValues, newPath, fulltextIndex, newHistory );
+            }
+        }
+        else if ( node instanceof ArrayNode ) {
+            Object[] newHistory = Arrays.copyOf( history, history.length + 1 );
+            newHistory[history.length] = node;
+            ArrayNode c = ( ArrayNode ) node;
+            for ( JsonNode o : c ) {
+                buildKeyValueSet( o, keyValues, path, fulltextIndex, newHistory );
+            }
+        }
+        else if ( node instanceof ObjectNode ) {
+            Object[] newHistory = Arrays.copyOf( history, history.length + 1 );
+            newHistory[history.length] = node;
+            ObjectNode c = ( ObjectNode ) node;
+            Iterator<Entry<String, JsonNode>> i = c.getFields();
+            while ( i.hasNext() ) {
+                Entry<String, JsonNode> e = i.next();
+                String newPath;
+                String key = e.getKey();
+                key = quoteString( key );
+                if ( key.indexOf( '\\' ) == -1 ) {
+                    if ( path != null ) {
+                        newPath = path + "." + key;
+                    }
+                    else {
+                        newPath = "" + key;
+                    }
+                }
+                else {
+                    if ( path != null ) {
+                        newPath = path + "[\"" + key + "\"]";
+                    }
+                    else {
+                        newPath = "" + "[\"" + key + "\"]";
+                    }
+                }
+                buildKeyValueSet( e.getValue(), keyValues, newPath, fulltextIndex, newHistory );
+            }
+        }
+        else if ( !isBasicType( node.getClass() ) && ( !( node instanceof JsonNode ) ) ) {
+            buildKeyValueSet( toJsonNode( node ), keyValues, path, fulltextIndex, history );
+        }
+        else {
+
+            if ( node instanceof JsonNode ) {
+                if ( ( ( JsonNode ) node ).isTextual() ) {
+                    node = ( ( JsonNode ) node ).getTextValue();
+                    UUID uuid = UUIDUtils.tryGetUUID( ( String ) node );
+                    if ( uuid != null ) {
+                        node = uuid;
+                    }
+                }
+                else if ( ( ( JsonNode ) node ).isNumber() ) {
+                    node = ( ( JsonNode ) node ).getNumberValue();
+                }
+                else {
+                    return;
+                }
+            }
+
+            if ( path == null ) {
+                path = "";
+            }
+            List<Object> l = keyValues.get( path );
+            if ( l == null ) {
+                l = new ArrayList<Object>();
+                keyValues.put( path, l );
+            }
+
+            l.add( node );
+
+            if ( ( node instanceof String ) && fulltextIndex ) {
+                String keywordsPath = ( path.length() > 0 ) ? path + ".keywords" : "keywords";
+                List<Object> keywords = cast( keywords( ( String ) node ) );
+
+                if ( keywords.size() > 0 ) {
+                    keyValues.put( keywordsPath, keywords );
+                }
+            }
+        }
+    }
+
+
+    public static Map<String, List<Object>> getKeyValues( String path, Object obj, boolean fulltextIndex ) {
+        Map<String, List<Object>> keys = new LinkedHashMap<String, List<Object>>();
+        buildKeyValueSet( obj, keys, path, fulltextIndex );
+        return keys;
+    }
+
+
+    public static List<Map.Entry<String, Object>> getKeyValueList( String path, Object obj, boolean fulltextIndex ) {
+        Map<String, List<Object>> map = getKeyValues( path, obj, fulltextIndex );
+        List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>();
+        for ( Entry<String, List<Object>> entry : map.entrySet() ) {
+            for ( Object value : entry.getValue() ) {
+                list.add( new AbstractMap.SimpleEntry<String, Object>( entry.getKey(), value ) );
+            }
+        }
+        return list;
+    }
+
+
+    public static List<Entry<String, Object>> getKeyValueList( Object obj, boolean fulltextIndex ) {
+        return getKeyValueList( null, obj, fulltextIndex );
+    }
+
+
+    public static List<String> keywords( String source ) {
+        TokenStream ts = analyzer.tokenStream( "keywords", new StringReader( source ) );
+        List<String> keywords = new ArrayList<String>();
+        try {
+            while ( ts.incrementToken() ) {
+                keywords.add( ts.getAttribute( TermAttribute.class ).term() );
+            }
+        }
+        catch ( IOException e ) {
+            LOG.error( "Error getting keywords ", e );
+        }
+        return keywords;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/InflectionUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/InflectionUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/InflectionUtils.java
new file mode 100644
index 0000000..72b9207
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/InflectionUtils.java
@@ -0,0 +1,51 @@
+/*
+ * 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.usergrid.utils;
+
+
+public class InflectionUtils {
+
+    public static String pluralize( Object word ) {
+        return Inflector.INSTANCE.pluralize( word );
+    }
+
+
+    public static String singularize( Object word ) {
+        return Inflector.INSTANCE.singularize( word );
+    }
+
+
+    public static boolean isPlural( Object word ) {
+        return Inflector.INSTANCE.isPlural( word );
+    }
+
+
+    public static boolean isSingular( Object word ) {
+        return Inflector.INSTANCE.isSingular( word );
+    }
+
+
+    public static String underscore( String s ) {
+        return Inflector.INSTANCE.underscore( s );
+    }
+
+
+    public static String camelCase( String lowerCaseAndUnderscoredWord, boolean uppercaseFirstLetter,
+                                    char... delimiterChars ) {
+        return Inflector.INSTANCE.camelCase( lowerCaseAndUnderscoredWord, uppercaseFirstLetter, delimiterChars );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/Inflector.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/Inflector.java b/stack/core/src/main/java/org/apache/usergrid/utils/Inflector.java
new file mode 100644
index 0000000..e0bfb84
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/Inflector.java
@@ -0,0 +1,553 @@
+/*
+ * 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.
+ */
+
+// TODO - This Class needs to go - it's LGPL Source !!!
+// ModeShape (http://www.modeshape.org)
+// See the COPYRIGHT.txt file distributed with this work for information
+// regarding copyright ownership.  Some portions may be licensed
+// to Red Hat, Inc. under one or more contributor license agreements.
+// See the AUTHORS.txt file in the distribution for a full listing of
+// individual contributors.
+//
+// ModeShape is free software. Unless otherwise indicated, all code in ModeShape
+// is licensed to you under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation; either version 2.1 of
+// the License, or (at your option) any later version.
+//
+// ModeShape is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this software; if not, write to the Free
+// Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+// 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+//
+
+package org.apache.usergrid.utils;
+
+
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * Transforms words to singular, plural, humanized (human readable), underscore, camel case, or ordinal form. This is
+ * inspired by the <a href="http://api.rubyonrails.org/classes/Inflector.html">Inflector</a> class in <a
+ * href="http://www.rubyonrails.org">Ruby on Rails</a>, which is distributed under the <a
+ * href="http://wiki.rubyonrails.org/rails/pages/License">Rails license</a>.
+ */
+public class Inflector {
+
+    protected static final Inflector INSTANCE = new Inflector();
+
+
+    public static Inflector getInstance() {
+        return INSTANCE;
+    }
+
+
+    protected class Rule {
+
+        protected final String expression;
+        protected final Pattern expressionPattern;
+        protected final String replacement;
+
+
+        protected Rule( String expression, String replacement ) {
+            this.expression = expression;
+            this.replacement = replacement != null ? replacement : "";
+            expressionPattern = Pattern.compile( this.expression, Pattern.CASE_INSENSITIVE );
+        }
+
+
+        /**
+         * Apply the rule against the input string, returning the modified string or null if the rule didn't apply (and
+         * no modifications were made)
+         *
+         * @param input the input string
+         *
+         * @return the modified string if this rule applied, or null if the input was not modified by this rule
+         */
+        protected String apply( String input ) {
+            Matcher matcher = expressionPattern.matcher( input );
+            if ( !matcher.find() ) {
+                return null;
+            }
+            return matcher.replaceAll( replacement );
+        }
+
+
+        @Override
+        public int hashCode() {
+            return expression.hashCode();
+        }
+
+
+        @Override
+        public boolean equals( Object obj ) {
+            if ( obj == this ) {
+                return true;
+            }
+            if ( ( obj != null ) && ( obj.getClass() == this.getClass() ) ) {
+                final Rule that = ( Rule ) obj;
+                if ( expression.equalsIgnoreCase( that.expression ) ) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+
+        @Override
+        public String toString() {
+            return expression + ", " + replacement;
+        }
+    }
+
+
+    private final LinkedList<Rule> plurals = new LinkedList<Rule>();
+    private final LinkedList<Rule> singulars = new LinkedList<Rule>();
+    /**
+     * The lowercase words that are to be excluded and not processed. This map can be modified by the users via {@link
+     * #getUncountables()}.
+     */
+    private final Set<String> uncountables = new HashSet<String>();
+
+
+    public Inflector() {
+        initialize();
+    }
+
+
+    protected Inflector( Inflector original ) {
+        plurals.addAll( original.plurals );
+        singulars.addAll( original.singulars );
+        uncountables.addAll( original.uncountables );
+    }
+
+
+    @Override
+    @SuppressWarnings("all")
+    public Inflector clone() {
+        return new Inflector( this );
+    }
+
+    // ------------------------------------------------------------------------------------------------
+    // Usage functions
+    // ------------------------------------------------------------------------------------------------
+
+
+    /**
+     * Returns the plural form of the word in the string. <p> Examples: <p/>
+     * <pre>
+     *   inflector.pluralize(&quot;post&quot;)               #=&gt; &quot;posts&quot;
+     *   inflector.pluralize(&quot;octopus&quot;)            #=&gt; &quot;octopi&quot;
+     *   inflector.pluralize(&quot;sheep&quot;)              #=&gt; &quot;sheep&quot;
+     *   inflector.pluralize(&quot;words&quot;)              #=&gt; &quot;words&quot;
+     *   inflector.pluralize(&quot;the blue mailman&quot;)   #=&gt; &quot;the blue mailmen&quot;
+     *   inflector.pluralize(&quot;CamelOctopus&quot;)       #=&gt; &quot;CamelOctopi&quot;
+     * </pre>
+     * <p/> </p> <p> Note that if the {@link Object#toString()} is called on the supplied object, so this method works
+     * for non-strings, too. </p>
+     *
+     * @param word the word that is to be pluralized.
+     *
+     * @return the pluralized form of the word, or the word itself if it could not be pluralized
+     *
+     * @see #singularize(Object)
+     */
+    public String pluralize( Object word ) {
+        if ( word == null ) {
+            return null;
+        }
+        String wordStr = word.toString().trim();
+        if ( wordStr.length() == 0 ) {
+            return wordStr;
+        }
+        if ( isUncountable( wordStr ) ) {
+            return wordStr;
+        }
+        for ( Rule rule : plurals ) {
+            String result = rule.apply( wordStr );
+            if ( result != null ) {
+                return result;
+            }
+        }
+        return wordStr;
+    }
+
+
+    public String pluralize( Object word, int count ) {
+        if ( word == null ) {
+            return null;
+        }
+        if ( ( count == 1 ) || ( count == -1 ) ) {
+            return word.toString();
+        }
+        return pluralize( word );
+    }
+
+
+    public boolean isPlural( Object word ) {
+        if ( word == null ) {
+            return false;
+        }
+        return pluralize( word ).equals( word.toString() );
+    }
+
+
+    /**
+     * Returns the singular form of the word in the string. <p> Examples: <p/>
+     * <pre>
+     *   inflector.singularize(&quot;posts&quot;)             #=&gt; &quot;post&quot;
+     *   inflector.singularize(&quot;octopi&quot;)            #=&gt; &quot;octopus&quot;
+     *   inflector.singularize(&quot;sheep&quot;)             #=&gt; &quot;sheep&quot;
+     *   inflector.singularize(&quot;words&quot;)             #=&gt; &quot;word&quot;
+     *   inflector.singularize(&quot;the blue mailmen&quot;)  #=&gt; &quot;the blue mailman&quot;
+     *   inflector.singularize(&quot;CamelOctopi&quot;)       #=&gt; &quot;CamelOctopus&quot;
+     * </pre>
+     * <p/> </p> <p> Note that if the {@link Object#toString()} is called on the supplied object, so this method works
+     * for non-strings, too. </p>
+     *
+     * @param word the word that is to be pluralized.
+     *
+     * @return the pluralized form of the word, or the word itself if it could not be pluralized
+     *
+     * @see #pluralize(Object)
+     */
+    public String singularize( Object word ) {
+        if ( word == null ) {
+            return null;
+        }
+        String wordStr = word.toString().trim();
+        if ( wordStr.length() == 0 ) {
+            return wordStr;
+        }
+        if ( isUncountable( wordStr ) ) {
+            return wordStr;
+        }
+        for ( Rule rule : singulars ) {
+            String result = rule.apply( wordStr );
+            if ( result != null ) {
+                return result;
+            }
+        }
+        return wordStr;
+    }
+
+
+    public boolean isSingular( Object word ) {
+        if ( word == null ) {
+            return false;
+        }
+        return singularize( word ).equals( word.toString() );
+    }
+
+
+    /**
+     * By default, this method converts strings to UpperCamelCase. If the <code>uppercaseFirstLetter</code> argument to
+     * false, then this method produces lowerCamelCase. This method will also use any extra delimiter characters to
+     * identify word boundaries. <p> Examples: <p/>
+     * <pre>
+     *   inflector.camelCase(&quot;active_record&quot;,false)    #=&gt; &quot;activeRecord&quot;
+     *   inflector.camelCase(&quot;active_record&quot;,true)     #=&gt; &quot;ActiveRecord&quot;
+     *   inflector.camelCase(&quot;first_name&quot;,false)       #=&gt; &quot;firstName&quot;
+     *   inflector.camelCase(&quot;first_name&quot;,true)        #=&gt; &quot;FirstName&quot;
+     *   inflector.camelCase(&quot;name&quot;,false)             #=&gt; &quot;name&quot;
+     *   inflector.camelCase(&quot;name&quot;,true)              #=&gt; &quot;Name&quot;
+     * </pre>
+     * <p/> </p>
+     *
+     * @param lowerCaseAndUnderscoredWord the word that is to be converted to camel case
+     * @param uppercaseFirstLetter true if the first character is to be uppercased, or false if the first character is
+     * to be lowercased
+     * @param delimiterChars optional characters that are used to delimit word boundaries
+     *
+     * @return the camel case version of the word
+     *
+     * @see #underscore(String, char[])
+     */
+    public String camelCase( String lowerCaseAndUnderscoredWord, boolean uppercaseFirstLetter,
+                             char... delimiterChars ) {
+        if ( lowerCaseAndUnderscoredWord == null ) {
+            return null;
+        }
+        lowerCaseAndUnderscoredWord = lowerCaseAndUnderscoredWord.trim();
+        if ( lowerCaseAndUnderscoredWord.length() == 0 ) {
+            return "";
+        }
+        if ( uppercaseFirstLetter ) {
+            String result = lowerCaseAndUnderscoredWord;
+            // Replace any extra delimiters with underscores (before the
+            // underscores are converted in the next step)...
+            if ( delimiterChars != null ) {
+                for ( char delimiterChar : delimiterChars ) {
+                    result = result.replace( delimiterChar, '_' );
+                }
+            }
+
+            // Change the case at the beginning at after each underscore ...
+            return replaceAllWithUppercase( result, "(^|_)(.)", 2 );
+        }
+        if ( lowerCaseAndUnderscoredWord.length() < 2 ) {
+            return lowerCaseAndUnderscoredWord;
+        }
+        return "" + Character.toLowerCase( lowerCaseAndUnderscoredWord.charAt( 0 ) ) + camelCase(
+                lowerCaseAndUnderscoredWord, true, delimiterChars ).substring( 1 );
+    }
+
+
+    /**
+     * Makes an underscored form from the expression in the string (the reverse of the {@link #camelCase(String,
+     * boolean, char[]) camelCase} method. Also changes any characters that match the supplied delimiters into
+     * underscore. <p> Examples: <p/>
+     * <pre>
+     *   inflector.underscore(&quot;activeRecord&quot;)     #=&gt; &quot;active_record&quot;
+     *   inflector.underscore(&quot;ActiveRecord&quot;)     #=&gt; &quot;active_record&quot;
+     *   inflector.underscore(&quot;firstName&quot;)        #=&gt; &quot;first_name&quot;
+     *   inflector.underscore(&quot;FirstName&quot;)        #=&gt; &quot;first_name&quot;
+     *   inflector.underscore(&quot;name&quot;)             #=&gt; &quot;name&quot;
+     *   inflector.underscore(&quot;The.firstName&quot;)    #=&gt; &quot;the_first_name&quot;
+     * </pre>
+     * <p/> </p>
+     *
+     * @param camelCaseWord the camel-cased word that is to be converted;
+     * @param delimiterChars optional characters that are used to delimit word boundaries (beyond capitalization)
+     *
+     * @return a lower-cased version of the input, with separate words delimited by the underscore character.
+     */
+    public String underscore( String camelCaseWord, char... delimiterChars ) {
+        if ( camelCaseWord == null ) {
+            return null;
+        }
+        String result = camelCaseWord.trim();
+        if ( result.length() == 0 ) {
+            return "";
+        }
+        result = result.replaceAll( "([A-Z]+)([A-Z][a-z])", "$1_$2" );
+        result = result.replaceAll( "([a-z\\d])([A-Z])", "$1_$2" );
+        result = result.replace( '-', '_' );
+        if ( delimiterChars != null ) {
+            for ( char delimiterChar : delimiterChars ) {
+                result = result.replace( delimiterChar, '_' );
+            }
+        }
+        return result.toLowerCase();
+    }
+
+
+    /**
+     * Returns a copy of the input with the first character converted to uppercase and the remainder to lowercase.
+     *
+     * @param words the word to be capitalized
+     *
+     * @return the string with the first character capitalized and the remaining characters lowercased
+     */
+    public String capitalize( String words ) {
+        if ( words == null ) {
+            return null;
+        }
+        String result = words.trim();
+        if ( result.length() == 0 ) {
+            return "";
+        }
+        if ( result.length() == 1 ) {
+            return result.toUpperCase();
+        }
+        return "" + Character.toUpperCase( result.charAt( 0 ) ) + result.substring( 1 ).toLowerCase();
+    }
+
+
+    // ------------------------------------------------------------------------------------------------
+    // Management methods
+    // ------------------------------------------------------------------------------------------------
+
+
+    /**
+     * Determine whether the supplied word is considered uncountable by the {@link #pluralize(Object) pluralize} and
+     * {@link #singularize(Object) singularize} methods.
+     *
+     * @param word the word
+     *
+     * @return true if the plural and singular forms of the word are the same
+     */
+    public boolean isUncountable( String word ) {
+        if ( word == null ) {
+            return false;
+        }
+        String trimmedLower = word.trim().toLowerCase();
+        return uncountables.contains( trimmedLower );
+    }
+
+
+    /**
+     * Get the set of words that are not processed by the Inflector. The resulting map is directly modifiable.
+     *
+     * @return the set of uncountable words
+     */
+    public Set<String> getUncountables() {
+        return uncountables;
+    }
+
+
+    public void addPluralize( String rule, String replacement ) {
+        final Rule pluralizeRule = new Rule( rule, replacement );
+        plurals.addFirst( pluralizeRule );
+    }
+
+
+    public void addSingularize( String rule, String replacement ) {
+        final Rule singularizeRule = new Rule( rule, replacement );
+        singulars.addFirst( singularizeRule );
+    }
+
+
+    public void addIrregular( String singular, String plural ) {
+        if ( org.apache.commons.lang.StringUtils.isEmpty( singular ) ) {
+            throw new IllegalArgumentException( "singular rule may not be empty" );
+        }
+        if ( org.apache.commons.lang.StringUtils.isEmpty( plural ) ) {
+            throw new IllegalArgumentException( "plural rule may not be empty" );
+        }
+        String singularRemainder = singular.length() > 1 ? singular.substring( 1 ) : "";
+        String pluralRemainder = plural.length() > 1 ? plural.substring( 1 ) : "";
+        addPluralize( "(" + singular.charAt( 0 ) + ")" + singularRemainder + "$", "$1" + pluralRemainder );
+        addSingularize( "(" + plural.charAt( 0 ) + ")" + pluralRemainder + "$", "$1" + singularRemainder );
+    }
+
+
+    public void addUncountable( String... words ) {
+        if ( ( words == null ) || ( words.length == 0 ) ) {
+            return;
+        }
+        for ( String word : words ) {
+            if ( word != null ) {
+                uncountables.add( word.trim().toLowerCase() );
+            }
+        }
+    }
+
+
+    /**
+     * Utility method to replace all occurrences given by the specific backreference with its uppercased form, and
+     * remove all other backreferences. <p> The Java {@link Pattern regular expression processing} does not use the
+     * preprocessing directives <code>\l</code>, <code>&#92;u</code>, <code>\L</code>, and <code>\U</code>. If so, such
+     * directives could be used in the replacement string to uppercase or lowercase the backreferences. For example,
+     * <code>\L1</code> would lowercase the first backreference, and <code>&#92;u3</code> would uppercase the 3rd
+     * backreference. </p>
+     *
+     * @return the input string with the appropriate characters converted to upper-case
+     */
+    protected static String replaceAllWithUppercase( String input, String regex, int groupNumberToUppercase ) {
+        Pattern underscoreAndDotPattern = Pattern.compile( regex );
+        Matcher matcher = underscoreAndDotPattern.matcher( input );
+        StringBuffer sb = new StringBuffer();
+        while ( matcher.find() ) {
+            matcher.appendReplacement( sb, matcher.group( groupNumberToUppercase ).toUpperCase() );
+        }
+        matcher.appendTail( sb );
+        return sb.toString();
+    }
+
+
+    /** Completely remove all rules within this inflector. */
+    public void clear() {
+        uncountables.clear();
+        plurals.clear();
+        singulars.clear();
+    }
+
+
+    protected void initialize() {
+        Inflector inflect = this;
+        inflect.addPluralize( "$", "s" );
+        inflect.addPluralize( "s$", "s" );
+        inflect.addPluralize( "(ax|test)is$", "$1es" );
+        inflect.addPluralize( "(octop|vir)us$", "$1i" );
+        inflect.addPluralize( "(octop|vir)i$", "$1i" ); // already plural
+        inflect.addPluralize( "(alias|status)$", "$1es" );
+        inflect.addPluralize( "(bu)s$", "$1ses" );
+        inflect.addPluralize( "(buffal|tomat)o$", "$1oes" );
+        inflect.addPluralize( "([ti])um$", "$1a" );
+        inflect.addPluralize( "([ti])a$", "$1a" ); // already plural
+        inflect.addPluralize( "sis$", "ses" );
+        inflect.addPluralize( "(?:([^f])fe|([lr])f)$", "$1$2ves" );
+        inflect.addPluralize( "(hive)$", "$1s" );
+        inflect.addPluralize( "([^aeiouy]|qu)y$", "$1ies" );
+        inflect.addPluralize( "(x|ch|ss|sh)$", "$1es" );
+        inflect.addPluralize( "(matr|vert|ind)ix|ex$", "$1ices" );
+        inflect.addPluralize( "([m|l])ouse$", "$1ice" );
+        inflect.addPluralize( "([m|l])ice$", "$1ice" );
+        inflect.addPluralize( "^(ox)$", "$1en" );
+        inflect.addPluralize( "(quiz)$", "$1zes" );
+        // Need to check for the following words that are already pluralized:
+        inflect.addPluralize( "(people|men|children|sexes|moves|stadiums)$", "$1" ); // irregulars
+        inflect.addPluralize( "(oxen|octopi|viri|aliases|quizzes)$", "$1" ); // special
+        // rules
+
+        inflect.addSingularize( "s$", "" );
+        inflect.addSingularize( "(s|si|u)s$", "$1s" ); // '-us' and '-ss' are
+        // already singular
+        inflect.addSingularize( "(n)ews$", "$1ews" );
+        inflect.addSingularize( "([ti])a$", "$1um" );
+        inflect.addSingularize( "((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis" );
+        inflect.addSingularize( "(^analy)ses$", "$1sis" );
+        inflect.addSingularize( "(^analy)sis$", "$1sis" ); // already singular,
+        // but ends in 's'
+        inflect.addSingularize( "([^f])ves$", "$1fe" );
+        inflect.addSingularize( "(hive)s$", "$1" );
+        inflect.addSingularize( "(tive)s$", "$1" );
+        inflect.addSingularize( "([lr])ves$", "$1f" );
+        inflect.addSingularize( "([^aeiouy]|qu)ies$", "$1y" );
+        inflect.addSingularize( "(s)eries$", "$1eries" );
+        inflect.addSingularize( "(m)ovies$", "$1ovie" );
+        inflect.addSingularize( "(x|ch|ss|sh)es$", "$1" );
+        inflect.addSingularize( "([m|l])ice$", "$1ouse" );
+        inflect.addSingularize( "(bus)es$", "$1" );
+        inflect.addSingularize( "(o)es$", "$1" );
+        inflect.addSingularize( "(shoe)s$", "$1" );
+        inflect.addSingularize( "(cris|ax|test)is$", "$1is" ); // already
+        // singular, but
+        // ends in 's'
+        inflect.addSingularize( "(cris|ax|test)es$", "$1is" );
+        inflect.addSingularize( "(octop|vir)i$", "$1us" );
+        inflect.addSingularize( "(octop|vir)us$", "$1us" ); // already singular,
+        // but ends in 's'
+        inflect.addSingularize( "(alias|status)es$", "$1" );
+        inflect.addSingularize( "(alias|status)$", "$1" ); // already singular,
+        // but ends in 's'
+        inflect.addSingularize( "^(ox)en", "$1" );
+        inflect.addSingularize( "(vert|ind)ices$", "$1ex" );
+        inflect.addSingularize( "(matr)ices$", "$1ix" );
+        inflect.addSingularize( "(quiz)zes$", "$1" );
+
+        inflect.addIrregular( "person", "people" );
+        inflect.addIrregular( "man", "men" );
+        inflect.addIrregular( "child", "children" );
+        inflect.addIrregular( "sex", "sexes" );
+        inflect.addIrregular( "move", "moves" );
+        inflect.addIrregular( "stadium", "stadiums" );
+
+        inflect.addUncountable( "equipment", "information", "rice", "money", "species", "series", "fish", "sheep",
+                "data", "analytics" );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/JsonUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/JsonUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/JsonUtils.java
new file mode 100644
index 0000000..6643ce7
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/JsonUtils.java
@@ -0,0 +1,327 @@
+/*
+ * 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.usergrid.utils;
+
+
+import java.io.File;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.usergrid.exception.JsonReadException;
+import org.apache.usergrid.exception.JsonWriteException;
+import org.apache.usergrid.persistence.Entity;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.io.JsonStringEncoder;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig.Feature;
+import org.codehaus.jackson.smile.SmileFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.commons.lang.StringUtils.substringAfter;
+import static org.apache.usergrid.utils.StringUtils.stringOrSubstringBeforeFirst;
+
+
+public class JsonUtils {
+
+    private static final Logger LOG = LoggerFactory.getLogger( JsonUtils.class );
+
+    static ObjectMapper mapper = new ObjectMapper();
+
+    static SmileFactory smile = new SmileFactory();
+
+    static ObjectMapper smileMapper = new ObjectMapper( smile );
+
+    private static ObjectMapper indentObjectMapper = new ObjectMapper();
+
+
+    static {
+        indentObjectMapper.getSerializationConfig().set( Feature.INDENT_OUTPUT, true );
+    }
+
+
+    /** Converts object to JSON string, throws runtime exception JsonWriteException on failure. */
+    public static String mapToJsonString( Object obj ) {
+        try {
+            return mapper.writeValueAsString( obj );
+        }
+        catch ( Throwable t ) {
+            LOG.debug( "Error generating JSON", t );
+            throw new JsonWriteException( "Error generating JSON", t );
+        }
+    }
+
+
+    /** Converts object to JSON string, throws runtime exception JsonWriteException on failure. */
+    public static String mapToFormattedJsonString( Object obj ) {
+        try {
+            return indentObjectMapper.writeValueAsString( obj );
+        }
+        catch ( Throwable t ) {
+            LOG.debug( "Error generating JSON", t );
+            throw new JsonWriteException( "Error generating JSON", t );
+        }
+    }
+
+
+    /** Parses JSON string  and returns object, throws runtime exception JsonReadException on failure. */
+    public static Object parse( String json ) {
+        try {
+            return mapper.readValue( json, Object.class );
+        }
+        catch ( Throwable t ) {
+            LOG.debug( "Error parsing JSON", t );
+            throw new JsonReadException( "Error parsing JSON", t );
+        }
+    }
+
+
+    public static String quoteString( String s ) {
+        JsonStringEncoder encoder = new JsonStringEncoder();
+        return new String( encoder.quoteAsUTF8( s ) );
+    }
+
+
+    public static ByteBuffer toByteBuffer( Object obj ) {
+        if ( obj == null ) {
+            return null;
+        }
+
+        byte[] bytes = null;
+        try {
+            bytes = smileMapper.writeValueAsBytes( obj );
+        }
+        catch ( Exception e ) {
+            LOG.error( "Error getting SMILE bytes", e );
+        }
+        if ( bytes != null ) {
+            return ByteBuffer.wrap( bytes );
+        }
+        return null;
+    }
+
+
+    public static Object fromByteBuffer( ByteBuffer byteBuffer ) {
+        return fromByteBuffer( byteBuffer, Object.class );
+    }
+
+
+    public static Object fromByteBuffer( ByteBuffer byteBuffer, Class<?> clazz ) {
+        if ( ( byteBuffer == null ) || !byteBuffer.hasRemaining() ) {
+            return null;
+        }
+        if ( clazz == null ) {
+            clazz = Object.class;
+        }
+
+        Object obj = null;
+        try {
+            obj = smileMapper.readValue( byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(),
+                    byteBuffer.remaining(), clazz );
+        }
+        catch ( Exception e ) {
+            LOG.error( "Error parsing SMILE bytes", e );
+        }
+        return obj;
+    }
+
+
+    public static JsonNode toJsonNode( Object obj ) {
+        if ( obj == null ) {
+            return null;
+        }
+        return mapper.convertValue( obj, JsonNode.class );
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static Map<String, Object> toJsonMap( Object obj ) {
+        if ( obj == null ) {
+            return null;
+        }
+
+        return ( Map<String, Object> ) mapper.convertValue( obj, Map.class );
+    }
+
+
+    private static UUID tryConvertToUUID( Object o ) {
+        if ( o instanceof String ) {
+            String s = ( String ) o;
+            if ( s.length() == 36 ) {
+                try {
+                    return UUID.fromString( s );
+                }
+                catch ( IllegalArgumentException e ) {
+                    LOG.warn( "Argument to UUID.fromString({}) was invalid.", s, e );
+                }
+            }
+        }
+        return null;
+    }
+
+
+    public static Object normalizeJsonTree( Object obj ) {
+        if ( obj instanceof Map ) {
+            @SuppressWarnings("unchecked") Map<Object, Object> m = ( Map<Object, Object> ) obj;
+            Object o;
+            UUID uuid;
+            for ( Object k : m.keySet() ) {
+                if ( k instanceof String && ( ( String ) k ).equalsIgnoreCase( "name" ) ) {
+                    continue;
+                }
+
+                o = m.get( k );
+                uuid = tryConvertToUUID( o );
+                if ( uuid != null ) {
+                    m.put( k, uuid );
+                }
+                else if ( o instanceof Integer ) {
+                    m.put( k, ( ( Integer ) o ).longValue() );
+                }
+                else if ( o instanceof BigInteger ) {
+                    m.put( k, ( ( BigInteger ) o ).longValue() );
+                }
+            }
+        }
+        else if ( obj instanceof List ) {
+            @SuppressWarnings("unchecked") List<Object> l = ( List<Object> ) obj;
+            Object o;
+            UUID uuid;
+            for ( int i = 0; i < l.size(); i++ ) {
+                o = l.get( i );
+                uuid = tryConvertToUUID( o );
+                if ( uuid != null ) {
+                    l.set( i, uuid );
+                }
+                else if ( ( o instanceof Map ) || ( o instanceof List ) ) {
+                    normalizeJsonTree( o );
+                }
+                else if ( o instanceof Integer ) {
+                    l.set( i, ( ( Integer ) o ).longValue() );
+                }
+                else if ( o instanceof BigInteger ) {
+                    l.set( i, ( ( BigInteger ) o ).longValue() );
+                }
+            }
+        }
+        else if ( obj instanceof String ) {
+            UUID uuid = tryConvertToUUID( obj );
+            if ( uuid != null ) {
+                return uuid;
+            }
+        }
+        else if ( obj instanceof Integer ) {
+            return ( ( Integer ) obj ).longValue();
+        }
+        else if ( obj instanceof BigInteger ) {
+            return ( ( BigInteger ) obj ).longValue();
+        }
+        else if ( obj instanceof JsonNode ) {
+            return mapper.convertValue( obj, Object.class );
+        }
+        return obj;
+    }
+
+
+    public static Object select( Object obj, String path ) {
+        return select( obj, path, false );
+    }
+
+
+    public static Object select( Object obj, String path, boolean buildResultTree ) {
+
+        if ( obj == null ) {
+            return null;
+        }
+
+        if ( org.apache.commons.lang.StringUtils.isBlank( path ) ) {
+            return obj;
+        }
+
+        String segment = stringOrSubstringBeforeFirst( path, '.' );
+        String remaining = substringAfter( path, "." );
+
+        if ( obj instanceof Map ) {
+            Map<?, ?> map = ( Map<?, ?> ) obj;
+            Object child = map.get( segment );
+            Object result = select( child, remaining, buildResultTree );
+            if ( result != null ) {
+                if ( buildResultTree ) {
+                    Map<Object, Object> results = new LinkedHashMap<Object, Object>();
+                    results.put( segment, result );
+                    return results;
+                }
+                else {
+                    return result;
+                }
+            }
+            return null;
+        }
+        if ( obj instanceof List ) {
+            List<Object> results = new ArrayList<Object>();
+            List<?> list = ( List<?> ) obj;
+            for ( Object i : list ) {
+                Object result = select( i, path, buildResultTree );
+                if ( result != null ) {
+                    results.add( result );
+                }
+            }
+            if ( !results.isEmpty() ) {
+                return results;
+            }
+            return null;
+        }
+
+        if ( obj instanceof Entity ) {
+            Object child = ( ( Entity ) obj ).getProperty( segment );
+            Object result = select( child, remaining, buildResultTree );
+            if ( result != null ) {
+                if ( buildResultTree ) {
+                    Map<Object, Object> results = new LinkedHashMap<Object, Object>();
+                    results.put( segment, result );
+                    return results;
+                }
+                else {
+                    return result;
+                }
+            }
+            else {
+                return result;
+            }
+        }
+
+        return obj;
+    }
+
+
+    public static Object loadFromFilesystem( String filename ) {
+        Object json = null;
+        try {
+            File file = new File( filename );
+            json = mapper.readValue( file, Object.class );
+        }
+        catch ( Exception e ) {
+            LOG.error( "Error loading JSON", e );
+        }
+        return json;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/ListUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/ListUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/ListUtils.java
new file mode 100644
index 0000000..6a88193
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/ListUtils.java
@@ -0,0 +1,230 @@
+/*
+ * 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.usergrid.utils;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.commons.lang.math.NumberUtils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class ListUtils extends org.apache.commons.collections.ListUtils {
+    private static final Logger LOG = LoggerFactory.getLogger( ListUtils.class );
+
+
+    public static <A> A first( List<A> list ) {
+        if ( list == null ) {
+            return null;
+        }
+        if ( list.size() == 0 ) {
+            return null;
+        }
+        return list.get( 0 );
+    }
+
+
+    public static <A> A last( List<A> list ) {
+        if ( list == null ) {
+            return null;
+        }
+        if ( list.size() == 0 ) {
+            return null;
+        }
+        return list.get( list.size() - 1 );
+    }
+
+
+    public static <A> Integer firstInteger( List<A> list ) {
+        A a = first( list );
+        if ( a == null ) {
+            return null;
+        }
+
+        if ( a instanceof Integer ) {
+            return ( Integer ) a;
+        }
+
+        try {
+            return NumberUtils.toInt( ( String ) a );
+        }
+        catch ( Exception e ) {
+            LOG.warn( "Could not convert list item {} to int", a, e );
+        }
+        return null;
+    }
+
+
+    public static <A> Long firstLong( List<A> list ) {
+        A a = first( list );
+        if ( a == null ) {
+            return null;
+        }
+
+        if ( a instanceof Long ) {
+            return ( Long ) a;
+        }
+
+        try {
+            return NumberUtils.toLong( ( String ) a );
+        }
+        catch ( Exception e ) {
+            LOG.warn( "Could not convert list item {} to long", a, e );
+        }
+        return null;
+    }
+
+
+    public static <A> Boolean firstBoolean( List<A> list ) {
+        A a = first( list );
+        if ( a == null ) {
+            return null;
+        }
+
+        if ( a instanceof Boolean ) {
+            return ( Boolean ) a;
+        }
+
+        try {
+            return Boolean.parseBoolean( ( String ) a );
+        }
+        catch ( Exception e ) {
+            LOG.warn( "Could not convert list item {} to boolean", a, e );
+        }
+        return null;
+    }
+
+
+    public static <A> UUID firstUuid( List<A> list ) {
+        A i = first( list );
+        if ( i == null ) {
+            return null;
+        }
+
+        if ( i instanceof UUID ) {
+            return ( UUID ) i;
+        }
+
+        try {
+            return UUIDUtils.tryGetUUID( ( String ) i );
+        }
+        catch ( Exception e ) {
+            LOG.warn( "Could not convert list item {} to UUID", i, e );
+        }
+        return null;
+    }
+
+
+    public static boolean isEmpty( List<?> list ) {
+        return ( list == null ) || ( list.size() == 0 );
+    }
+
+
+    public static <T> List<T> dequeueCopy( List<T> list ) {
+        if ( !isEmpty( list ) ) {
+            list = list.subList( 1, list.size() );
+        }
+        return list;
+    }
+
+
+    public static <T> List<T> initCopy( List<T> list ) {
+        if ( !isEmpty( list ) ) {
+            list = new ArrayList<T>( list );
+        }
+        else {
+            list = new ArrayList<T>();
+        }
+        return list;
+    }
+
+
+    public static <T> T dequeue( List<T> list ) {
+        if ( !isEmpty( list ) ) {
+            return list.remove( 0 );
+        }
+        return null;
+    }
+
+
+    public static <T> List<T> queue( List<T> list, T item ) {
+        if ( list == null ) {
+            list = new ArrayList<T>();
+        }
+        list.add( item );
+        return list;
+    }
+
+
+    public static <T> List<T> requeue( List<T> list, T item ) {
+        if ( list == null ) {
+            list = new ArrayList<T>();
+        }
+        list.add( 0, item );
+        return list;
+    }
+
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static List<?> flatten( Collection<?> l ) {
+        boolean hasCollection = false;
+        for ( Object o : l ) {
+            if ( o instanceof Collection ) {
+                hasCollection = true;
+                break;
+            }
+        }
+        if ( !hasCollection && ( l instanceof List ) ) {
+            return ( List<?> ) l;
+        }
+        List newList = new ArrayList();
+        for ( Object o : l ) {
+            if ( o instanceof List ) {
+                newList.addAll( flatten( ( List ) o ) );
+            }
+            else {
+                newList.add( o );
+            }
+        }
+        return newList;
+    }
+
+
+    public static boolean anyNull( List<?> l ) {
+        for ( Object o : l ) {
+            if ( o == null ) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    public static boolean anyNull( Object... objects ) {
+        for ( Object o : objects ) {
+            if ( o == null ) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/MailUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/MailUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/MailUtils.java
new file mode 100644
index 0000000..becd669
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/MailUtils.java
@@ -0,0 +1,154 @@
+/*
+ * 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.usergrid.utils;
+
+
+import java.util.Properties;
+
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.jsoup.Jsoup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+import static org.apache.usergrid.utils.MapUtils.filter;
+
+
+/** Encapsulate the transport and error reporting of email */
+public class MailUtils {
+
+    private static final Logger logger = LoggerFactory.getLogger( MailUtils.class );
+
+    private static final String LOG_PREFIX = "MAIL-DELIVERY-FAILURE - description: [%s] recipient: [%s]";
+    private static final String LOG_PREFIX_OK = "MAIL-DELIVERY-SUCCESS - recipient: [%s]";
+    private static final String CONTENT_TYPE = "Content-Type";
+    private static final String MIME_VERSION = "MIME-Version";
+    private static final String MAIL_PROP_PREFIX = "mail.";
+    private static final String PROP_TRANSPORT = MAIL_PROP_PREFIX + "transport.protocol";
+
+
+    public static Properties getMailProperties( Properties properties ) {
+        return filter( properties, MAIL_PROP_PREFIX );
+    }
+
+
+    /**
+     * Send a message to the transport configured via the provided properties. Encapsulates the MIME multipart
+     * construction with the provided HTML and plain text forms.
+     * <p/>
+     * One of either plainText or htmlText (or both) are required. If both are null or empty we throw an
+     * IllegalArgumentException.
+     * <p/>
+     * In the case of only having htmlText, plainText is extracted from the body and wrapped in &lt;pre&gt; tags to
+     * create the multi-part.
+     *
+     * @param plainText can be null
+     */
+    public void sendMail( Properties props, String to, String from, String subject, String plainText,
+                          String htmlText ) {
+        Preconditions.checkArgument( StringUtils.isNotBlank( htmlText ) || StringUtils.isNotBlank( plainText ),
+                "htmlText and plainText were both blank" );
+
+        try {
+            if ( props == null ) {
+                props = System.getProperties();
+            }
+
+            String protocol = props.getProperty( PROP_TRANSPORT, "smtp" );
+            String host = props.getProperty( MAIL_PROP_PREFIX + protocol + ".host" );
+            String username = props.getProperty( MAIL_PROP_PREFIX + protocol + ".username" );
+            String password = props.getProperty( MAIL_PROP_PREFIX + protocol + ".password" );
+
+            Session session = Session.getInstance( props );
+            // session.setDebug(true);
+
+            MimeMultipart msgContent = new MimeMultipart( "alternative" );
+
+            if ( ( htmlText != null ) && ( plainText == null ) ) {
+                try {
+                    plainText = Jsoup.parse( htmlText ).body().wrap( "<pre></pre>" ).text();
+                }
+                catch ( Exception e ) {
+                    logger.error( "Html parse error", e );
+                }
+            }
+
+            if ( plainText != null ) {
+                MimeBodyPart plainPart = new MimeBodyPart();
+                plainPart.setContent( plainText, "text/plain" );
+                plainPart.setHeader( MIME_VERSION, "1.0" );
+                plainPart.setHeader( CONTENT_TYPE, "text/plain; charset=iso-8859-1" );
+                msgContent.addBodyPart( plainPart );
+            }
+
+            if ( htmlText != null ) {
+                MimeBodyPart htmlPart = new MimeBodyPart();
+                htmlPart.setContent( htmlText, "text/html" );
+                htmlPart.setHeader( MIME_VERSION, "1.0" );
+                htmlPart.setHeader( CONTENT_TYPE, "text/html; charset=iso-8859-1" );
+                msgContent.addBodyPart( htmlPart );
+            }
+
+            MimeMessage msg = new MimeMessage( session );
+            msg.setContent( msgContent );
+            msg.setFrom( new InternetAddress( from ) );
+            msg.addRecipient( Message.RecipientType.TO, new InternetAddress( to ) );
+            msg.setSubject( subject );
+
+            Transport transport = session.getTransport();
+
+            transport.connect( host, username, password );
+
+            transport.sendMessage( msg, msg.getAllRecipients() );
+            transport.close();
+            logger.info( String.format( LOG_PREFIX_OK, to ) );
+        }
+        catch ( AddressException ae ) {
+            logger.error( createErrorMessage( "could not send to bad address", to ), ae );
+        }
+        catch ( MessagingException me ) {
+            logger.error( createErrorMessage( "could not deliver message", to ), me );
+        }
+        catch ( Exception e ) {
+            logger.error( "General exception delivering mail", to, e );
+        }
+    }
+
+
+    /**
+     * Delegates to {@link #sendMail(java.util.Properties, String, String, String, String, String)} with null as the
+     * 'plainText' argument to such.
+     */
+    public void sendHtmlMail( Properties props, String to, String from, String subject, String html ) {
+        sendMail( props, to, from, subject, null, html );
+    }
+
+
+    String createErrorMessage( String message, String toAddress ) {
+        return String.format( LOG_PREFIX, message, toAddress );
+    }
+}


Mime
View raw message