You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/02/05 22:28:22 UTC
[28/90] [partial] Change package namespace to org.apache.usergrid
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("post") #=> "posts"
+ * inflector.pluralize("octopus") #=> "octopi"
+ * inflector.pluralize("sheep") #=> "sheep"
+ * inflector.pluralize("words") #=> "words"
+ * inflector.pluralize("the blue mailman") #=> "the blue mailmen"
+ * inflector.pluralize("CamelOctopus") #=> "CamelOctopi"
+ * </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("posts") #=> "post"
+ * inflector.singularize("octopi") #=> "octopus"
+ * inflector.singularize("sheep") #=> "sheep"
+ * inflector.singularize("words") #=> "word"
+ * inflector.singularize("the blue mailmen") #=> "the blue mailman"
+ * inflector.singularize("CamelOctopi") #=> "CamelOctopus"
+ * </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("active_record",false) #=> "activeRecord"
+ * inflector.camelCase("active_record",true) #=> "ActiveRecord"
+ * inflector.camelCase("first_name",false) #=> "firstName"
+ * inflector.camelCase("first_name",true) #=> "FirstName"
+ * inflector.camelCase("name",false) #=> "name"
+ * inflector.camelCase("name",true) #=> "Name"
+ * </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("activeRecord") #=> "active_record"
+ * inflector.underscore("ActiveRecord") #=> "active_record"
+ * inflector.underscore("firstName") #=> "first_name"
+ * inflector.underscore("FirstName") #=> "first_name"
+ * inflector.underscore("name") #=> "name"
+ * inflector.underscore("The.firstName") #=> "the_first_name"
+ * </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>\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>\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 <pre> 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 );
+ }
+}