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:59 UTC

[49/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/count/BatchSubmitter.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/BatchSubmitter.java b/stack/core/src/main/java/org/apache/usergrid/count/BatchSubmitter.java
new file mode 100644
index 0000000..0fd7965
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/BatchSubmitter.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count;
+
+
+import java.util.Collection;
+import java.util.concurrent.Future;
+
+import org.apache.usergrid.count.common.Count;
+
+
+/** @author zznate */
+public interface BatchSubmitter {
+    Future<?> submit( Collection<Count> counts );
+
+    void shutdown();
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/Batcher.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/Batcher.java b/stack/core/src/main/java/org/apache/usergrid/count/Batcher.java
new file mode 100644
index 0000000..bef03e1
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/Batcher.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count;
+
+
+import org.apache.usergrid.count.common.Count;
+
+
+/**
+ * Defines minimal set of batch submission operations
+ *
+ * @author zznate
+ */
+public interface Batcher {
+    void setBatchSubmitter( BatchSubmitter batchSubmitter );
+
+    void add( Count count );
+
+    long getOpCount();
+
+    long getBatchSubmissionCount();
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/CassandraCounterStore.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/CassandraCounterStore.java b/stack/core/src/main/java/org/apache/usergrid/count/CassandraCounterStore.java
new file mode 100644
index 0000000..26d610d
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/CassandraCounterStore.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count;
+
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.usergrid.count.common.Count;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import me.prettyprint.cassandra.model.HCounterColumnImpl;
+import me.prettyprint.cassandra.serializers.ByteBufferSerializer;
+import me.prettyprint.hector.api.Keyspace;
+import me.prettyprint.hector.api.factory.HFactory;
+import me.prettyprint.hector.api.mutation.Mutator;
+
+
+/**
+ * Encapsulate counter writes to Cassandra
+ *
+ * @author zznate
+ */
+public class CassandraCounterStore implements CounterStore {
+    private Logger log = LoggerFactory.getLogger( CassandraCounterStore.class );
+
+    // keep track of exceptions thrown in scheduler so we can reduce noise in logs
+    private Map<String, Integer> counterInsertFailures = new HashMap<String, Integer>();
+
+    private final Keyspace keyspace;
+
+
+    public CassandraCounterStore( Keyspace keyspace ) {
+        this.keyspace = keyspace;
+    }
+
+
+    public void save( Count count ) {
+        this.save( Arrays.asList( count ) );
+    }
+
+
+    public void save( Collection<Count> counts ) {
+        Map<String, Count> countHolder = new HashMap<String, Count>();
+        for ( Count count : counts ) {
+            Count c = countHolder.get( count.getCounterName() );
+            if ( c != null ) {
+                c.apply( count );
+            }
+            else {
+                countHolder.put( count.getCounterName(), count );
+            }
+        }
+        Mutator<ByteBuffer> mutator = HFactory.createMutator( keyspace, ByteBufferSerializer.get() );
+        for ( Count count : countHolder.values() ) {
+            mutator.addCounter( count.getKeyNameBytes(), count.getTableName(),
+                    new HCounterColumnImpl( count.getColumnName(), count.getValue(),
+                            count.getColumnNameSerializer() ) );
+        }
+        try {
+            mutator.execute();
+        }
+        catch ( Exception e ) {
+
+            // errors here happen a lot on shutdown, don't fill the logs with them
+            String error = e.getClass().getCanonicalName();
+            if (counterInsertFailures.get( error ) == null) {
+                log.error( "CounterStore insert failed, first instance", e);
+                counterInsertFailures.put( error, 1);
+
+            } else {
+                int count = counterInsertFailures.get(error) + 1; 
+                counterInsertFailures.put(error, count);
+                if (log.isDebugEnabled()) {
+                    log.debug( error + " caused CounterStore insert failure, count =  " + count, e );
+                } else {
+                    log.error( error + " caused CounterStore insert failure, count =  " + count );
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/CassandraSubmitter.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/CassandraSubmitter.java b/stack/core/src/main/java/org/apache/usergrid/count/CassandraSubmitter.java
new file mode 100644
index 0000000..13f72c1
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/CassandraSubmitter.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count;
+
+
+import java.util.Collection;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.usergrid.count.common.Count;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.yammer.metrics.Metrics;
+import com.yammer.metrics.core.Timer;
+import com.yammer.metrics.core.TimerContext;
+
+
+/**
+ * Submits directly to Cassandra for insertion
+ *
+ * @author zznate
+ */
+public class CassandraSubmitter implements BatchSubmitter {
+    private final Logger log = LoggerFactory.getLogger( CassandraSubmitter.class );
+
+    private final int threadCount = 3;
+    private final CassandraCounterStore cassandraCounterStore;
+
+    private final ExecutorService executor = Executors.newFixedThreadPool( threadCount );
+    private final Timer addTimer =
+            Metrics.newTimer( CassandraSubmitter.class, "submit_invocation", TimeUnit.MICROSECONDS, TimeUnit.SECONDS );
+
+
+    public CassandraSubmitter( CassandraCounterStore cassandraCounterStore ) {
+        this.cassandraCounterStore = cassandraCounterStore;
+    }
+
+
+    @Override
+    public Future submit( final Collection<Count> counts ) {
+        return executor.submit( new Callable<Object>() {
+            final TimerContext timer = addTimer.time();
+
+
+            @Override
+            public Object call() throws Exception {
+                cassandraCounterStore.save( counts );
+                timer.stop();
+                return true;
+            }
+        } );
+    }
+
+
+    @Override
+    public void shutdown() {
+        log.warn( "Shutting down CassandraSubmitter" );
+        executor.shutdown();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/CountProducer.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/CountProducer.java b/stack/core/src/main/java/org/apache/usergrid/count/CountProducer.java
new file mode 100644
index 0000000..6bbe3dc
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/CountProducer.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count;
+
+
+import org.apache.usergrid.count.common.Count;
+
+
+/** @author zznate */
+public interface CountProducer {
+    void send( Count count );
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/CounterProcessingUnavailableException.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/CounterProcessingUnavailableException.java b/stack/core/src/main/java/org/apache/usergrid/count/CounterProcessingUnavailableException.java
new file mode 100644
index 0000000..50b9593
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/CounterProcessingUnavailableException.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count;
+
+
+/** @author zznate */
+public class CounterProcessingUnavailableException extends RuntimeException {
+
+    private static final String ERR_MSG = "Counter was not processed. Reason: ";
+
+
+    public CounterProcessingUnavailableException() {
+        super( ERR_MSG );
+    }
+
+
+    public CounterProcessingUnavailableException( String errMsg ) {
+        super( ERR_MSG + errMsg );
+    }
+
+
+    public CounterProcessingUnavailableException( String errMsg, Throwable t ) {
+        super( ERR_MSG + errMsg, t );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/CounterStore.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/CounterStore.java b/stack/core/src/main/java/org/apache/usergrid/count/CounterStore.java
new file mode 100644
index 0000000..595b55b
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/CounterStore.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count;
+
+
+import java.util.Collection;
+
+import org.apache.usergrid.count.common.Count;
+
+
+/** @author zznate */
+public interface CounterStore {
+    // TODO consider inforcing Async via Future<T> as return type
+    void save( Count count );
+
+    void save( Collection<Count> counts );
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/SimpleBatcher.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/SimpleBatcher.java b/stack/core/src/main/java/org/apache/usergrid/count/SimpleBatcher.java
new file mode 100644
index 0000000..6d685a9
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/SimpleBatcher.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count;
+
+
+import org.apache.usergrid.count.common.Count;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A simple Batcher implementation that keeps a sum of the number of {@link Count} operations which have been applied.
+ * Counters are aggregated by name.
+ *
+ * @author zznate
+ */
+public class SimpleBatcher extends AbstractBatcher {
+    private Logger log = LoggerFactory.getLogger( SimpleBatcher.class );
+
+    private boolean blockingSubmit = false;
+
+
+    public void setBlockingSubmit( boolean blockingSubmit ) {
+        this.blockingSubmit = blockingSubmit;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/Slf4JBatchSubmitter.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/Slf4JBatchSubmitter.java b/stack/core/src/main/java/org/apache/usergrid/count/Slf4JBatchSubmitter.java
new file mode 100644
index 0000000..bbfb5d1
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/Slf4JBatchSubmitter.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count;
+
+
+import java.util.Collection;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.usergrid.count.common.Count;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.yammer.metrics.Metrics;
+import com.yammer.metrics.core.Timer;
+import com.yammer.metrics.core.TimerContext;
+
+
+/**
+ * A BatchSubmitter that prints contents to the configured slf4j logger logger
+ *
+ * @author zznate
+ */
+public class Slf4JBatchSubmitter implements BatchSubmitter {
+
+    // TODO custom logger for printing counts
+    // - should be configed programatically
+    private Logger log = LoggerFactory.getLogger( Slf4JBatchSubmitter.class );
+
+    private int threadCount = 3;
+
+    private ExecutorService executor = Executors.newFixedThreadPool( threadCount );
+    private final Timer addTimer =
+            Metrics.newTimer( Slf4JBatchSubmitter.class, "submit_invocation", TimeUnit.MICROSECONDS, TimeUnit.SECONDS );
+
+
+    @Override
+    public Future submit( final Collection<Count> counts ) {
+        return executor.submit( new Callable<Object>() {
+            final TimerContext timer = addTimer.time();
+
+
+            @Override
+            public Object call() throws Exception {
+                // TODO perhaps this could be pushed down further into CountProducer Impl?
+                // - this would leave generic submitter class
+                for ( Count c : counts ) {
+                    log.info( "found count {}", c );
+                }
+                timer.stop();
+                return true;
+            }
+        } );
+    }
+
+
+    public void shutdown() {
+        log.warn( "Shutdown Slf4jBatchSubmitter" );
+        executor.shutdown();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/common/Count.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/common/Count.java b/stack/core/src/main/java/org/apache/usergrid/count/common/Count.java
new file mode 100644
index 0000000..c912bbf
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/common/Count.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count.common;
+
+
+import java.nio.ByteBuffer;
+
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonCreator;
+import org.codehaus.jackson.annotate.JsonIgnore;
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang.StringUtils;
+
+import me.prettyprint.cassandra.serializers.SerializerTypeInferer;
+import me.prettyprint.cassandra.serializers.StringSerializer;
+import me.prettyprint.hector.api.Serializer;
+
+import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
+
+
+/**
+ * Loosely models a 'count' of things to
+ *
+ * @author zznate
+ */
+@JsonAutoDetect(creatorVisibility = Visibility.PUBLIC_ONLY)
+public class Count<K, C> {
+    private static final StringSerializer se = StringSerializer.get();
+
+    @JsonProperty
+    private final String tableName;
+    @JsonProperty
+    private final K keyName;
+    @JsonProperty
+    private final C columnName;
+    @JsonProperty
+    private long value;
+
+    private Serializer<K> keySerializer;
+    private Serializer<C> columnNameSerializer;
+    private String counterName;
+
+
+    @JsonCreator
+    public Count( @JsonProperty(value = "tableName") String tableName, @JsonProperty(value = "keyName") K keyName,
+                  @JsonProperty(value = "columnName") C columnName, @JsonProperty(value = "value") long value ) {
+        this.tableName = tableName;
+        this.keyName = keyName;
+        this.columnName = columnName;
+        this.value = value;
+        this.keySerializer = SerializerTypeInferer.getSerializer( keyName );
+        this.columnNameSerializer = SerializerTypeInferer.getSerializer( columnName );
+    }
+
+
+    public Count apply( Count count ) {
+        if ( !StringUtils.equals( count.getCounterName(), getCounterName() ) ) {
+            throw new IllegalArgumentException( "Attempt to apply a counter with a different name" );
+        }
+        this.value += count.getValue();
+        return this;
+    }
+
+
+    /** the counter name should uniquely identify the entity being counted. */
+    @JsonIgnore
+    public String getCounterName() {
+        if ( counterName == null ) {
+            counterName = tableName + ":" + Hex.encodeHexString( getKeyNameBytes().array() ) + ":" + Hex
+                    .encodeHexString( getColumnNameBytes().array() );
+        }
+        return counterName;
+    }
+
+
+    public long getValue() {
+        return value;
+    }
+
+
+    public C getColumnName() {
+        return columnName;
+    }
+
+
+    public K getKeyName() {
+        return keyName;
+    }
+
+
+    @JsonIgnore
+    public ByteBuffer getKeyNameBytes() {
+        return keySerializer.toByteBuffer( keyName );
+    }
+
+
+    @JsonIgnore
+    public ByteBuffer getColumnNameBytes() {
+        return columnNameSerializer.toByteBuffer( columnName );
+    }
+
+
+    @JsonIgnore
+    public Serializer<K> getKeySerializer() {
+        return keySerializer;
+    }
+
+
+    @JsonIgnore
+    public Serializer<C> getColumnNameSerializer() {
+        return columnNameSerializer;
+    }
+
+
+    public String getTableName() {
+        return tableName;
+    }
+
+
+    @Override
+    public String toString() {
+        return "Counter Name: ".concat( getCounterName() ).concat( " value: " ).concat( Long.toString( value ) );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/common/CountSerDeUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/common/CountSerDeUtils.java b/stack/core/src/main/java/org/apache/usergrid/count/common/CountSerDeUtils.java
new file mode 100644
index 0000000..84492dc
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/common/CountSerDeUtils.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count.common;
+
+
+import java.io.IOException;
+
+import org.codehaus.jackson.annotate.JsonAutoDetect;
+import org.codehaus.jackson.annotate.JsonMethod;
+import org.codehaus.jackson.map.ObjectMapper;
+
+
+/** @author zznate */
+public class CountSerDeUtils {
+
+    public static String serialize( Count count ) {
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            return mapper.writeValueAsString( count );
+        }
+        catch ( Exception ex ) {
+            throw new CountTransportSerDeException( "Problem in serialize() call", ex );
+        }
+    }
+
+
+    public static Count deserialize( String json ) {
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.setVisibility( JsonMethod.CREATOR, JsonAutoDetect.Visibility.ANY );
+
+        try {
+            return mapper.readValue( json, Count.class );
+        }
+        catch ( IOException e ) {
+            throw new CountTransportSerDeException( "Problem in deserialize() call", e );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/common/CountTransportSerDeException.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/common/CountTransportSerDeException.java b/stack/core/src/main/java/org/apache/usergrid/count/common/CountTransportSerDeException.java
new file mode 100644
index 0000000..e1b7188
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/common/CountTransportSerDeException.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.apache.usergrid.count.common;
+
+
+/** @author zznate */
+public class CountTransportSerDeException extends RuntimeException {
+    private static final String DEF_MSG =
+            "There was a serialization/deserialization problem in Count transport. Reason: ";
+
+
+    public CountTransportSerDeException() {
+        super( DEF_MSG );
+    }
+
+
+    public CountTransportSerDeException( String msg ) {
+        super( DEF_MSG + msg );
+    }
+
+
+    public CountTransportSerDeException( String msg, Throwable t ) {
+        super( DEF_MSG + msg, t );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/count/package-info.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/count/package-info.java b/stack/core/src/main/java/org/apache/usergrid/count/package-info.java
new file mode 100644
index 0000000..50e5957
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/count/package-info.java
@@ -0,0 +1 @@
+package org.apache.usergrid.count;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/exception/JsonReadException.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/exception/JsonReadException.java b/stack/core/src/main/java/org/apache/usergrid/exception/JsonReadException.java
new file mode 100644
index 0000000..7ddbfb4
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/exception/JsonReadException.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * 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.apache.usergrid.exception;
+
+
+public class JsonReadException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+
+    public JsonReadException( String msg, Throwable t ) {
+        super( msg, t );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/exception/JsonWriteException.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/exception/JsonWriteException.java b/stack/core/src/main/java/org/apache/usergrid/exception/JsonWriteException.java
new file mode 100644
index 0000000..4feb886
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/exception/JsonWriteException.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * 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.apache.usergrid.exception;
+
+
+public class JsonWriteException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+
+    public JsonWriteException( String msg, Throwable t ) {
+        super( msg, t );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/exception/NotImplementedException.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/exception/NotImplementedException.java b/stack/core/src/main/java/org/apache/usergrid/exception/NotImplementedException.java
new file mode 100644
index 0000000..17a6a6c
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/exception/NotImplementedException.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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.apache.usergrid.exception;
+
+
+public class NotImplementedException extends RuntimeException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     *
+     */
+    public NotImplementedException() {
+        super();
+    }
+
+
+    /**
+     * @param message
+     * @param cause
+     */
+    public NotImplementedException( String message, Throwable cause ) {
+        super( message, cause );
+    }
+
+
+    /**
+     * @param message
+     */
+    public NotImplementedException( String message ) {
+        super( message );
+    }
+
+
+    /**
+     * @param cause
+     */
+    public NotImplementedException( Throwable cause ) {
+        super( cause );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/Lock.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/Lock.java b/stack/core/src/main/java/org/apache/usergrid/locking/Lock.java
new file mode 100644
index 0000000..3826818
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/Lock.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking;
+
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.usergrid.locking.exception.UGLockException;
+
+
+/**
+ * The lock object to acquire
+ *
+ * @author tnine
+ */
+public interface Lock {
+
+    /**
+     * Acquire the lock.  Wait the specified amount of time before giving up
+     *
+     * @param timeout The amount of time to wait
+     * @param time the units of time to wait
+     */
+    public boolean tryLock( long timeout, TimeUnit time ) throws UGLockException;
+
+    /** Block until a lock is available */
+    public void lock() throws UGLockException;
+
+    /** Release the lock */
+    public void unlock() throws UGLockException;
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/LockHelper.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/LockHelper.java b/stack/core/src/main/java/org/apache/usergrid/locking/LockHelper.java
new file mode 100644
index 0000000..ac92ac4
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/LockHelper.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking;
+
+
+import java.util.UUID;
+
+import org.apache.commons.codec.binary.Hex;
+import org.apache.usergrid.locking.exception.UGLockException;
+import org.apache.usergrid.locking.noop.NoOpLockImpl;
+
+import static org.apache.usergrid.locking.LockPathBuilder.buildPath;
+import static org.apache.usergrid.utils.ConversionUtils.bytes;
+
+
+/** @author tnine */
+public class LockHelper {
+
+
+    private static final NoOpLockImpl NO_OP_LOCK = new NoOpLockImpl();
+
+
+    /**
+     * Build a string path for this lock.  Since it's specifically for updating a property, the property needs appended
+     * to the path.  If the property is null, it's getting deleted, so a lock on it isn't neccessary.  In that case, a
+     * no op lock is returned
+     */
+    public static Lock getUniqueUpdateLock( LockManager manager, UUID applicationId, Object value, String... path )
+            throws UGLockException {
+        //we have no value, therefore there's nothing to lock
+        if ( value == null ) {
+            return NO_OP_LOCK;
+        }
+
+        return manager.createLock( applicationId, buildPath( Hex.encodeHexString( bytes( value ) ), path ) );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/LockManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/LockManager.java b/stack/core/src/main/java/org/apache/usergrid/locking/LockManager.java
new file mode 100644
index 0000000..db7d079
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/LockManager.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking;
+
+
+import java.util.UUID;
+
+import org.apache.usergrid.locking.exception.UGLockException;
+
+
+/**
+ * This Interface to a class responsible for distributed lock across system.
+ *
+ * @author tnine
+ */
+public interface LockManager {
+
+    /**
+     * Acquires a lock on a particular path.
+     *
+     * @param applicationId application UUID
+     * @param path a unique path
+     *
+     * @throws UGLockException if the lock cannot be acquired
+     */
+    public Lock createLock( final UUID applicationId, final String... path );
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/LockPathBuilder.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/LockPathBuilder.java b/stack/core/src/main/java/org/apache/usergrid/locking/LockPathBuilder.java
new file mode 100644
index 0000000..5842a07
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/LockPathBuilder.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking;
+
+
+import java.util.UUID;
+
+
+/**
+ * Helper class that contains the logic to build a lock path
+ *
+ * @author eanuff
+ */
+public class LockPathBuilder {
+
+    private static final String SLASH = "/";
+
+
+    /** Build a string path for this lock */
+    public static String buildPath( UUID applicationId, String... path ) {
+        StringBuilder builder = new StringBuilder();
+        builder.append( SLASH );
+        builder.append( applicationId.toString() );
+
+        for ( String element : path ) {
+            builder.append( SLASH );
+            builder.append( element );
+        }
+        return builder.toString();
+    }
+
+
+    /**
+     * Build a string path for this lock
+     *
+     * @param The binary value to append to the end of the lock path
+     * @param path The values to prepend to build path
+     */
+    public static String buildPath( String binaryValue, String... path ) {
+
+        StringBuilder builder = new StringBuilder();
+
+        for ( String element : path ) {
+            builder.append( SLASH );
+            builder.append( element );
+        }
+
+        builder.append( SLASH );
+        builder.append( binaryValue );
+
+        builder.deleteCharAt( 0 );
+
+        return builder.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/HectorLockImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/HectorLockImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/HectorLockImpl.java
new file mode 100644
index 0000000..1812f37
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/HectorLockImpl.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking.cassandra;
+
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.usergrid.locking.Lock;
+import org.apache.usergrid.locking.exception.UGLockException;
+
+import me.prettyprint.hector.api.locking.HLock;
+import me.prettyprint.hector.api.locking.HLockManager;
+import me.prettyprint.hector.api.locking.HLockTimeoutException;
+
+
+/** @author tnine */
+public class HectorLockImpl implements Lock {
+
+    private HLock lock;
+    private HLockManager lm;
+    private AtomicInteger count = new AtomicInteger();
+
+
+    /**
+     *
+     */
+    public HectorLockImpl( HLock lock, HLockManager lm ) {
+        this.lock = lock;
+        this.lm = lm;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#acquire(long, java.util.concurrent.TimeUnit)
+     */
+    @Override
+    public boolean tryLock( long timeout, TimeUnit time ) throws UGLockException {
+        try {
+            lm.acquire( this.lock, time.toMillis( timeout ) );
+            count.incrementAndGet();
+        }
+        catch ( HLockTimeoutException hlte ) {
+            return false;
+        }
+
+        return true;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#lock()
+     */
+    @Override
+    public void lock() throws UGLockException {
+        lm.acquire( lock );
+        count.incrementAndGet();
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#release()
+     */
+    @Override
+    public void unlock() throws UGLockException {
+        int current = count.decrementAndGet();
+
+        if ( current == 0 ) {
+            lm.release( this.lock );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/HectorLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/HectorLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/HectorLockManagerImpl.java
new file mode 100644
index 0000000..6642f97
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/HectorLockManagerImpl.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking.cassandra;
+
+
+import java.util.UUID;
+
+import javax.annotation.PostConstruct;
+
+import me.prettyprint.cassandra.locking.HLockManagerImpl;
+import me.prettyprint.hector.api.Cluster;
+import me.prettyprint.hector.api.ConsistencyLevelPolicy;
+import me.prettyprint.hector.api.locking.HLockManager;
+import me.prettyprint.hector.api.locking.HLockManagerConfigurator;
+
+import org.apache.usergrid.locking.Lock;
+import org.apache.usergrid.locking.LockManager;
+import org.apache.usergrid.locking.LockPathBuilder;
+import org.springframework.util.Assert;
+
+
+/**
+ * Uses the hector based locking implementation to obtain locks
+ *
+ * @author tnine
+ */
+public class HectorLockManagerImpl implements LockManager {
+    private int replicationFactor = 1;
+    private int numberOfLockObserverThreads = 1;
+    private long lockTtl = 2000;
+    private String keyspaceName;
+    private Cluster cluster;
+    private HLockManager lm;
+    private ConsistencyLevelPolicy consistencyLevelPolicy;
+
+
+    /**
+     *
+     */
+    public HectorLockManagerImpl() {
+    }
+
+
+    @PostConstruct
+    public void init() {
+        HLockManagerConfigurator hlc = new HLockManagerConfigurator();
+        hlc.setReplicationFactor( replicationFactor );
+        hlc.setKeyspaceName( keyspaceName );
+        hlc.setNumberOfLockObserverThreads( numberOfLockObserverThreads );
+        hlc.setLocksTTLInMillis( lockTtl );
+        lm = new HLockManagerImpl( cluster, hlc );
+        if ( consistencyLevelPolicy != null ) {
+        	lm.getKeyspace().setConsistencyLevelPolicy(consistencyLevelPolicy);
+        }
+        // if consistencyLevelPolicy == null, use hector's default, which is QuorumAll, no need to explicitly set
+        lm.init();
+    }
+
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.apache.usergrid.locking.LockManager#createLock(java.util.UUID,
+     * java.lang.String[])
+     */
+    @Override
+    public Lock createLock( UUID applicationId, String... path ) {
+
+        String lockPath = LockPathBuilder.buildPath( applicationId, path );
+
+        return new HectorLockImpl( lm.createLock( lockPath ), lm );
+    }
+
+
+    /**
+     * Note that in a real environment this MUST be an odd number. Locks are read and written at QUORUM. RF >= 3 is
+     * preferred for failure tolerance and replication.  Defaults to 1
+     *
+     * @param replicationFactor the replicationFactor to set
+     */
+    public void setReplicationFactor( int replicationFactor ) {
+
+        Assert.isTrue( numberOfLockObserverThreads % 2 != 0, "You must specify an odd number for replication factor" );
+
+        this.replicationFactor = replicationFactor;
+    }
+
+
+    /**
+     * Set the number of threads the lock heartbeat executor uses.  Must accommodate the total number of locks that may
+     * exist in the system.  Locks are always renewed at the ttl/2 time.
+     *
+     * @param numberOfLockObserverThreads the numberOfLockObserverThreads to set
+     */
+    public void setNumberOfLockObserverThreads( int numberOfLockObserverThreads ) {
+        this.numberOfLockObserverThreads = numberOfLockObserverThreads;
+    }
+
+
+    /**
+     * The amount of time a lock must not be renewed before it times out.  Set in milliseconds.  2000 is the default
+     *
+     * @param lockTtl the lockTtl to set
+     */
+    public void setLockTtl( long lockTtl ) {
+        this.lockTtl = lockTtl;
+    }
+
+
+    /** @param keyspaceName the keyspaceName to set */
+    public void setKeyspaceName( String keyspaceName ) {
+        this.keyspaceName = keyspaceName;
+    }
+
+
+    /** @param cluster the cluster to set */
+    public void setCluster( Cluster cluster ) {
+        this.cluster = cluster;
+    }
+
+
+	/**
+	 * @param consistencyLevelPolicy the consistencyLevelPolicy to set
+	 */
+	public void setConsistencyLevelPolicy(ConsistencyLevelPolicy consistencyLevelPolicy) {
+		this.consistencyLevelPolicy = consistencyLevelPolicy;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/exception/UGLockException.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/exception/UGLockException.java b/stack/core/src/main/java/org/apache/usergrid/locking/exception/UGLockException.java
new file mode 100644
index 0000000..21a610d
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/exception/UGLockException.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking.exception;
+
+
+public class UGLockException extends Exception {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -8902830935510966393L;
+
+
+    public UGLockException() {
+        super();
+        // TODO Auto-generated constructor stub
+    }
+
+
+    public UGLockException( String message, Throwable cause ) {
+        super( message, cause );
+        // TODO Auto-generated constructor stub
+    }
+
+
+    public UGLockException( String message ) {
+        super( message );
+        // TODO Auto-generated constructor stub
+    }
+
+
+    public UGLockException( Throwable cause ) {
+        super( cause );
+        // TODO Auto-generated constructor stub
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockImpl.java
new file mode 100644
index 0000000..dd1cc39
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockImpl.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking.noop;
+
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.usergrid.locking.Lock;
+import org.apache.usergrid.locking.exception.UGLockException;
+
+
+/** @author tnine */
+public class NoOpLockImpl implements Lock {
+
+    /**
+     *
+     */
+    public NoOpLockImpl() {
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#acquire(long, java.util.concurrent.TimeUnit)
+     */
+    @Override
+    public boolean tryLock( long timeout, TimeUnit time ) throws UGLockException {
+        //no op
+        return true;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#lock()
+     */
+    @Override
+    public void lock() throws UGLockException {
+        //no op
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#release()
+     */
+    @Override
+    public void unlock() throws UGLockException {
+        //no op
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockManagerImpl.java
new file mode 100644
index 0000000..467f5a5
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockManagerImpl.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking.noop;
+
+
+import java.util.UUID;
+
+import org.apache.usergrid.locking.Lock;
+import org.apache.usergrid.locking.LockManager;
+
+
+/** This is a no-op manager used for testing. */
+public class NoOpLockManagerImpl implements LockManager {
+
+    public NoOpLockManagerImpl() {
+
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.LockManager#createLock(java.util.UUID, java.lang.String[])
+     */
+    @Override
+    public Lock createLock( UUID applicationId, String... path ) {
+        return new NoOpLockImpl();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/singlenode/SingleNodeLockImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/singlenode/SingleNodeLockImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/singlenode/SingleNodeLockImpl.java
new file mode 100644
index 0000000..aec969a
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/singlenode/SingleNodeLockImpl.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking.singlenode;
+
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.usergrid.locking.Lock;
+import org.apache.usergrid.locking.exception.UGLockException;
+
+
+/** @author tnine */
+public class SingleNodeLockImpl implements Lock {
+
+    private final ReentrantLock lock;
+
+
+    /**
+     *
+     */
+    public SingleNodeLockImpl( ReentrantLock lock ) {
+        this.lock = lock;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#acquire(long)
+     */
+    @Override
+    public boolean tryLock( long timeout, TimeUnit time ) throws UGLockException {
+        try {
+            return this.lock.tryLock( timeout, time );
+        }
+        catch ( InterruptedException e ) {
+            throw new UGLockException( "Couldn't get the lock", e );
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#lock()
+     */
+    @Override
+    public void lock() throws UGLockException {
+        this.lock.lock();
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#release()
+     */
+    @Override
+    public void unlock() throws UGLockException {
+        this.lock.unlock();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/singlenode/SingleNodeLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/singlenode/SingleNodeLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/singlenode/SingleNodeLockManagerImpl.java
new file mode 100644
index 0000000..b75ad76
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/singlenode/SingleNodeLockManagerImpl.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking.singlenode;
+
+
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.usergrid.locking.Lock;
+import org.apache.usergrid.locking.LockManager;
+import org.apache.usergrid.locking.LockPathBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.cache.RemovalListener;
+import com.google.common.cache.RemovalNotification;
+
+
+/**
+ * Single Node implementation for {@link LockManager} Note that this implementation has not been used in a production
+ * environment.
+ * <p/>
+ * The hector based implementation is the preferred production locking system
+ */
+public class SingleNodeLockManagerImpl implements LockManager {
+
+    private static final Logger logger = LoggerFactory.getLogger( SingleNodeLockManagerImpl.class );
+
+    public static final long MILLI_EXPIRATION = 5000;
+
+    /** Lock cache that sill expire after 5 seconds of no use for a lock path */
+    private LoadingCache<String, ReentrantLock> locks =
+            CacheBuilder.newBuilder().expireAfterWrite( MILLI_EXPIRATION, TimeUnit.MILLISECONDS )
+                    // use weakValues. We want want entries removed if they're not being
+                    // referenced by another
+                    // thread somewhere and GC occurs
+                    .weakValues().removalListener( new RemovalListener<String, ReentrantLock>() {
+
+                @Override
+                public void onRemoval( RemovalNotification<String, ReentrantLock> notification ) {
+                    logger.debug( "Evicting reentrant lock for {}", notification.getKey() );
+                }
+            } ).build( new CacheLoader<String, ReentrantLock>() {
+
+                @Override
+                public ReentrantLock load( String arg0 ) throws Exception {
+                    return new ReentrantLock( true );
+                }
+            } );
+
+
+    /** Default constructor. */
+    public SingleNodeLockManagerImpl() {
+    }
+
+
+    /*
+   * (non-Javadoc)
+   * 
+   * @see org.apache.usergrid.locking.LockManager#createLock(java.util.UUID,
+   * java.lang.String[])
+   */
+    @Override
+    public Lock createLock( UUID applicationId, String... path ) {
+
+        String lockPath = LockPathBuilder.buildPath( applicationId, path );
+
+        try {
+            return new SingleNodeLockImpl( locks.get( lockPath ) );
+        }
+        catch ( ExecutionException e ) {
+            throw new RuntimeException( "Unable to create lock in cache", e );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/zookeeper/ZooKeeperLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/zookeeper/ZooKeeperLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/zookeeper/ZooKeeperLockManagerImpl.java
new file mode 100644
index 0000000..e0c7ae2
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/zookeeper/ZooKeeperLockManagerImpl.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking.zookeeper;
+
+
+import java.util.UUID;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.usergrid.locking.Lock;
+import org.apache.usergrid.locking.LockManager;
+import org.apache.usergrid.locking.LockPathBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.netflix.curator.RetryPolicy;
+import com.netflix.curator.framework.CuratorFramework;
+import com.netflix.curator.framework.CuratorFrameworkFactory;
+import com.netflix.curator.framework.recipes.locks.InterProcessMutex;
+import com.netflix.curator.retry.ExponentialBackoffRetry;
+
+
+/** Implementation for Zookeeper service that handles global locks. */
+public final class ZooKeeperLockManagerImpl implements LockManager {
+
+    private String hostPort;
+
+    private int sessionTimeout = 2000;
+
+    private int maxAttempts = 5;
+
+    private CuratorFramework client;
+
+
+    public ZooKeeperLockManagerImpl( String hostPort, int sessionTimeout, int maxAttemps ) {
+        this.hostPort = hostPort;
+        this.sessionTimeout = sessionTimeout;
+        this.maxAttempts = maxAttemps;
+        init();
+    }
+
+
+    public ZooKeeperLockManagerImpl() {
+    }
+
+
+    @PostConstruct
+    public void init() {
+        RetryPolicy retryPolicy = new ExponentialBackoffRetry( sessionTimeout, maxAttempts );
+        client = CuratorFrameworkFactory.newClient( hostPort, retryPolicy );
+        client.start();
+    }
+
+
+    protected static final Logger logger = LoggerFactory.getLogger( ZooKeeperLockManagerImpl.class );
+
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.apache.usergrid.locking.LockManager#createLock(java.util.UUID,
+     * java.lang.String[])
+     */
+    @Override
+    public Lock createLock( UUID applicationId, String... path ) {
+        String lockPath = LockPathBuilder.buildPath( applicationId, path );
+
+
+        return new ZookeeperLockImpl( new InterProcessMutex( client, lockPath ) );
+    }
+
+
+    public String getHostPort() {
+        return hostPort;
+    }
+
+
+    public void setHostPort( String hostPort ) {
+        this.hostPort = hostPort;
+    }
+
+
+    public int getSessionTimeout() {
+        return sessionTimeout;
+    }
+
+
+    public void setSessionTimeout( int sessionTimeout ) {
+        this.sessionTimeout = sessionTimeout;
+    }
+
+
+    public int getMaxAttempts() {
+        return maxAttempts;
+    }
+
+
+    public void setMaxAttempts( int maxAttemps ) {
+        this.maxAttempts = maxAttemps;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/locking/zookeeper/ZookeeperLockImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/zookeeper/ZookeeperLockImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/zookeeper/ZookeeperLockImpl.java
new file mode 100644
index 0000000..185f37c
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/zookeeper/ZookeeperLockImpl.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * 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.apache.usergrid.locking.zookeeper;
+
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.usergrid.locking.Lock;
+import org.apache.usergrid.locking.exception.UGLockException;
+
+import com.netflix.curator.framework.recipes.locks.InterProcessMutex;
+
+
+/**
+ * Wrapper for locks using curator
+ *
+ * @author tnine
+ */
+public class ZookeeperLockImpl implements Lock {
+
+
+    private InterProcessMutex zkMutex;
+
+
+    /**
+     *
+     */
+    public ZookeeperLockImpl( InterProcessMutex zkMutex ) {
+        this.zkMutex = zkMutex;
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#tryLock(long, java.util.concurrent.TimeUnit)
+     */
+    @Override
+    public boolean tryLock( long timeout, TimeUnit time ) throws UGLockException {
+
+        try {
+            return zkMutex.acquire( timeout, time );
+        }
+        catch ( Exception e ) {
+            throw new UGLockException( "Unable to obtain lock", e );
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#lock()
+     */
+    @Override
+    public void lock() throws UGLockException {
+        try {
+            zkMutex.acquire();
+        }
+        catch ( Exception e ) {
+            throw new UGLockException( "Unable to obtain lock", e );
+        }
+    }
+
+
+    /* (non-Javadoc)
+     * @see org.apache.usergrid.locking.Lock#unlock()
+     */
+    @Override
+    public void unlock() throws UGLockException {
+        try {
+            zkMutex.release();
+        }
+        catch ( Exception e ) {
+            throw new UGLockException( "Unable to obtain lock", e );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/mq/CounterQuery.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/mq/CounterQuery.java b/stack/core/src/main/java/org/apache/usergrid/mq/CounterQuery.java
new file mode 100644
index 0000000..2a0f074
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/mq/CounterQuery.java
@@ -0,0 +1,314 @@
+/*******************************************************************************
+ * 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.apache.usergrid.mq;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.usergrid.mq.Query.CounterFilterPredicate;
+import org.apache.usergrid.persistence.CounterResolution;
+import org.apache.usergrid.utils.JsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.usergrid.utils.ClassUtils.cast;
+import static org.apache.usergrid.utils.ListUtils.firstBoolean;
+import static org.apache.usergrid.utils.ListUtils.firstInteger;
+import static org.apache.usergrid.utils.ListUtils.firstLong;
+import static org.apache.usergrid.utils.ListUtils.isEmpty;
+import static org.apache.usergrid.utils.MapUtils.toMapList;
+
+
+public class CounterQuery {
+
+    public static final Logger logger = LoggerFactory.getLogger( CounterQuery.class );
+
+    public static final int DEFAULT_MAX_RESULTS = 10;
+
+    private int limit = 0;
+    boolean limitSet = false;
+
+    private Long startTime;
+    private Long finishTime;
+    private boolean pad;
+    private CounterResolution resolution = CounterResolution.ALL;
+    private List<String> categories;
+    private List<CounterFilterPredicate> counterFilters;
+
+
+    public CounterQuery() {
+    }
+
+
+    public CounterQuery( CounterQuery q ) {
+        if ( q != null ) {
+            limit = q.limit;
+            limitSet = q.limitSet;
+            startTime = q.startTime;
+            finishTime = q.finishTime;
+            resolution = q.resolution;
+            pad = q.pad;
+            categories = q.categories != null ? new ArrayList<String>( q.categories ) : null;
+            counterFilters =
+                    q.counterFilters != null ? new ArrayList<CounterFilterPredicate>( q.counterFilters ) : null;
+        }
+    }
+
+
+    public static CounterQuery newQueryIfNull( CounterQuery query ) {
+        if ( query == null ) {
+            query = new CounterQuery();
+        }
+        return query;
+    }
+
+
+    public static CounterQuery fromJsonString( String json ) {
+        Object o = JsonUtils.parse( json );
+        if ( o instanceof Map ) {
+            @SuppressWarnings({ "unchecked", "rawtypes" }) Map<String, List<String>> params =
+                    cast( toMapList( ( Map ) o ) );
+            return fromQueryParams( params );
+        }
+        return null;
+    }
+
+
+    public static CounterQuery fromQueryParams( Map<String, List<String>> params ) {
+
+        CounterQuery q = null;
+        Integer limit = null;
+        Long startTime = null;
+        Long finishTime = null;
+        Boolean pad = null;
+        CounterResolution resolution = null;
+        List<CounterFilterPredicate> counterFilters = null;
+        List<String> categories = null;
+
+        List<String> l = null;
+
+        limit = firstInteger( params.get( "limit" ) );
+        startTime = firstLong( params.get( "start_time" ) );
+        finishTime = firstLong( params.get( "end_time" ) );
+
+        l = params.get( "resolution" );
+        if ( !isEmpty( l ) ) {
+            resolution = CounterResolution.fromString( l.get( 0 ) );
+        }
+
+        categories = params.get( "category" );
+
+        l = params.get( "counter" );
+        if ( !isEmpty( l ) ) {
+            counterFilters = CounterFilterPredicate.fromList( l );
+        }
+
+        pad = firstBoolean( params.get( "pad" ) );
+
+        if ( limit != null ) {
+            q = newQueryIfNull( q );
+            q.setLimit( limit );
+        }
+
+        if ( startTime != null ) {
+            q = newQueryIfNull( q );
+            q.setStartTime( startTime );
+        }
+
+        if ( finishTime != null ) {
+            q = newQueryIfNull( q );
+            q.setFinishTime( finishTime );
+        }
+
+        if ( resolution != null ) {
+            q = newQueryIfNull( q );
+            q.setResolution( resolution );
+        }
+
+        if ( categories != null ) {
+            q = newQueryIfNull( q );
+            q.setCategories( categories );
+        }
+
+        if ( counterFilters != null ) {
+            q = newQueryIfNull( q );
+            q.setCounterFilters( counterFilters );
+        }
+
+        if ( pad != null ) {
+            q = newQueryIfNull( q );
+            q.setPad( pad );
+        }
+
+        return q;
+    }
+
+
+    public int getLimit() {
+        return getLimit( DEFAULT_MAX_RESULTS );
+    }
+
+
+    public int getLimit( int defaultMax ) {
+        if ( limit <= 0 ) {
+            if ( defaultMax > 0 ) {
+                return defaultMax;
+            }
+            else {
+                return DEFAULT_MAX_RESULTS;
+            }
+        }
+        return limit;
+    }
+
+
+    public void setLimit( int limit ) {
+        limitSet = true;
+        this.limit = limit;
+    }
+
+
+    public CounterQuery withLimit( int limit ) {
+        limitSet = true;
+        this.limit = limit;
+        return this;
+    }
+
+
+    public boolean isLimitSet() {
+        return limitSet;
+    }
+
+
+    public Long getStartTime() {
+        return startTime;
+    }
+
+
+    public void setStartTime( Long startTime ) {
+        this.startTime = startTime;
+    }
+
+
+    public CounterQuery withStartTime( Long startTime ) {
+        this.startTime = startTime;
+        return this;
+    }
+
+
+    public Long getFinishTime() {
+        return finishTime;
+    }
+
+
+    public void setFinishTime( Long finishTime ) {
+        this.finishTime = finishTime;
+    }
+
+
+    public CounterQuery withFinishTime( Long finishTime ) {
+        this.finishTime = finishTime;
+        return this;
+    }
+
+
+    public boolean isPad() {
+        return pad;
+    }
+
+
+    public void setPad( boolean pad ) {
+        this.pad = pad;
+    }
+
+
+    public CounterQuery withPad( boolean pad ) {
+        this.pad = pad;
+        return this;
+    }
+
+
+    public void setResolution( CounterResolution resolution ) {
+        this.resolution = resolution;
+    }
+
+
+    public CounterResolution getResolution() {
+        return resolution;
+    }
+
+
+    public CounterQuery withResolution( CounterResolution resolution ) {
+        this.resolution = resolution;
+        return this;
+    }
+
+
+    public List<String> getCategories() {
+        return categories;
+    }
+
+
+    public CounterQuery addCategory( String category ) {
+        if ( categories == null ) {
+            categories = new ArrayList<String>();
+        }
+        categories.add( category );
+        return this;
+    }
+
+
+    public void setCategories( List<String> categories ) {
+        this.categories = categories;
+    }
+
+
+    public CounterQuery withCategories( List<String> categories ) {
+        this.categories = categories;
+        return this;
+    }
+
+
+    public List<CounterFilterPredicate> getCounterFilters() {
+        return counterFilters;
+    }
+
+
+    public CounterQuery addCounterFilter( String counter ) {
+        CounterFilterPredicate p = CounterFilterPredicate.fromString( counter );
+        if ( p == null ) {
+            return this;
+        }
+        if ( counterFilters == null ) {
+            counterFilters = new ArrayList<CounterFilterPredicate>();
+        }
+        counterFilters.add( p );
+        return this;
+    }
+
+
+    public void setCounterFilters( List<CounterFilterPredicate> counterFilters ) {
+        this.counterFilters = counterFilters;
+    }
+
+
+    public CounterQuery withCounterFilters( List<CounterFilterPredicate> counterFilters ) {
+        this.counterFilters = counterFilters;
+        return this;
+    }
+}