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/01/28 23:21:37 UTC

[27/96] [abbrv] [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/MapUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/MapUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/MapUtils.java
new file mode 100644
index 0000000..fcf61b6
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/MapUtils.java
@@ -0,0 +1,376 @@
+/*
+ * 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.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.apache.usergrid.utils.ClassUtils.cast;
+
+
+public class MapUtils extends org.apache.commons.collections.MapUtils {
+
+    public static <A, B> void addMapSet( Map<A, Set<B>> map, A a, B b ) {
+        addMapSet( map, false, a, b );
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static <A, B> void addMapSet( Map<A, Set<B>> map, boolean ignoreCase, A a, B b ) {
+
+        Set<B> setB = map.get( a );
+        if ( setB == null ) {
+            if ( ignoreCase && ( b instanceof String ) ) {
+                setB = ( Set<B> ) new TreeSet<String>( String.CASE_INSENSITIVE_ORDER );
+            }
+            else {
+                setB = new LinkedHashSet<B>();
+            }
+            map.put( a, setB );
+        }
+        setB.add( b );
+    }
+
+
+    public static <A, B, C> void addMapMapSet( Map<A, Map<B, Set<C>>> map, A a, B b, C c ) {
+        addMapMapSet( map, false, a, b, c );
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static <A, B, C> void addMapMapSet( Map<A, Map<B, Set<C>>> map, boolean ignoreCase, A a, B b, C c ) {
+
+        Map<B, Set<C>> mapB = map.get( a );
+        if ( mapB == null ) {
+            if ( ignoreCase && ( b instanceof String ) ) {
+                mapB = ( Map<B, Set<C>> ) new TreeMap<String, Set<C>>( String.CASE_INSENSITIVE_ORDER );
+            }
+            else {
+                mapB = new LinkedHashMap<B, Set<C>>();
+            }
+            map.put( a, mapB );
+        }
+        addMapSet( mapB, ignoreCase, b, c );
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static <A, B, C, D> void addMapMapMapSet( Map<A, Map<B, Map<C, Set<D>>>> map, boolean ignoreCase, A a, B b,
+                                                     C c, D d ) {
+        Map<B, Map<C, Set<D>>> mapB = map.get( a );
+        if ( mapB == null ) {
+            if ( ignoreCase && ( b instanceof String ) ) {
+                mapB = ( Map<B, Map<C, Set<D>>> ) new TreeMap<String, Map<C, Set<D>>>( String.CASE_INSENSITIVE_ORDER );
+            }
+            else {
+                mapB = new LinkedHashMap<B, Map<C, Set<D>>>();
+            }
+            map.put( a, mapB );
+        }
+        addMapMapSet( mapB, ignoreCase, b, c, d );
+    }
+
+
+    public static <A, B, C> C getMapMap( Map<A, Map<B, C>> map, A a, B b ) {
+
+        Map<B, C> mapB = map.get( a );
+        if ( mapB == null ) {
+            return null;
+        }
+        return mapB.get( b );
+    }
+
+
+    public static <A, B> void addMapList( Map<A, List<B>> map, A a, B b ) {
+
+        List<B> listB = map.get( a );
+        if ( listB == null ) {
+            listB = new ArrayList<B>();
+            map.put( a, listB );
+        }
+        listB.add( b );
+    }
+
+
+    public static <A, B> void addListToMapList( Map<A, List<B>> map, A a, List<B> b ) {
+
+        List<B> listB = map.get( a );
+        if ( listB == null ) {
+            listB = new ArrayList<B>();
+            map.put( a, listB );
+        }
+        listB.addAll( b );
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static <K, V> V getValue( Map<K, ?> map, K k ) {
+        V v = null;
+        try {
+            v = ( V ) map.get( k );
+        }
+        catch ( ClassCastException e ) {
+            //LOG.war( "Map value {} was not the expected class", map.get( k ), e );
+        }
+
+        return v;
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static <K, V> Map<?, ?> map( Object... objects ) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+        int i = 0;
+        while ( i < objects.length ) {
+            if ( objects[i] instanceof Map.Entry ) {
+                Map.Entry<K, V> entry = ( Entry<K, V> ) objects[i];
+                map.put( entry.getKey(), entry.getValue() );
+                i++;
+            }
+            else if ( objects[i] instanceof Map ) {
+                map.putAll( ( Map<? extends K, ? extends V> ) objects[i] );
+                i++;
+            }
+            else if ( i < ( objects.length - 1 ) ) {
+                K k = ( K ) objects[i];
+                V v = ( V ) objects[i + 1];
+                map.put( k, v );
+                i += 2;
+            }
+            else {
+                break;
+            }
+        }
+        return map;
+    }
+
+
+    private static class SimpleMapEntry<K, V> implements Map.Entry<K, V> {
+
+        private final K k;
+        private V v;
+
+
+        public SimpleMapEntry( K k, V v ) {
+            this.k = k;
+            this.v = v;
+        }
+
+
+        @Override
+        public K getKey() {
+            return k;
+        }
+
+
+        @Override
+        public V getValue() {
+            return v;
+        }
+
+
+        @Override
+        public V setValue( V v ) {
+            V oldV = this.v;
+            this.v = v;
+            return oldV;
+        }
+    }
+
+
+    public static <K, V> Map.Entry<K, V> entry( K k, V v ) {
+        return new SimpleMapEntry<K, V>( k, v );
+    }
+
+
+    public static <K, V> K getFirstKey( Map<K, V> map ) {
+        if ( map == null ) {
+            return null;
+        }
+        Entry<K, V> e = map.entrySet().iterator().next();
+        if ( e != null ) {
+            return e.getKey();
+        }
+        return null;
+    }
+
+
+    public static <V> Map<String, V> filter( Map<String, V> map, String prefix, boolean removePrefix ) {
+        Map<String, V> filteredMap = new LinkedHashMap<String, V>();
+        for ( Entry<String, V> entry : map.entrySet() ) {
+            if ( entry.getKey().startsWith( prefix ) ) {
+                if ( removePrefix ) {
+                    filteredMap.put( entry.getKey().substring( prefix.length() ), entry.getValue() );
+                }
+                else {
+                    filteredMap.put( entry.getKey(), entry.getValue() );
+                }
+            }
+        }
+        return filteredMap;
+    }
+
+
+    public static <V> Map<String, V> filter( Map<String, V> map, String prefix ) {
+        return filter( map, prefix, false );
+    }
+
+
+    public static Properties filter( Properties properties, String prefix, boolean removePrefix ) {
+        Properties filteredProperties = new Properties();
+        for ( Entry<String, String> entry : asMap( properties ).entrySet() ) {
+            if ( entry.getKey().startsWith( prefix ) ) {
+                if ( removePrefix ) {
+                    filteredProperties.put( entry.getKey().substring( prefix.length() ), entry.getValue() );
+                }
+                else {
+                    filteredProperties.put( entry.getKey(), entry.getValue() );
+                }
+            }
+        }
+        return filteredProperties;
+    }
+
+
+    public static Properties filter( Properties properties, String prefix ) {
+        return filter( properties, prefix, false );
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static Map<String, String> asMap( Properties properties ) {
+        return cast( properties );
+    }
+
+
+    public static <S, T> HashMapBuilder<S, T> hashMap( S key, T value ) {
+        return new HashMapBuilder<S, T>().map( key, value );
+    }
+
+
+    public static class HashMapBuilder<S, T> extends HashMap<S, T> {
+        private static final long serialVersionUID = 1L;
+
+
+        public HashMapBuilder() {
+        }
+
+
+        public HashMapBuilder<S, T> map( S key, T value ) {
+            put( key, value );
+            return this;
+        }
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static Map<String, List<?>> toMapList( Map<String, ?> m ) {
+        Map<String, List<Object>> mapList = new LinkedHashMap<String, List<Object>>();
+
+        for ( Entry<String, ?> e : m.entrySet() ) {
+            if ( e.getValue() instanceof List ) {
+                addListToMapList( mapList, e.getKey(), ( List<Object> ) e.getValue() );
+            }
+            else {
+                addMapList( mapList, e.getKey(), e.getValue() );
+            }
+        }
+
+        return cast( mapList );
+    }
+
+
+    public static Map<String, ?> putPath( String path, Object value ) {
+        return putPath( null, path, value );
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public static Map<String, ?> putPath( Map<String, ?> map, String path, Object value ) {
+
+        if ( map == null ) {
+            map = new HashMap<String, Object>();
+        }
+
+        int i = path.indexOf( '.' );
+        if ( i < 0 ) {
+            ( ( Map<String, Object> ) map ).put( path, value );
+            return map;
+        }
+        String segment = path.substring( 0, i ).trim();
+        if ( isNotBlank( segment ) ) {
+            Object o = map.get( segment );
+            if ( ( o != null ) && ( !( o instanceof Map ) ) ) {
+                return map;
+            }
+            Map<String, Object> subMap = ( Map<String, Object> ) o;
+            if ( subMap == null ) {
+                subMap = new HashMap<String, Object>();
+                ( ( Map<String, Object> ) map ).put( segment, subMap );
+            }
+            String subPath = path.substring( i + 1 );
+            if ( isNotBlank( subPath ) ) {
+                putPath( subMap, subPath, value );
+            }
+        }
+
+        return map;
+    }
+
+
+    public static <K, V> Map<K, V> emptyMapWithKeys( Map<K, V> map ) {
+        Map<K, V> newMap = new HashMap<K, V>();
+
+        for ( K k : map.keySet() ) {
+            newMap.put( k, null );
+        }
+
+        return newMap;
+    }
+
+
+    public static boolean hasKeys( Map<?, ?> map, String... keys ) {
+        if ( map == null ) {
+            return false;
+        }
+        for ( String key : keys ) {
+            if ( !map.containsKey( key ) ) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    public static boolean hasKeys( Map<?, ?> map, Set<String> keys ) {
+        if ( map == null ) {
+            return false;
+        }
+        return map.keySet().containsAll( keys );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/NumberUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/NumberUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/NumberUtils.java
new file mode 100644
index 0000000..129040b
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/NumberUtils.java
@@ -0,0 +1,35 @@
+/*
+ * 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 NumberUtils {
+    public static int sign( int i ) {
+        if ( i < 0 ) {
+            return -1;
+        }
+        if ( i > 0 ) {
+            return 1;
+        }
+        return 0;
+    }
+
+
+    public static long roundLong( long l, long r ) {
+        return ( l / r ) * r;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/PasswordUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/PasswordUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/PasswordUtils.java
new file mode 100644
index 0000000..41d6a67
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/PasswordUtils.java
@@ -0,0 +1,28 @@
+/*
+ * 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 org.apache.commons.codec.digest.DigestUtils;
+
+
+public class PasswordUtils {
+
+    public static String mongoPassword( String username, String password ) {
+        return DigestUtils.md5Hex( username + ":mongo:" + password );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/StringUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/StringUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/StringUtils.java
new file mode 100644
index 0000000..241e211
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/StringUtils.java
@@ -0,0 +1,171 @@
+/*
+ * 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.Arrays;
+
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.usergrid.utils.ConversionUtils.string;
+
+
+public class StringUtils extends org.apache.commons.lang.StringUtils {
+
+    private static final Logger LOG = LoggerFactory.getLogger( StringUtils.class );
+
+
+    public static Object lower( Object obj ) {
+        if ( !( obj instanceof String ) ) {
+            return obj;
+        }
+        return ( ( String ) obj ).toLowerCase();
+    }
+
+
+    public static String stringOrSubstringAfterLast( String str, char c ) {
+        if ( str == null ) {
+            return null;
+        }
+        int i = str.lastIndexOf( c );
+        if ( i != -1 ) {
+            return str.substring( i + 1 );
+        }
+        return str;
+    }
+
+
+    public static String stringOrSubstringBeforeLast( String str, char c ) {
+        if ( str == null ) {
+            return null;
+        }
+        int i = str.lastIndexOf( c );
+        if ( i != -1 ) {
+            return str.substring( 0, i );
+        }
+        return str;
+    }
+
+
+    public static String stringOrSubstringBeforeFirst( String str, char c ) {
+        if ( str == null ) {
+            return null;
+        }
+        int i = str.indexOf( c );
+        if ( i != -1 ) {
+            return str.substring( 0, i );
+        }
+        return str;
+    }
+
+
+    public static String stringOrSubstringAfterFirst( String str, char c ) {
+        if ( str == null ) {
+            return null;
+        }
+        int i = str.indexOf( c );
+        if ( i != -1 ) {
+            return str.substring( i + 1 );
+        }
+        return str;
+    }
+
+
+    public static String compactWhitespace( String str ) {
+        if ( str == null ) {
+            return null;
+        }
+        boolean prevWS = false;
+        StringBuilder builder = new StringBuilder();
+        for ( int i = 0; i < str.length(); i++ ) {
+            char c = str.charAt( i );
+            if ( Character.isWhitespace( c ) ) {
+                if ( !prevWS ) {
+                    builder.append( ' ' );
+                }
+                prevWS = true;
+            }
+            else {
+                prevWS = false;
+                builder.append( c );
+            }
+        }
+        return builder.toString().trim();
+    }
+
+
+    /** @return new string with replace applied */
+    public static String replaceAll( String source, String find, String replace ) {
+        if ( source == null ) {
+            return null;
+        }
+        while ( true ) {
+            String old = source;
+            source = source.replaceAll( find, replace );
+            if ( source.equals( old ) ) {
+                return source;
+            }
+        }
+    }
+
+
+    public static String toString( Object obj ) {
+        return string( obj );
+    }
+
+
+    public static String toStringFormat( Object obj, String format ) {
+        if ( obj != null ) {
+            if ( format != null ) {
+                if ( obj.getClass().isArray() ) {
+                    return String.format( format, Arrays.toString( ( Object[] ) obj ) );
+                }
+                return String.format( format, string( obj ) );
+            }
+            else {
+                return string( obj );
+            }
+        }
+        return "";
+    }
+
+
+    public static boolean isString( Object obj ) {
+        return obj instanceof String;
+    }
+
+
+    public static boolean isStringOrNull( Object obj ) {
+        if ( obj == null ) {
+            return true;
+        }
+        return obj instanceof String;
+    }
+
+
+    public static String readClasspathFileAsString( String filePath ) {
+        try {
+            return IOUtils.toString( StringUtils.class.getResourceAsStream( filePath ) );
+        }
+        catch ( Exception e ) {
+            LOG.error( "Error getting file from classpath: " + filePath, e );
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/TimeUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/TimeUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/TimeUtils.java
new file mode 100644
index 0000000..64dc3f5
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/TimeUtils.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.
+ */
+package org.apache.usergrid.utils;
+
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+
+
+public class TimeUtils {
+    /**
+     * Jira-style duration parser. Supported duration strings are: <ul> <li>'S': milliseconds</li> <li>'s': seconds</li>
+     * <li>'m': minutes</li> <li>'h': hours</li> <li>'d': days</li> </ul>
+     * <p/>
+     * Durations can be compound statements in any order as long as they are separated by a ',' (comma). Eg. "1d,14h,3s"
+     * to get the millisecond equivalent of one day, fourteen hours and 3 seconds.
+     * <p/>
+     * Numbers with no durations will be treated as raw millisecond values
+     *
+     * @return the number of milliseconds representing the duration
+     */
+    public static long millisFromDuration( String durationStr ) {
+        long total = 0;
+        MultiplierToken mt;
+        long dur;
+        for ( String val : Splitter.on( ',' ).trimResults().omitEmptyStrings().split( durationStr ) ) {
+            dur = Long.parseLong( CharMatcher.DIGIT.retainFrom( val ) );
+            mt = MultiplierToken.from( val.charAt( val.length() - 1 ) );
+            total += ( mt.multiplier * dur );
+        }
+        return total;
+    }
+
+
+    private enum MultiplierToken {
+        MILSEC_TOKEN( 'S', 1L ),
+        SEC_TOKEN( 's', 1000L ),
+        MIN_TOKEN( 'm', 60000L ),
+        HOUR_TOKEN( 'h', 3600000L ),
+        DAY_TOKEN( 'd', 86400000L );
+
+        final char token;
+        final long multiplier;
+
+
+        MultiplierToken( char token, long multiplier ) {
+            this.token = token;
+            this.multiplier = multiplier;
+        }
+
+
+        static MultiplierToken from( char c ) {
+            switch ( c ) {
+                case 's':
+                    return SEC_TOKEN;
+                case 'm':
+                    return MIN_TOKEN;
+                case 'h':
+                    return HOUR_TOKEN;
+                case 'd':
+                    return DAY_TOKEN;
+                case 'S':
+                    return MILSEC_TOKEN;
+                default:
+                    break;
+            }
+
+            if ( CharMatcher.DIGIT.matches( c ) ) {
+                return MILSEC_TOKEN;
+            }
+            throw new IllegalArgumentException( "Duration token was not on of [S,s,m,h,d] but was " + c );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/UUIDUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/UUIDUtils.java b/stack/core/src/main/java/org/apache/usergrid/utils/UUIDUtils.java
new file mode 100644
index 0000000..cbb508b
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/UUIDUtils.java
@@ -0,0 +1,411 @@
+/*
+ * 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.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
+
+import com.fasterxml.uuid.EthernetAddress;
+import com.fasterxml.uuid.UUIDComparator;
+
+import static com.fasterxml.uuid.impl.UUIDUtil.BYTE_OFFSET_CLOCK_HI;
+import static com.fasterxml.uuid.impl.UUIDUtil.BYTE_OFFSET_CLOCK_LO;
+import static com.fasterxml.uuid.impl.UUIDUtil.BYTE_OFFSET_CLOCK_MID;
+import static com.fasterxml.uuid.impl.UUIDUtil.BYTE_OFFSET_CLOCK_SEQUENCE;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.commons.codec.binary.Base64.decodeBase64;
+import static org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString;
+import static org.apache.usergrid.utils.ConversionUtils.bytes;
+import static org.apache.usergrid.utils.ConversionUtils.uuid;
+
+
+public class UUIDUtils {
+    private static final Logger LOG = LoggerFactory.getLogger( UUIDUtils.class );
+    private static final int[] MICROS = new int[1000];
+
+
+    static {
+        for ( int x = 0; x < 1000; x++ ) {
+            MICROS[x] = x * 10;
+        }
+    }
+
+
+    private static ReentrantLock tsLock = new ReentrantLock( true );
+
+    public static final UUID MIN_TIME_UUID = UUID.fromString( "00000000-0000-1000-8000-000000000000" );
+
+    public static final UUID MAX_TIME_UUID = UUID.fromString( "ffffffff-ffff-1fff-bfff-ffffffffffff" );
+
+    public static final UUID ZERO_UUID = new UUID( 0, 0 );
+
+    private static long timestampMillisNow = System.currentTimeMillis();
+
+    private static AtomicInteger currentMicrosPoint = new AtomicInteger( 0 );
+    private static AtomicInteger customMicrosPointer = new AtomicInteger( 0 );
+
+
+    /**
+     * Return the "next" UUID in micro second resolution. <b>WARNING</b>: this is designed to return the next unique
+     * timestamped UUID for this JVM. Depending on velocity of the call, this method may block internally to insure that
+     * "now" is kept in sync with the UUIDs being generated by this call.
+     * <p/>
+     * In other words, we will intentionally burn CPU insuring that this method is not executed more than 10k -1 times
+     * per millisecond and guarantee that those microseconds held within are sequential.
+     * <p/>
+     * If we did not do this, you would get <b>timestamp collision</b> even though the UUIDs will technically be
+     * 'unique.'
+     */
+    public static java.util.UUID newTimeUUID() {
+        // get & inc counter, but roll on 1k (because we divide by 10 on retrieval)
+        // if count + currentMicro > 1k, block and roll
+        tsLock.lock();
+        long ts = System.currentTimeMillis();
+        if ( ts > timestampMillisNow ) {
+            timestampMillisNow = ts;
+            currentMicrosPoint.set( 0 );
+        }
+        int pointer = currentMicrosPoint.getAndIncrement();
+        try {
+            if ( pointer > 990 ) {
+                TimeUnit.MILLISECONDS.sleep( 1L );
+            }
+        }
+        catch ( Exception ex ) {
+            ex.printStackTrace();
+        }
+        finally {
+            tsLock.unlock();
+        }
+        return newTimeUUID( ts, MICROS[pointer] );
+    }
+
+
+    private static final long KCLOCK_OFFSET = 0x01b21dd213814000L;
+    private static final long KCLOCK_MULTIPLIER_L = 10000L;
+
+    private static final Random CLOCK_SEQ_RANDOM = new Random();
+
+
+    // 14 bits of randomness
+    private static int getRandomClockSequence() {
+        return CLOCK_SEQ_RANDOM.nextInt() & 0x3FFF;
+    }
+
+
+    private static void setTimestamp( long timestamp, byte[] uuidBytes, int clockSeq, int timeOffset ) {
+
+        timestamp *= KCLOCK_MULTIPLIER_L;
+        timestamp += KCLOCK_OFFSET;
+        timestamp += timeOffset;
+
+        // Set random clock sequence
+        uuidBytes[BYTE_OFFSET_CLOCK_SEQUENCE] = ( byte ) ( clockSeq >> 8 );
+        uuidBytes[BYTE_OFFSET_CLOCK_SEQUENCE + 1] = ( byte ) clockSeq;
+
+        // Set variant
+        uuidBytes[BYTE_OFFSET_CLOCK_SEQUENCE] &= 0x3F;
+        uuidBytes[BYTE_OFFSET_CLOCK_SEQUENCE] |= 0x80;
+        setTime( uuidBytes, timestamp );
+    }
+
+
+    @SuppressWarnings("all")
+    private static void setTime( byte[] uuidBytes, long timestamp ) {
+
+        // Time fields aren't nicely split across the UUID, so can't just
+        // linearly dump the stamp:
+        int clockHi = ( int ) ( timestamp >>> 32 );
+        int clockLo = ( int ) timestamp;
+
+        uuidBytes[BYTE_OFFSET_CLOCK_HI] = ( byte ) ( clockHi >>> 24 );
+        uuidBytes[BYTE_OFFSET_CLOCK_HI + 1] = ( byte ) ( clockHi >>> 16 );
+        uuidBytes[BYTE_OFFSET_CLOCK_MID] = ( byte ) ( clockHi >>> 8 );
+        uuidBytes[BYTE_OFFSET_CLOCK_MID + 1] = ( byte ) clockHi;
+
+        uuidBytes[BYTE_OFFSET_CLOCK_LO] = ( byte ) ( clockLo >>> 24 );
+        uuidBytes[BYTE_OFFSET_CLOCK_LO + 1] = ( byte ) ( clockLo >>> 16 );
+        uuidBytes[BYTE_OFFSET_CLOCK_LO + 2] = ( byte ) ( clockLo >>> 8 );
+        uuidBytes[BYTE_OFFSET_CLOCK_LO + 3] = ( byte ) clockLo;
+
+        // Set version
+        uuidBytes[BYTE_OFFSET_CLOCK_HI] &= 0x0F;
+        uuidBytes[BYTE_OFFSET_CLOCK_HI] |= 0x10;
+    }
+
+
+    /**
+     * Generate a timeuuid with the given timestamp in milliseconds and the time offset. Useful when you need to
+     * generate sequential UUIDs for the same period in time. I.E
+     * <p/>
+     * newTimeUUID(1000, 0) <br/> newTimeUUID(1000, 1) <br /> newTimeUUID(1000, 2) <br />
+     * <p/>
+     * etc.
+     * <p/>
+     * Only use this method if you are absolutely sure you need it. When it doubt use the method without the timestamp
+     * offset
+     *
+     * @param ts The timestamp in milliseconds
+     * @param timeoffset The offset, which should always be <= 10000. If you go beyond this range, the millisecond will
+     * be incremented since this is beyond the possible values when coverrting from millis to 1/10 microseconds stored
+     * in the time uuid.
+     */
+    public static UUID newTimeUUID( long ts, int timeoffset ) {
+        if ( ts == 0 ) {
+            return newTimeUUID();
+        }
+
+        byte[] uuidBytes = new byte[16];
+        // 47 bits of randomness
+        EthernetAddress eth = EthernetAddress.constructMulticastAddress();
+        eth.toByteArray( uuidBytes, 10 );
+        setTimestamp( ts, uuidBytes, getRandomClockSequence(), timeoffset );
+
+        return uuid( uuidBytes );
+    }
+
+
+    /**
+     * Generate a new UUID with the given time stamp in milliseconds. This method guarantees that subsequent calls will
+     * be of increasing value chronologically. If a large number of subsequent calls are made to this method (>1000)
+     * with the same timestamp, you will have non-unique temporal values stored in your UUID.
+     */
+    public static UUID newTimeUUID( long ts ) {
+        tsLock.lock();
+        int pointer = customMicrosPointer.getAndIncrement();
+        try {
+            if ( pointer > 990 ) {
+                customMicrosPointer.set( 0 );
+            }
+        }
+        finally {
+            tsLock.unlock();
+        }
+        return newTimeUUID( ts, MICROS[pointer] );
+    }
+
+
+    public static UUID minTimeUUID( long ts ) {
+        byte[] uuidBytes = new byte[16];
+        setTimestamp( ts, uuidBytes, 0, 0 );
+
+        return uuid( uuidBytes );
+    }
+
+
+    public static UUID maxTimeUUID( long ts ) {
+        byte[] uuidBytes = new byte[16];
+        uuidBytes[10] = ( byte ) 0xFF;
+        uuidBytes[11] = ( byte ) 0xFF;
+        uuidBytes[12] = ( byte ) 0xFF;
+        uuidBytes[13] = ( byte ) 0xFF;
+        uuidBytes[14] = ( byte ) 0xFF;
+        uuidBytes[15] = ( byte ) 0xFF;
+        setTimestamp( ts, uuidBytes, 0x3FFF, 0x1FFF );
+
+        return uuid( uuidBytes );
+    }
+
+
+    /** Returns the minimum UUID */
+    public static UUID min( UUID first, UUID second ) {
+        if ( first == null ) {
+            if ( second == null ) {
+                return null;
+            }
+            return second;
+        }
+
+        if ( second == null ) {
+            return first;
+        }
+
+        if ( compare( first, second ) < 0 ) {
+            return first;
+        }
+        return second;
+    }
+
+
+    /** Returns the minimum UUID */
+    public static UUID max( UUID first, UUID second ) {
+        if ( first == null ) {
+            if ( second == null ) {
+                return null;
+            }
+            return second;
+        }
+
+        if ( second == null ) {
+            return first;
+        }
+
+        if ( compare( first, second ) < 0 ) {
+            return second;
+        }
+        return first;
+    }
+
+
+    /** Returns a UUID that is -1 of the passed uuid, sorted by time uuid only */
+    public static UUID decrement( UUID uuid ) {
+        if ( !isTimeBased( uuid ) ) {
+            throw new IllegalArgumentException( "The uuid must be a time type" );
+        }
+
+
+        //timestamp is in the 60 bit timestamp
+        long timestamp = uuid.timestamp();
+        timestamp--;
+
+        if ( timestamp < 0 ) {
+            throw new IllegalArgumentException( "You must specify a time uuid with a timestamp > 0" );
+        }
+
+        //get our bytes, then set the smaller timestamp into it
+        byte[] uuidBytes = bytes( uuid );
+
+        setTime( uuidBytes, timestamp );
+
+        return uuid( uuidBytes );
+    }
+
+
+    public static boolean isTimeBased( UUID uuid ) {
+        if ( uuid == null ) {
+            return false;
+        }
+        return uuid.version() == 1;
+    }
+
+
+    public static long getTimestampInMillis( UUID uuid ) {
+        if ( uuid == null ) {
+            return 0;
+        }
+        long t = uuid.timestamp();
+        return ( t - KCLOCK_OFFSET ) / KCLOCK_MULTIPLIER_L;
+    }
+
+
+    public static long getTimestampInMicros( UUID uuid ) {
+        if ( uuid == null ) {
+            return 0;
+        }
+        long t = uuid.timestamp();
+        return ( t - KCLOCK_OFFSET ) / 10;
+    }
+
+
+    public static UUID tryGetUUID( String s ) {
+        if ( s == null ) {
+            return null;
+        }
+        if ( s.length() != 36 ) {
+            return null;
+        }
+        // 8-4-4-4-12
+        // 0-7,8,9-12,13,14-17,18,19-22,23,24-35
+        if ( s.charAt( 8 ) != '-' ) {
+            return null;
+        }
+        if ( s.charAt( 13 ) != '-' ) {
+            return null;
+        }
+        if ( s.charAt( 18 ) != '-' ) {
+            return null;
+        }
+        if ( s.charAt( 23 ) != '-' ) {
+            return null;
+        }
+        UUID uuid = null;
+        try {
+            uuid = UUID.fromString( s );
+        }
+        catch ( Exception e ) {
+            LOG.info( "Could not convert String {} into a UUID", s, e );
+        }
+        return uuid;
+    }
+
+
+    public static boolean isUUID( String s ) {
+        return tryGetUUID( s ) != null;
+    }
+
+
+    public static UUID tryExtractUUID( String s ) {
+        if ( s == null ) {
+            return null;
+        }
+        if ( s.length() < 36 ) {
+            return null;
+        }
+        return tryGetUUID( s.substring( 0, 36 ) );
+    }
+
+
+    public static UUID tryExtractUUID( String s, int offset ) {
+        if ( s == null ) {
+            return null;
+        }
+        if ( ( s.length() - offset ) < 36 ) {
+            return null;
+        }
+        return tryGetUUID( s.substring( offset, offset + 36 ) );
+    }
+
+
+    public static String toBase64( UUID id ) {
+        if ( id == null ) {
+            return null;
+        }
+        return encodeBase64URLSafeString( bytes( id ) );
+    }
+
+
+    public static UUID fromBase64( String str ) {
+        if ( str == null ) {
+            return null;
+        }
+        byte[] bytes = decodeBase64( str );
+        if ( bytes.length != 16 ) {
+            return null;
+        }
+        return uuid( bytes );
+    }
+
+
+    public static int compare( UUID u1, UUID u2 ) {
+        return UUIDComparator.staticCompare( u1, u2 );
+    }
+
+
+    public static List<UUID> sort( List<UUID> uuids ) {
+        Collections.sort( uuids, new UUIDComparator() );
+        return uuids;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/Version.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/Version.java b/stack/core/src/main/java/org/apache/usergrid/utils/Version.java
new file mode 100644
index 0000000..ec9244a
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/Version.java
@@ -0,0 +1,428 @@
+/*
+ * 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;
+
+/*******************************************************************************
+ * Copyright (c) 2010, Schley Andrew Kutz All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Schley Andrew Kutz nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+
+import java.io.Serializable;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang.StringUtils;
+
+
+/**
+ * The Version class can be used to parse a standard version string into its four components,
+ * MAJOR.MINOR.BUILD.REVISION.
+ */
+public class Version implements Serializable, Cloneable, Comparable<Version> {
+    /** A serial version UID. */
+    private static final long serialVersionUID = -4316270526722986552L;
+
+    /** A pattern to match the standard version format MAJOR.MINOR.BUILD.REVISION. */
+    private static final Pattern STD_VERSION_PATT =
+            Pattern.compile( "^([^\\d]*?)(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:\\.(\\d+))?(.*)$" );
+
+
+    /** Initialize a new Version object that is set to "0.0.0.0". */
+    public Version() {
+    }
+
+
+    /** Everything before the version in the string that was parsed. */
+    private String prefix;
+
+    /** Everything after the version in the string that was parsed. */
+    private String suffix;
+
+    /** The String that was parsed to create this version object. */
+    private String rawVersion;
+
+
+    /**
+     * Gets everything before the version in the string that was parsed.
+     *
+     * @return Everything before the version in the string that was parsed.
+     */
+    public String getPrefix() {
+        return prefix;
+    }
+
+
+    /**
+     * Parses a new Version object from a String.
+     *
+     * @param toParse The String object to parse.
+     *
+     * @return A new Version object.
+     *
+     * @throws Exception When there is an error parsing the String.
+     */
+    public static Version parse( String toParse ) throws Exception {
+        Matcher m = STD_VERSION_PATT.matcher( toParse );
+
+        if ( !m.find() ) {
+            throw new Exception( String.format( "Error parsing version from '%s'", toParse ) );
+        }
+
+        Version v = new Version();
+        v.rawVersion = toParse;
+        v.prefix = m.group( 1 );
+
+        if ( StringUtils.isNotEmpty( m.group( 2 ) ) ) {
+            v.setMajor( m.group( 2 ) );
+        }
+
+        if ( StringUtils.isNotEmpty( m.group( 3 ) ) ) {
+            v.setMinor( m.group( 3 ) );
+        }
+
+        if ( StringUtils.isNotEmpty( m.group( 4 ) ) ) {
+            v.setBuild( m.group( 4 ) );
+        }
+
+        if ( StringUtils.isNotEmpty( m.group( 5 ) ) ) {
+            v.setRevision( m.group( 5 ) );
+        }
+
+        v.suffix = m.group( 6 );
+
+        return v;
+    }
+
+
+    /** The version's MAJOR component. */
+    private String major = "0";
+
+
+    /**
+     * Sets the version's MAJOR component.
+     *
+     * @param toSet The version's MAJOR component.
+     *
+     * @throws IllegalArgumentException When a null or non-numeric value is given.
+     */
+    public void setMajor( String toSet ) throws IllegalArgumentException {
+        if ( StringUtils.isEmpty( toSet ) ) {
+            throw new IllegalArgumentException( "Argument is null" );
+        }
+
+        if ( !toSet.matches( "\\d+" ) ) {
+            throw new IllegalArgumentException( "Argument is not numeric" );
+        }
+
+        if ( numberOfComponents < 1 ) {
+            numberOfComponents = 1;
+        }
+
+        major = toSet;
+    }
+
+
+    /** The version's MAJOR component as an integer. */
+    private int getMajorAsInt() {
+        return Integer.parseInt( major );
+    }
+
+
+    /** The version's MINOR component. */
+    private String minor = "0";
+
+
+    /**
+     * Sets the version's MINOR component.
+     *
+     * @param toSet The version's MINOR component.
+     *
+     * @throws IllegalArgumentException When a null or non-numeric value is given.
+     */
+    public void setMinor( String toSet ) throws IllegalArgumentException {
+        if ( StringUtils.isEmpty( toSet ) ) {
+            throw new IllegalArgumentException( "Argument is null" );
+        }
+
+        if ( !toSet.matches( "\\d+" ) ) {
+            throw new IllegalArgumentException( "Argument is not numeric" );
+        }
+
+        if ( numberOfComponents < 2 ) {
+            numberOfComponents = 2;
+        }
+
+        minor = toSet;
+    }
+
+
+    /** The version's MINOR component as an integer. */
+    private int getMinorAsInt() {
+        return Integer.parseInt( minor );
+    }
+
+
+    /** The version's BUILD component. */
+    private String build = "0";
+
+
+    /** The version's BUILD component as an integer. */
+    private int getBuildAsInt() {
+        return Integer.parseInt( build );
+    }
+
+
+    /**
+     * Gets the version's BUILD component.
+     *
+     * @return The version's BUILD component.
+     */
+    public String getBuild() {
+        return build;
+    }
+
+
+    /**
+     * Sets the version's BUILD component.
+     *
+     * @param toSet The version's BUILD component.
+     *
+     * @throws IllegalArgumentException When a null or non-numeric value is given.
+     */
+    public void setBuild( String toSet ) throws IllegalArgumentException {
+        if ( StringUtils.isEmpty( toSet ) ) {
+            throw new IllegalArgumentException( "Argument is null" );
+        }
+
+        if ( !toSet.matches( "\\d+" ) ) {
+            throw new IllegalArgumentException( "Argument is not numeric" );
+        }
+
+        if ( numberOfComponents < 3 ) {
+            numberOfComponents = 3;
+        }
+
+        build = toSet;
+    }
+
+
+    /**
+     * Sets the version's BUILD component.
+     *
+     * @param toSet The version's BUILD component.
+     */
+    public void setBuild( int toSet ) {
+        setBuild( String.valueOf( toSet ) );
+    }
+
+
+    /** The version's REVISION component. */
+    private String revision = "0";
+
+
+    /** The version's REVISION component as an integer. */
+    private int getRevisionAsInt() {
+        return Integer.parseInt( revision );
+    }
+
+
+    /**
+     * Sets the version's REVISION component.
+     *
+     * @param toSet The version's REVISION component.
+     *
+     * @throws IllegalArgumentException When a null or non-numeric value is given.
+     */
+    public void setRevision( String toSet ) throws IllegalArgumentException {
+        if ( StringUtils.isEmpty( toSet ) ) {
+            throw new IllegalArgumentException( "Argument is null" );
+        }
+
+        if ( !toSet.matches( "\\d+" ) ) {
+            throw new IllegalArgumentException( "Argument is not numeric" );
+        }
+
+        if ( numberOfComponents < 4 ) {
+            numberOfComponents = 4;
+        }
+
+        revision = toSet;
+    }
+
+
+    /**
+     * The number of components that make up the version. The value will always be between 1 (inclusive) and 4
+     * (inclusive).
+     */
+    private int numberOfComponents;
+
+
+    @Override
+    @SuppressWarnings("all")
+    public Object clone() throws CloneNotSupportedException {
+        Version v = new Version();
+
+        v.rawVersion = rawVersion;
+        v.prefix = prefix;
+        v.suffix = suffix;
+
+        v.numberOfComponents = numberOfComponents;
+
+        v.major = major;
+        v.minor = minor;
+        v.build = build;
+        v.revision = revision;
+
+        return v;
+    }
+
+
+    @Override
+    public boolean equals( Object toCompare ) {
+        // Compare pointers
+        if ( toCompare == this ) {
+            return true;
+        }
+
+        // Compare types
+        if ( !( toCompare instanceof Version ) ) {
+            return false;
+        }
+
+        return compareTo( ( Version ) toCompare ) == 0;
+    }
+
+
+    @Override
+    public int hashCode() {
+        return toString().hashCode();
+    }
+
+
+    @Override
+    public String toString() {
+        return String.format( "%s.%s.%s.%s", major, minor, build, revision );
+    }
+
+
+    /**
+     * Gets the version as a string using the specified number of components.
+     *
+     * @param components The number of components. Values less than 1 will be treated as 1 and values greater than 4
+     * will be treated as 4.
+     *
+     * @return The version as a string using the specified number of components.
+     */
+    public String toString( int components ) {
+        StringBuilder buff = new StringBuilder();
+        buff.append( major );
+
+        if ( components > 4 ) {
+            components = 4;
+        }
+
+        switch ( components ) {
+            case 2:
+                buff.append( String.format( ".%s", minor ) );
+                break;
+            case 3:
+                buff.append( String.format( ".%s.%s", minor, build ) );
+                break;
+            case 4:
+                buff.append( String.format( ".%s.%s.%s", minor, build, revision ) );
+                break;
+            default:
+                break;
+        }
+
+        return buff.toString();
+    }
+
+
+    private int compareInts( int x, int y ) {
+        if ( x == y ) {
+            return 0;
+        }
+
+        if ( x < y ) {
+            return -1;
+        }
+
+        return 1;
+    }
+
+
+    @Override
+    public int compareTo( Version toCompare ) {
+        int result = toString().compareTo( toCompare.toString() );
+
+        if ( result == 0 ) {
+            return result;
+        }
+
+        result = compareInts( getMajorAsInt(), toCompare.getMajorAsInt() );
+
+        if ( result != 0 ) {
+            return result;
+        }
+
+        result = compareInts( getMinorAsInt(), toCompare.getMinorAsInt() );
+
+        if ( result != 0 ) {
+            return result;
+        }
+
+        result = compareInts( getBuildAsInt(), toCompare.getBuildAsInt() );
+
+        if ( result != 0 ) {
+            return result;
+        }
+
+        result = compareInts( getRevisionAsInt(), toCompare.getRevisionAsInt() );
+
+        if ( result != 0 ) {
+            return result;
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/utils/package-info.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/utils/package-info.java b/stack/core/src/main/java/org/apache/usergrid/utils/package-info.java
new file mode 100644
index 0000000..4936523
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/utils/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/AppArgs.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/AppArgs.java b/stack/core/src/main/java/org/usergrid/batch/AppArgs.java
deleted file mode 100644
index 55b6efe..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/AppArgs.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.usergrid.batch;
-
-
-import com.beust.jcommander.JCommander;
-import com.beust.jcommander.Parameter;
-
-
-/** @author zznate */
-public class AppArgs {
-
-    @Parameter(names = "-host", description = "The Cassandra host to which we will connect")
-    private String host = "127.0.0.1";
-
-    @Parameter(names = "-port", description = "The port which we will connect")
-    private int port = 9160;
-
-    @Parameter(names = "-workerThreads", description = "The number of worker threads")
-    private int workerThreads = 4;
-
-    @Parameter(names = "-sleepFor", description = "Number of seconds to sleep between checks of the work queue")
-    private int sleepFor = 2;
-
-    @Parameter(names = "-appContext", description = "Location of Spring Application context files")
-    private String appContext;
-
-
-    public static AppArgs parseArgs( String[] args ) {
-        AppArgs appArgs = new AppArgs();
-        JCommander jcommander = new JCommander( appArgs, args );
-        return appArgs;
-    }
-
-
-    public String getHost() {
-        return host;
-    }
-
-
-    public int getPort() {
-        return port;
-    }
-
-
-    public int getWorkerThreads() {
-        return workerThreads;
-    }
-
-
-    public int getSleepFor() {
-        return sleepFor;
-    }
-
-
-    public String getAppContext() {
-        return appContext;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/Job.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/Job.java b/stack/core/src/main/java/org/usergrid/batch/Job.java
deleted file mode 100644
index 34240c8..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/Job.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.usergrid.batch;
-
-
-/**
- * Defines only an execute method. Implementation functionality is completely up to the {@link JobFactory}
- *
- * @author zznate
- */
-public interface Job {
-
-    /**
-     * Invoked when a job should execute
-     *
-     * @param execution The execution information.  This will be the same from the last run.  By default you should call
-     * exeuction.start() once processing starts
-     *
-     * @throws JobExecutionException If the job cannot be executed
-     */
-    public void execute( JobExecution execution ) throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/JobExecution.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/JobExecution.java b/stack/core/src/main/java/org/usergrid/batch/JobExecution.java
deleted file mode 100644
index 150de17..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/JobExecution.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*******************************************************************************
- * Copyright 2012 Apigee Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- ******************************************************************************/
-package org.usergrid.batch;
-
-
-import java.util.UUID;
-
-import org.usergrid.persistence.entities.JobData;
-import org.usergrid.persistence.entities.JobStat;
-
-
-/**
- * Interface to define all operations possible during a job execution. The job execution has several states.
- * <p/>
- * <p/>
- * The Execution has the following state transitions
- * <p/>
- * NOT_STARTED->IN_PROGRESS
- * <p/>
- * <p/>
- * IN_PROGRESS->COMPLETED <br/> IN_PROGRESS->FAILED <br/> IN_PROGRESS->DEAD
- * <p/>
- * FAILED->IN_PROGRESS
- *
- * @author tnine
- */
-public interface JobExecution {
-
-    /** Retry constant to signal the job should try forever */
-    public static final int FOREVER = -1;
-
-    /** Get the data for this execution */
-    public JobData getJobData();
-
-    /** Get the job statistic information */
-    public JobStat getJobStats();
-
-    /** Marke the job as started.  If it's failed too many times, don't run it */
-    public void start( int maxFailures );
-
-    /** Mark the job as successfully completed */
-    public void completed();
-
-    /** Mark the job as failed. If it has failed more than maxFailures, mark it as dead */
-    public void failed();
-
-    /** Mark the job as dead */
-    public void killed();
-
-    /** Provide a heartbeat to the job execution to keep it alive */
-    public void heartbeat();
-
-    /** Signal the execution is still running, and delay the timeout for the milliseconds specified */
-    public void heartbeat( long milliseconds );
-
-    /**
-     * Don't treat the execution as complete.  Simply delay execution for the specified milliseconds.  Similar to
-     * heartbeat but allows the user to specify the timeout for the next attempt instead of the heartbeat default.  This
-     * DOES NOT update locks, so your job should use distributed locking internally to ensure single execution
-     */
-    public void delay( long milliseconds );
-
-    /** Get the current status of the execution */
-    public Status getStatus();
-
-    /** Get the name of the job */
-    public String getJobName();
-
-    /** Get the job id */
-    public UUID getJobId();
-
-    /** Get the current transaction Id from the heartbeat */
-    public UUID getTransactionId();
-
-    public enum Status {
-        NOT_STARTED, IN_PROGRESS, COMPLETED, FAILED, DEAD, DELAYED
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/JobExecutionImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/JobExecutionImpl.java b/stack/core/src/main/java/org/usergrid/batch/JobExecutionImpl.java
deleted file mode 100644
index d5aecfc..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/JobExecutionImpl.java
+++ /dev/null
@@ -1,202 +0,0 @@
-package org.usergrid.batch;
-
-
-import java.util.UUID;
-
-import org.usergrid.batch.repository.JobDescriptor;
-import org.usergrid.batch.service.JobRuntimeService;
-import org.usergrid.persistence.entities.JobData;
-import org.usergrid.persistence.entities.JobStat;
-
-import com.google.common.base.Preconditions;
-
-
-/**
- * Models the execution context of the {@link Job} with state transition methods for job status.
- *
- * @author zznate
- * @author tnine
- */
-public class JobExecutionImpl implements JobExecution, JobRuntime {
-
-    private final UUID jobId;
-    private final UUID runId;
-    private final String jobName;
-    private long duration;
-    private Status status = Status.NOT_STARTED;
-    private long startTime;
-    private JobRuntimeService runtime;
-    private UUID transactionId;
-    private JobData data;
-    private JobStat stats;
-    private long delay = -1;
-
-
-    public JobExecutionImpl( JobDescriptor jobDescriptor ) {
-        this.runId = UUID.randomUUID();
-        this.jobId = jobDescriptor.getJobId();
-        this.runtime = jobDescriptor.getRuntime();
-        this.jobName = jobDescriptor.getJobName();
-        this.transactionId = jobDescriptor.getTransactionId();
-        this.data = jobDescriptor.getData();
-        this.stats = jobDescriptor.getStats();
-    }
-
-
-    public UUID getRunId() {
-        return runId;
-    }
-
-
-    public long getDuration() {
-        return duration;
-    }
-
-
-    /** @param transactionId the transactionId to set */
-    public void setTransactionId( UUID transactionId ) {
-        this.transactionId = transactionId;
-    }
-
-
-    public UUID getJobId() {
-        return jobId;
-    }
-
-
-    /** @return the data */
-    public JobData getJobData() {
-        return data;
-    }
-
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see org.usergrid.batch.JobExecution#getJobStats()
-     */
-    @Override
-    public JobStat getJobStats() {
-        return stats;
-    }
-
-
-    public void start( int maxFailures ) {
-        Preconditions.checkState( this.status.equals( Status.NOT_STARTED ) || this.status.equals( Status.FAILED ),
-                "Attempted to start job in progress" );
-        this.status = Status.IN_PROGRESS;
-
-        stats.incrementRuns();
-
-
-        // use >= in case the threshold lowers after the job has passed the failure
-        // mark
-        if ( maxFailures != FOREVER && stats.getTotalAttempts() > maxFailures ) {
-            status = Status.DEAD;
-        }
-
-        startTime = System.currentTimeMillis();
-        stats.setStartTime( startTime );
-    }
-
-
-    public void completed() {
-        updateState( Status.IN_PROGRESS, "Attempted to complete job not in progress", Status.COMPLETED );
-        stats.setDuration( duration );
-    }
-
-
-    /**
-     * Mark this execution as failed. Also pass the maxium number of possible failures. Set to JobExecution.FOREVER for
-     * no limit
-     */
-    public void failed() {
-        updateState( Status.IN_PROGRESS, "Attempted to fail job not in progress", Status.FAILED );
-    }
-
-
-    /** This job should be killed and not retried */
-    public void killed() {
-        updateState( Status.IN_PROGRESS, "Attempted to fail job not in progress", Status.DEAD );
-    }
-
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see org.usergrid.batch.JobExecution#delay(long)
-     */
-    @Override
-    public void delay( long delay ) {
-        updateState( Status.IN_PROGRESS, "Attempted to delay a job not in progress", Status.DELAYED );
-        stats.incrementDelays();
-        this.delay = delay;
-        runtime.delay( this );
-    }
-
-
-    /** Update our state */
-    private void updateState( Status expected, String message, Status newStatus ) {
-        Preconditions.checkState( this.status.equals( expected ), message );
-        this.status = newStatus;
-        duration = System.currentTimeMillis() - startTime;
-    }
-
-
-    /** Make sure we're in progress and notifiy the scheduler we're still running */
-    public void heartbeat() {
-        Preconditions
-                .checkState( this.status.equals( Status.IN_PROGRESS ), "Attempted to heartbeat job not in progress" );
-        runtime.heartbeat( this );
-    }
-
-
-    /* (non-Javadoc)
-     * @see org.usergrid.batch.JobExecution#heartbeat(long)
-     */
-    @Override
-    public void heartbeat( long milliseconds ) {
-        Preconditions
-                .checkState( this.status.equals( Status.IN_PROGRESS ), "Attempted to heartbeat job not in progress" );
-        runtime.heartbeat( this, milliseconds );
-        this.delay = milliseconds;
-    }
-
-
-    /** @return the startTime */
-    public long getStartTime() {
-        return startTime;
-    }
-
-
-    /** @return the transactionId */
-    public UUID getTransactionId() {
-        return transactionId;
-    }
-
-
-    public Status getStatus() {
-        return this.status;
-    }
-
-
-    /** @return the delay */
-    public long getDelay() {
-        return delay;
-    }
-
-
-    /** @return the jobName */
-    public String getJobName() {
-        return jobName;
-    }
-
-
-    /* (non-Javadoc)
-     * @see org.usergrid.batch.JobRuntime#getExecution()
-     */
-    @Override
-    public JobExecution getExecution() {
-        return this;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/JobFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/JobFactory.java b/stack/core/src/main/java/org/usergrid/batch/JobFactory.java
deleted file mode 100644
index 6154858..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/JobFactory.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.usergrid.batch;
-
-
-import java.util.List;
-
-import org.usergrid.batch.repository.JobDescriptor;
-
-
-/**
- * It is up to the implementation how many BulkJob instances to return, but this should be controled by the
- * BulkJobsBuilder
- *
- * @author zznate
- */
-public interface JobFactory {
-
-    /** Return one or more BulkJob ready for execution by a worker thread */
-    List<Job> jobsFrom( JobDescriptor descriptor ) throws JobNotFoundException;
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/JobNotFoundException.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/JobNotFoundException.java b/stack/core/src/main/java/org/usergrid/batch/JobNotFoundException.java
deleted file mode 100644
index 9b806c5..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/JobNotFoundException.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.usergrid.batch;
-
-
-/**
- * Created when a job cannot be instantiated.  This usually occurs during the deploy of new code on nodes that don't yet
- * have the job implementation.  Nodes receiving this message should log it and move on.
- *
- * @author tnine
- */
-public class JobNotFoundException extends Exception {
-
-    /**
-     *
-     */
-    private static final long serialVersionUID = -67437852214725320L;
-
-    private static final String DEF_MSG = "Unable to find the job with name %s";
-
-
-    public JobNotFoundException( String jobName ) {
-        super( String.format( DEF_MSG, jobName ) );
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/JobRuntime.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/JobRuntime.java b/stack/core/src/main/java/org/usergrid/batch/JobRuntime.java
deleted file mode 100644
index 9244878..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/JobRuntime.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright 2012 Apigee Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- ******************************************************************************/
-package org.usergrid.batch;
-
-
-import java.util.UUID;
-
-
-/**
- * Interface to define all operations possible during a job's specific runtime
- *
- * @author tnine
- */
-public interface JobRuntime {
-
-    /** Set the transaction id for this job's runtime */
-    public void setTransactionId( UUID transactionId );
-
-    /** Get the transaction id of the run time */
-    public UUID getTransactionId();
-
-    /** Get the delay of the run time */
-    public long getDelay();
-
-    /** Get the job execution */
-    public JobExecution getExecution();
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/JobRuntimeException.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/JobRuntimeException.java b/stack/core/src/main/java/org/usergrid/batch/JobRuntimeException.java
deleted file mode 100644
index f641b2f..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/JobRuntimeException.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.usergrid.batch;
-
-
-/**
- * Created when a job cannot be instantiated.  This usually occurs during the deploy of new code on nodes that don't yet
- * have the job implementation.  Nodes receiving this message should log it and move on.
- *
- * @author tnine
- */
-public class JobRuntimeException extends RuntimeException {
-
-    /**
-     *
-     */
-    private static final long serialVersionUID = 1;
-
-
-    /**
-     *
-     */
-    public JobRuntimeException() {
-        super();
-    }
-
-
-    /**
-     * @param arg0
-     * @param arg1
-     */
-    public JobRuntimeException( String arg0, Throwable arg1 ) {
-        super( arg0, arg1 );
-    }
-
-
-    /**
-     * @param arg0
-     */
-    public JobRuntimeException( String arg0 ) {
-        super( arg0 );
-    }
-
-
-    /**
-     * @param arg0
-     */
-    public JobRuntimeException( Throwable arg0 ) {
-        super( arg0 );
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/UsergridJobFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/UsergridJobFactory.java b/stack/core/src/main/java/org/usergrid/batch/UsergridJobFactory.java
deleted file mode 100644
index 951d10d..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/UsergridJobFactory.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.usergrid.batch;
-
-
-import java.util.Collections;
-import java.util.List;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.ApplicationContext;
-import org.usergrid.batch.repository.JobDescriptor;
-
-
-/** @author tnine */
-public class UsergridJobFactory implements JobFactory {
-
-    @Autowired
-    private ApplicationContext context;
-
-    private Logger logger = LoggerFactory.getLogger( UsergridJobFactory.class );
-
-
-    @Override
-    public List<Job> jobsFrom( JobDescriptor descriptor ) throws JobNotFoundException {
-
-        Job job = context.getBean( descriptor.getJobName(), Job.class );
-
-        if ( job == null ) {
-            String error =
-                    String.format( "Could not find job impelmentation for job name %s", descriptor.getJobName() );
-            logger.error( error );
-            throw new JobNotFoundException( error );
-        }
-
-        return Collections.singletonList( job );
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/job/OnlyOnceJob.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/job/OnlyOnceJob.java b/stack/core/src/main/java/org/usergrid/batch/job/OnlyOnceJob.java
deleted file mode 100644
index 4b1c3c3..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/job/OnlyOnceJob.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*******************************************************************************
- * Copyright 2012 Apigee Corporation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- ******************************************************************************/
-package org.usergrid.batch.job;
-
-
-import java.util.concurrent.TimeUnit;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import org.usergrid.batch.Job;
-import org.usergrid.batch.JobExecution;
-import org.usergrid.locking.Lock;
-import org.usergrid.locking.LockManager;
-
-import static org.usergrid.persistence.cassandra.CassandraService.MANAGEMENT_APPLICATION_ID;
-
-
-/**
- * Simple abstract job class that performs additional locking to ensure that the job is only executing once. This can be
- * used if your job could potentially be too slow to invoke JobExceution.heartbeat() before the timeout passes.
- *
- * @author tnine
- */
-@Component("OnlyOnceJob")
-public abstract class OnlyOnceJob implements Job {
-
-    @Autowired
-    private LockManager lockManager;
-
-
-    /**
-     *
-     */
-    public OnlyOnceJob() {
-    }
-
-
-    /*
-     * (non-Javadoc)
-     *
-     * @see org.usergrid.batch.Job#execute(org.usergrid.batch.JobExecution)
-     */
-    @Override
-    public void execute( JobExecution execution ) throws Exception {
-
-        String lockId = execution.getJobId().toString();
-
-        Lock lock = lockManager.createLock( MANAGEMENT_APPLICATION_ID, String.format( "/jobs/%s", lockId ) );
-
-        // the job is still running somewhere else. Try again in getDelay() milliseconds
-        if ( !lock.tryLock( 0, TimeUnit.MILLISECONDS ) ) {
-            execution.delay( getDelay( execution ) );
-            return;
-        }
-
-        //if we get here we can proceed.  Make sure we unlock no matter what.
-        try {
-
-            doJob( execution );
-        }
-        finally {
-            lock.unlock();
-        }
-    }
-
-
-    /** Delegate the job execution to the subclass */
-    protected abstract void doJob( JobExecution execution ) throws Exception;
-
-    /** Get the delay for the next run if we can't acquire the lock */
-    protected abstract long getDelay( JobExecution execution ) throws Exception;
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/job/package-info.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/job/package-info.java b/stack/core/src/main/java/org/usergrid/batch/job/package-info.java
deleted file mode 100644
index 8095857..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/job/package-info.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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.usergrid.batch.job;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/repository/JobAccessor.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/repository/JobAccessor.java b/stack/core/src/main/java/org/usergrid/batch/repository/JobAccessor.java
deleted file mode 100644
index bc6e7dd..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/repository/JobAccessor.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.usergrid.batch.repository;
-
-
-import java.util.List;
-
-import org.usergrid.batch.JobExecution;
-
-
-public interface JobAccessor {
-
-    /** Get new jobs, with a max return value of size */
-    List<JobDescriptor> getJobs( int size );
-
-    /** Save job execution information */
-    void save( JobExecution bulkJobExecution );
-
-    /** Don't remove the execution, but rather schedule it to be fired after the given delay */
-    void delayRetry( JobExecution execution, long delay );
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/repository/JobDescriptor.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/repository/JobDescriptor.java b/stack/core/src/main/java/org/usergrid/batch/repository/JobDescriptor.java
deleted file mode 100644
index b245a89..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/repository/JobDescriptor.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package org.usergrid.batch.repository;
-
-
-import java.util.UUID;
-
-import org.usergrid.batch.service.JobRuntimeService;
-import org.usergrid.persistence.TypedEntity;
-import org.usergrid.persistence.entities.JobData;
-import org.usergrid.persistence.entities.JobStat;
-
-import me.prettyprint.cassandra.utils.Assert;
-
-
-/**
- * @author zznate
- * @author tnine
- */
-public class JobDescriptor extends TypedEntity {
-
-    private final String jobName;
-    private final UUID jobId;
-    private final UUID transactionId;
-    private final JobData data;
-    private final JobStat stats;
-    private final JobRuntimeService runtime;
-
-
-    public JobDescriptor( String jobName, UUID jobId, UUID transactionId, JobData data, JobStat stats,
-                          JobRuntimeService runtime ) {
-        Assert.notNull( jobName, "Job name cannot be null" );
-        Assert.notNull( jobId != null, "A JobId is required" );
-        Assert.notNull( transactionId != null, "A transactionId is required" );
-        Assert.notNull( data != null, "Data is required" );
-        Assert.notNull( stats != null, "Stats are required" );
-        Assert.notNull( runtime != null, "A scheduler is required" );
-
-        this.jobName = jobName;
-        this.jobId = jobId;
-        this.transactionId = transactionId;
-        this.data = data;
-        this.stats = stats;
-        this.runtime = runtime;
-    }
-
-
-    /** @return the jobName */
-    public String getJobName() {
-        return jobName;
-    }
-
-
-    /** @return the jobId */
-    public UUID getJobId() {
-        return jobId;
-    }
-
-
-    /** @return the transactionId */
-    public UUID getTransactionId() {
-        return transactionId;
-    }
-
-
-    /** @return the data */
-    public JobData getData() {
-        return data;
-    }
-
-
-    /** @return the scheduler */
-    public JobRuntimeService getRuntime() {
-        return runtime;
-    }
-
-
-    /** @return the stats */
-    public JobStat getStats() {
-        return stats;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/repository/package-info.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/repository/package-info.java b/stack/core/src/main/java/org/usergrid/batch/repository/package-info.java
deleted file mode 100644
index ec6565a..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/repository/package-info.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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.usergrid.batch.repository;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/service/App.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/service/App.java b/stack/core/src/main/java/org/usergrid/batch/service/App.java
deleted file mode 100644
index ba7eb09..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/service/App.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.usergrid.batch.service;
-
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.context.support.FileSystemXmlApplicationContext;
-
-import com.google.common.base.CharMatcher;
-
-
-/**
- * Entry point for CLI functions of Usergrid batch framework
- * <p/>
- * To run this with the built-in examples, invoke it thusly from the top level of the project directory:
- * <p/>
- * mvn -e exec:java -Dexec.mainClass="org.usergrid.batch.App" -Dexec.args="-appContext
- * src/test/resources/appContext.xml"
- *
- * @author zznate
- */
-public class App {
-
-    private static Logger logger = LoggerFactory.getLogger( App.class );
-
-    private ApplicationContext appContext;
-    private final org.usergrid.batch.AppArgs appArgs;
-
-
-    public static void main( String[] args ) {
-        org.usergrid.batch.AppArgs appArgs = org.usergrid.batch.AppArgs.parseArgs( args );
-        if ( logger.isDebugEnabled() ) {
-            logger.debug( "Invoked App with appArgs: {}", appArgs.toString() );
-        }
-
-        App app = new App( appArgs );
-
-        app.loadContext();
-
-        logger.info( "Context loaded, invoking execute() ..." );
-        app.doExecute();
-    }
-
-
-    App( org.usergrid.batch.AppArgs appArgs ) {
-        this.appArgs = appArgs;
-    }
-
-
-    private void loadContext() {
-        logger.info( "loading context" );
-        // spring context
-        int index = CharMatcher.is( ':' ).indexIn( appArgs.getAppContext() );
-        if ( index > 0 ) {
-            appContext = new ClassPathXmlApplicationContext( appArgs.getAppContext().substring( ++index ) );
-        }
-        else {
-            appContext = new FileSystemXmlApplicationContext( appArgs.getAppContext() );
-        }
-    }
-
-
-    private void doExecute() {
-        JobSchedulerService bjss = appContext.getBean( "bulkJobScheduledService", JobSchedulerService.class );
-        logger.info( "starting scheduledService..." );
-        bjss.startAndWait();
-        logger.info( "scheduledService started." );
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/service/JobListener.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/service/JobListener.java b/stack/core/src/main/java/org/usergrid/batch/service/JobListener.java
deleted file mode 100644
index 9e0a8b2..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/service/JobListener.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.usergrid.batch.service;
-
-
-import org.usergrid.batch.JobExecution;
-
-
-/**
- * Job callbacks in the @{link #SchedularService} are propagated to
- * registered implementations of this JobListener.
- */
-public interface JobListener {
-
-    /**
-     * Submission of job execution notified onSubmit.
-     *
-     * @param execution the submitted JobExecution
-     */
-    void onSubmit( JobExecution execution );
-
-    /**
-     * Successful executions of a Job notify onSuccess.
-     *
-     * @param execution the JobExection associated with the Job
-     */
-    void onSuccess( JobExecution execution );
-
-    /**
-     * Execution failures of a Job notify onFailure.
-     *
-     * @param execution the JobExection associated with the Job
-     */
-    void onFailure( JobExecution execution );
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/usergrid/batch/service/JobRuntimeService.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/usergrid/batch/service/JobRuntimeService.java b/stack/core/src/main/java/org/usergrid/batch/service/JobRuntimeService.java
deleted file mode 100644
index 3a4f191..0000000
--- a/stack/core/src/main/java/org/usergrid/batch/service/JobRuntimeService.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.usergrid.batch.service;
-
-
-import org.usergrid.batch.JobRuntime;
-
-
-/**
- * Methods to allow job executions to interact with the distributed runtime.
- */
-public interface JobRuntimeService {
-
-    /**
-     * Perform any heartbeat operations required.  Update jobExecution with the appropriate data
-     *
-     * @param execution The job execution to update
-     * @param delay The delay
-     */
-    void heartbeat( JobRuntime execution, long delay );
-
-    /**
-     * Heartbeat with the system defaults.  Update jobExecution with the appropriate data
-     *
-     * @param execution The execution
-     */
-    void heartbeat( JobRuntime execution );
-
-    /**
-     * Delay this execution.
-     *
-     * @param execution the execution to delay
-     */
-    void delay( JobRuntime execution );
-}