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/03/12 19:20:59 UTC

[3/4] git commit: We now cleanup and unique values on version conflict; also, added better tests for optimistic and unique verification.

We now cleanup and unique values on version conflict; also, added better tests for optimistic and unique verification.


Project: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/commit/29a4966b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/29a4966b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/29a4966b

Branch: refs/pull/52/merge
Commit: 29a4966b4b4682f42e22dacfc9f55c69a5f61b78
Parents: e072f0b
Author: Dave Johnson <dm...@apigee.com>
Authored: Wed Mar 12 14:11:32 2014 -0400
Committer: Dave Johnson <dm...@apigee.com>
Committed: Wed Mar 12 14:11:32 2014 -0400

----------------------------------------------------------------------
 .../exception/WriteUniqueVerifyException.java   |  24 ++-
 .../mvcc/stage/write/WriteOptimisticVerify.java | 114 +++++++++++-
 .../mvcc/stage/write/WriteUniqueVerify.java     |  69 ++++----
 .../mvcc/entity/impl/MvccEntityImplTest.java    |  23 ++-
 .../stage/write/WriteOptimisticVerifyTest.java  |  78 ++++++--
 .../mvcc/stage/write/WriteUniqueVerifyIT.java   |  97 ++++++++++
 .../mvcc/stage/write/WriteUniqueVerifyTest.java |  23 ---
 .../collection/util/EntityBuilder.java          | 177 +++++++++++++++++++
 .../src/test/resources/log4j.properties         |   4 +-
 .../index/impl/EntityCollectionIndexTest.java   |   2 +-
 .../persistence/index/legacy/EntityBuilder.java | 177 -------------------
 .../index/legacy/EntityManagerFacade.java       |   1 +
 12 files changed, 525 insertions(+), 264 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/WriteUniqueVerifyException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/WriteUniqueVerifyException.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/WriteUniqueVerifyException.java
index a003b16..66b3076 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/WriteUniqueVerifyException.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/WriteUniqueVerifyException.java
@@ -17,13 +17,20 @@
  */
 package org.apache.usergrid.persistence.collection.exception;
 
-public class WriteUniqueVerifyException extends CollectionRuntimeException {
-    public WriteUniqueVerifyException() {
-    }
+import java.util.Map;
+import org.apache.usergrid.persistence.model.field.Field;
 
 
-    public WriteUniqueVerifyException( final String message ) {
-        super( message );
+/**
+ * Indicates that one or more unique field checks failed.
+ */
+public class WriteUniqueVerifyException extends CollectionRuntimeException {
+    private Map<String, Field> violations;
+
+    
+    public WriteUniqueVerifyException( Map<String, Field> violations ) {
+        super( "Error: one or more duplicate fields detected");
+        this.violations = violations;
     }
 
 
@@ -41,4 +48,11 @@ public class WriteUniqueVerifyException extends CollectionRuntimeException {
                                        final boolean writableStackTrace ) {
         super( message, cause, enableSuppression, writableStackTrace );
     }
+
+    /**
+     * Get map of Fields in violation, keyed by field name.
+     */
+    public Map<String, Field> getVioliations() {
+        return violations;
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerify.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerify.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerify.java
index 3196404..061595c 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerify.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerify.java
@@ -20,10 +20,14 @@ package org.apache.usergrid.persistence.collection.mvcc.stage.write;
 
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import com.netflix.astyanax.MutationBatch;
 import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+import java.util.ArrayList;
 import java.util.List;
 import org.apache.usergrid.persistence.collection.CollectionScope;
+import org.apache.usergrid.persistence.collection.exception.CollectionRuntimeException;
 import org.apache.usergrid.persistence.collection.exception.WriteOptimisticVerifyException;
+import org.apache.usergrid.persistence.collection.exception.WriteUniqueVerifyException;
 import org.apache.usergrid.persistence.collection.mvcc.MvccLogEntrySerializationStrategy;
 import org.apache.usergrid.persistence.collection.mvcc.entity.MvccEntity;
 import org.apache.usergrid.persistence.collection.mvcc.entity.MvccLogEntry;
@@ -31,9 +35,14 @@ import org.apache.usergrid.persistence.collection.mvcc.entity.Stage;
 import org.apache.usergrid.persistence.collection.mvcc.entity.ValidationUtils;
 import org.apache.usergrid.persistence.collection.mvcc.entity.impl.MvccLogEntryImpl;
 import org.apache.usergrid.persistence.collection.mvcc.stage.CollectionIoEvent;
+import org.apache.usergrid.persistence.model.entity.Entity;
+import org.apache.usergrid.persistence.model.field.Field;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import rx.Observable;
+import rx.Scheduler;
 import rx.util.functions.Func1;
+import rx.util.functions.FuncN;
 
 
 /**
@@ -43,13 +52,21 @@ import rx.util.functions.Func1;
 public class WriteOptimisticVerify 
     implements Func1<CollectionIoEvent<MvccEntity>, CollectionIoEvent<MvccEntity>> {
 
-    private static final Logger LOG = LoggerFactory.getLogger( WriteOptimisticVerify.class );
+    private static final Logger log = LoggerFactory.getLogger( WriteOptimisticVerify.class );
 
     private final MvccLogEntrySerializationStrategy logEntryStrat;
 
+    private final UniqueValueSerializationStrategy uniqueValueStrat;
+
+    private final Scheduler scheduler;
+
     @Inject
-    public WriteOptimisticVerify( MvccLogEntrySerializationStrategy logEntryStrat ) {
+    public WriteOptimisticVerify( MvccLogEntrySerializationStrategy logEntryStrat, 
+            final UniqueValueSerializationStrategy uniqueValueStrat, final Scheduler scheduler ) {
+
         this.logEntryStrat = logEntryStrat;
+        this.uniqueValueStrat = uniqueValueStrat; 
+        this.scheduler = scheduler;
     }
 
 
@@ -63,7 +80,9 @@ public class WriteOptimisticVerify
         //
         // If not, fail fast, signal to the user their entity is "stale".
 
-        MvccEntity entity = ioevent.getEvent();
+        MvccEntity mvccEntity = ioevent.getEvent();
+        final Entity entity = mvccEntity.getEntity().get();
+
         CollectionScope collectionScope = ioevent.getEntityCollection();
 
         try {
@@ -73,21 +92,102 @@ public class WriteOptimisticVerify
             // Previous log entry must be committed, otherwise somebody is already writing
             if ( versions.size() > 1 
                     && versions.get(1).getStage().ordinal() < Stage.COMMITTED.ordinal() ) {
+
+                log.debug("Conflict writing entity id {} version {}", 
+                    entity.getId().toString(), entity.getVersion().toString());
             
-                // We're not the first writer, rollback and throw-up
+                // We're not the first writer, set ROLLBACK, cleanup and throw exception
+
                 final MvccLogEntry rollbackEntry = 
-                        new MvccLogEntryImpl( entity.getId(), entity.getVersion(), Stage.ROLLBACK);
+                    new MvccLogEntryImpl( entity.getId(), entity.getVersion(), Stage.ROLLBACK);
                 logEntryStrat.write( collectionScope, rollbackEntry );
+
+                // Delete all unique values of entity, and do it concurrently 
+
+                List<Observable<FieldDeleteResult>> results = 
+                    new ArrayList<Observable<FieldDeleteResult>>();
+
+                int uniqueFieldCount = 0;
+                for ( final Field field : entity.getFields() ) {
+
+                    // if it's unique, create a function to delete it
+                    if ( field.isUnique() ) {
+
+                        uniqueFieldCount++;
+
+                        Observable<FieldDeleteResult> result =  Observable.from( field )
+                            .subscribeOn( scheduler ).map(new Func1<Field,  FieldDeleteResult>() {
+
+                            @Override
+                            public FieldDeleteResult call(Field field ) {
+
+                                UniqueValue toDelete = new UniqueValueImpl( 
+                                    ioevent.getEntityCollection(), field, 
+                                    entity.getId(), entity.getVersion() );
+
+                                MutationBatch mb = uniqueValueStrat.delete( toDelete );
+                                try {
+                                    mb.execute();
+                                }
+                                catch ( ConnectionException ex ) {
+                                    throw new WriteUniqueVerifyException( 
+                                        "Error deleting unique value " + field.toString(), ex );
+                                }
+                                return new FieldDeleteResult( field.getName() );
+                            }
+                        });
+
+                        results.add( result ); 
+                    }
+                }
+
+                if ( uniqueFieldCount > 0 ) {
+
+                    final FuncN<Boolean> zipFunction = new FuncN<Boolean>() {
+
+                        @Override
+                        public Boolean call( final Object... args ) {
+                            for ( Object resultObj : args ) {
+
+                                FieldDeleteResult result = ( FieldDeleteResult ) resultObj;
+                                log.debug("Rollback deleted field from entity: {} version: {} name: {}",
+                                    new String[] { 
+                                        entity.getId().toString(), 
+                                        entity.getVersion().toString(),
+                                        result.getName()
+                                    });
+                            }
+                            return true;
+                        }
+                    };
+   
+                    // "zip" up the concurrent results
+                    Observable.zip( results, zipFunction ).toBlockingObservable().last();
+                }
+
                 throw new WriteOptimisticVerifyException("Change conflict, not first writer");
             }
 
 
         } catch ( ConnectionException e ) {
-            LOG.error( "Error reading entity log", e );
-            throw new WriteOptimisticVerifyException( "Error reading entity log", e );
+            log.error( "Error reading entity log", e );
+            throw new CollectionRuntimeException( "Error reading entity log", e );
         }
 
         // No op, just emit the value
         return ioevent;
     }
+
+
+    class FieldDeleteResult {
+        private final String name;
+
+        public FieldDeleteResult( String name ) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return this.name;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerify.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerify.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerify.java
index 02ed9db..ca99c0c 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerify.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerify.java
@@ -36,6 +36,8 @@ import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.netflix.astyanax.MutationBatch;
 import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+import java.util.HashMap;
+import java.util.Map;
 import org.apache.usergrid.persistence.collection.exception.WriteUniqueVerifyException;
 
 import rx.Observable;
@@ -48,34 +50,35 @@ import rx.util.functions.FuncN;
  * This phase execute all unique value verification on the MvccEntity.
  */
 @Singleton
-public class WriteUniqueVerify implements Func1<CollectionIoEvent<MvccEntity>, Observable<? extends CollectionIoEvent<MvccEntity>>> {
+public class WriteUniqueVerify implements 
+        Func1<CollectionIoEvent<MvccEntity>, Observable<? extends CollectionIoEvent<MvccEntity>>> {
 
     private static final Logger LOG = LoggerFactory.getLogger( WriteUniqueVerify.class );
 
     private final UniqueValueSerializationStrategy uniqueValueStrat;
 
-
     private final Scheduler scheduler;
 
     protected final SerializationFig serializationFig;
 
 
     @Inject
-    public WriteUniqueVerify( final UniqueValueSerializationStrategy uniqueValueSerializiationStrategy,
+    public WriteUniqueVerify( final UniqueValueSerializationStrategy uniqueValueStrat,
                               final Scheduler scheduler, final SerializationFig serializationFig ) {
 
-        Preconditions.checkNotNull( uniqueValueSerializiationStrategy, "uniqueValueSerializationStrategy is required" );
+        Preconditions.checkNotNull( uniqueValueStrat, "uniqueValueStrat is required" );
         Preconditions.checkNotNull( scheduler, "scheduler is required" );
         Preconditions.checkNotNull( serializationFig, "serializationFig is required" );
 
-        this.uniqueValueStrat = uniqueValueSerializiationStrategy;
+        this.uniqueValueStrat = uniqueValueStrat;
         this.scheduler = scheduler;
         this.serializationFig = serializationFig;
     }
 
 
     @Override
-    public Observable<? extends CollectionIoEvent<MvccEntity>> call(final CollectionIoEvent<MvccEntity> ioevent ) {
+    public Observable<? extends CollectionIoEvent<MvccEntity>> 
+        call(final CollectionIoEvent<MvccEntity> ioevent ) {
 
         ValidationUtils.verifyMvccEntityWithEntity( ioevent.getEvent() );
 
@@ -83,32 +86,33 @@ public class WriteUniqueVerify implements Func1<CollectionIoEvent<MvccEntity>, O
 
         // use simple thread pool to verify fields in parallel
 
-        // We want to use concurrent to fork all validations this way they're wrapped by timeouts and
-        // Hystrix thread pools for JMX operations.  See the WriteCommand in the EntityCollectionManagerImpl
-        // I think it still needs added to the Concurrent utility class
-
+        // We want to use concurrent to fork all validations this way they're wrapped by timeouts 
+        // and Hystrix thread pools for JMX operations.  See the WriteCommand in the 
+        // EntityCollectionManagerImpl. 
+        // TODO: still needs to be added to the Concurrent utility class?
 
         final List<Observable<FieldUniquenessResult>> fields =
                 new ArrayList<Observable<FieldUniquenessResult>>();
 
-
-
-        /**
-         * Construct all the functions for verifying we're unique
-         */
+        //
+        // Construct all the functions for verifying we're unique
+        //
         for ( final Field field : entity.getFields() ) {
 
-            //if it's unique, create a function to validate it and add it to the list of concurrent validations
+            // if it's unique, create a function to validate it and add it to the list of 
+            // concurrent validations
             if ( field.isUnique() ) {
 
                 Observable<FieldUniquenessResult> result =  
-                        Observable.from( field ).subscribeOn( scheduler ).map(new Func1<Field,  FieldUniquenessResult>() {
+                        Observable.from( field ).subscribeOn( scheduler )
+                                .map(new Func1<Field,  FieldUniquenessResult>() {
+
                     @Override
                     public FieldUniquenessResult call(Field field ) {
 
                         // use write-first then read strategy
-                        UniqueValue written = new UniqueValueImpl( ioevent.getEntityCollection(), field, entity.getId(),
-                                entity.getVersion() );
+                        UniqueValue written = new UniqueValueImpl( 
+                            ioevent.getEntityCollection(), field, entity.getId(), entity.getVersion() );
 
                         // use TTL in case something goes wrong before entity is finally committed
                         MutationBatch mb = uniqueValueStrat.write( written, serializationFig.getTimeout() );
@@ -138,29 +142,34 @@ public class WriteUniqueVerify implements Func1<CollectionIoEvent<MvccEntity>, O
             }
         }
 
-        //short circuit.  If we zip up nothing, we block forever.
-        if(fields.size() == 0){
-            return Observable.from(ioevent ).subscribeOn( scheduler );
+        // short circuit.  If we zip up nothing, we block forever.
+        if ( fields.isEmpty() ){
+            return Observable.from( ioevent ).subscribeOn( scheduler );
         }
 
-        /**
-         * Zip the results up
-         */
-        final FuncN<CollectionIoEvent<MvccEntity>> zipFunction = new FuncN<CollectionIoEvent<MvccEntity>>() {
+        //
+        // Zip the results up
+        //
+        final FuncN<CollectionIoEvent<MvccEntity>> zipFunction = 
+                new FuncN<CollectionIoEvent<MvccEntity>>() {
+            
             @Override
             public CollectionIoEvent<MvccEntity> call( final Object... args ) {
 
-                for ( Object resultObj : args ) {
+                Map<String, Field> uniquenessVioloations = new HashMap<String, Field>();
 
+                for ( Object resultObj : args ) {
                     FieldUniquenessResult result = ( FieldUniquenessResult ) resultObj;
-
                     if ( !result.isUnique() ) {
                         Field field = result.getField();
-                        throw new WriteUniqueVerifyException(
-                            "Duplicate field value " + field.getName() + " = " + field.getValue().toString() );
+                        uniquenessVioloations.put( field.getName(), field );
                     }
                 }
 
+                if ( !uniquenessVioloations.isEmpty() ) {
+                    throw new WriteUniqueVerifyException( uniquenessVioloations );
+                }
+                    
                 //return the original event
                 return ioevent;
             }

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/entity/impl/MvccEntityImplTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/entity/impl/MvccEntityImplTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/entity/impl/MvccEntityImplTest.java
index 36bce42..025b195 100644
--- a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/entity/impl/MvccEntityImplTest.java
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/entity/impl/MvccEntityImplTest.java
@@ -1,17 +1,30 @@
-package org.apache.usergrid.persistence.collection.mvcc.entity.impl;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
 
+package org.apache.usergrid.persistence.collection.mvcc.entity.impl;
 
 import java.util.UUID;
-
 import org.junit.Test;
-
 import org.apache.usergrid.persistence.collection.mvcc.entity.MvccEntity;
 import org.apache.usergrid.persistence.model.entity.Entity;
 import org.apache.usergrid.persistence.model.entity.SimpleId;
 import org.apache.usergrid.persistence.model.util.UUIDGenerator;
-
 import com.google.common.base.Optional;
-
 import static org.junit.Assert.assertEquals;
 
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerifyTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerifyTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerifyTest.java
index 1d93ddb..e9b2c7f 100644
--- a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerifyTest.java
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteOptimisticVerifyTest.java
@@ -17,9 +17,13 @@
  */
 package org.apache.usergrid.persistence.collection.mvcc.stage.write;
 
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.netflix.astyanax.MutationBatch;
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.usergrid.persistence.collection.CollectionScope;
+import org.apache.usergrid.persistence.collection.exception.WriteOptimisticVerifyException;
 import org.apache.usergrid.persistence.collection.guice.TestCollectionModule;
 import org.apache.usergrid.persistence.collection.mvcc.MvccLogEntrySerializationStrategy;
 import org.apache.usergrid.persistence.collection.mvcc.entity.MvccEntity;
@@ -32,13 +36,17 @@ import static org.apache.usergrid.persistence.collection.mvcc.stage.TestEntityGe
 import static org.apache.usergrid.persistence.collection.mvcc.stage.TestEntityGenerator.generateEntity;
 import org.apache.usergrid.persistence.model.entity.Entity;
 import org.apache.usergrid.persistence.model.entity.SimpleId;
+import org.apache.usergrid.persistence.model.field.StringField;
 import org.apache.usergrid.persistence.model.util.UUIDGenerator;
 import org.jukito.UseModules;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import org.junit.Test;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import rx.Scheduler;
 
 
 @UseModules( TestCollectionModule.class )
@@ -46,8 +54,14 @@ public class WriteOptimisticVerifyTest extends AbstractMvccEntityStageTest {
 
     @Override
     protected void validateStage( final CollectionIoEvent<MvccEntity> event ) {
+
         MvccLogEntrySerializationStrategy logstrat = mock( MvccLogEntrySerializationStrategy.class);
-        new WriteOptimisticVerify( logstrat ).call( event );
+
+        UniqueValueSerializationStrategy uvstrat = mock( UniqueValueSerializationStrategy.class);
+        Injector injector = Guice.createInjector( new TestCollectionModule() );
+        Scheduler scheduler = injector.getInstance( Scheduler.class );
+
+        new WriteOptimisticVerify( logstrat, uvstrat, scheduler ).call( event );
     }
 
     @Test
@@ -60,6 +74,9 @@ public class WriteOptimisticVerifyTest extends AbstractMvccEntityStageTest {
             .thenReturn( new SimpleId( UUIDGenerator.newTimeUUID(), "owner" ) );
 
         final Entity entity = generateEntity();
+        entity.setField(new StringField("name", "FOO", true));
+        entity.setField(new StringField("identifier", "BAR", true));
+
         final MvccEntity mvccEntity = fromEntity( entity );
 
         List<MvccLogEntry> logEntries = new ArrayList<MvccLogEntry>();
@@ -70,11 +87,16 @@ public class WriteOptimisticVerifyTest extends AbstractMvccEntityStageTest {
 
         MvccLogEntrySerializationStrategy noConflictLog = 
             mock( MvccLogEntrySerializationStrategy.class );
+
         when( noConflictLog.load( collectionScope, entity.getId(), entity.getVersion(), 2) )
             .thenReturn( logEntries );
 
+        UniqueValueSerializationStrategy uvstrat = mock( UniqueValueSerializationStrategy.class);
+        Injector injector = Guice.createInjector( new TestCollectionModule() );
+        Scheduler scheduler = injector.getInstance( Scheduler.class );
+
         // Run the stage
-        WriteOptimisticVerify newStage = new WriteOptimisticVerify( noConflictLog );
+        WriteOptimisticVerify newStage = new WriteOptimisticVerify( noConflictLog, uvstrat, scheduler );
 
         CollectionIoEvent<MvccEntity> result;
         result = newStage.call( new CollectionIoEvent<MvccEntity>( collectionScope, mvccEntity ) );
@@ -95,38 +117,66 @@ public class WriteOptimisticVerifyTest extends AbstractMvccEntityStageTest {
     @Test
     public void testConflict() throws Exception {
 
-        final CollectionScope collectionScope = mock( CollectionScope.class );
-        when( collectionScope.getOrganization() )
+        final CollectionScope scope = mock( CollectionScope.class );
+        when( scope.getOrganization() )
             .thenReturn( new SimpleId( UUIDGenerator.newTimeUUID(), "organization" ) );
-        when( collectionScope.getOwner() )
+        when( scope.getOwner() )
             .thenReturn( new SimpleId( UUIDGenerator.newTimeUUID(), "owner" ) );
 
+        // there is an entity
         final Entity entity = generateEntity();
-        final MvccEntity mvccEntity = fromEntity( entity );
+        entity.setField(new StringField("name", "FOO", true));
+        entity.setField(new StringField("identifier", "BAR", true));
 
+        // log that one operation is active on entity
         List<MvccLogEntry> logEntries = new ArrayList<MvccLogEntry>();
         logEntries.add( new MvccLogEntryImpl( 
             entity.getId(), UUIDGenerator.newTimeUUID(), Stage.ACTIVE ));
+
+        // log another operation as active on entity
         logEntries.add( new MvccLogEntryImpl( 
             entity.getId(), UUIDGenerator.newTimeUUID(), Stage.ACTIVE));
 
-        MvccLogEntrySerializationStrategy noConflictLog = 
+        // mock up the log
+        MvccLogEntrySerializationStrategy conflictLog = 
             mock( MvccLogEntrySerializationStrategy.class );
-        when( noConflictLog.load( collectionScope, entity.getId(), entity.getVersion(), 2) )
+        when( conflictLog.load( scope, entity.getId(), entity.getVersion(), 2) )
             .thenReturn( logEntries );
 
-        // Run the stage
-        WriteOptimisticVerify newStage = new WriteOptimisticVerify( noConflictLog );
-
-        CollectionIoEvent<MvccEntity> result;
+        // mock up unique values interface
+        UniqueValueSerializationStrategy uvstrat = mock( UniqueValueSerializationStrategy.class);
+        UniqueValue uv1 = new UniqueValueImpl(
+            scope, entity.getField("name"), entity.getId(), entity.getVersion());
+        UniqueValue uv2 = new UniqueValueImpl(
+            scope, entity.getField("identifier"), entity.getId(), entity.getVersion());
+        MutationBatch mb = mock( MutationBatch.class );
+        when( uvstrat.delete(uv1) ).thenReturn(mb);
+        when( uvstrat.delete(uv2) ).thenReturn(mb);
+
+        // use a real scheduler
+        Injector injector = Guice.createInjector( new TestCollectionModule() );
+        Scheduler scheduler = injector.getInstance( Scheduler.class );
+
+        // Run the stage, conflict should be detected
+        final MvccEntity mvccEntity = fromEntity( entity );
         boolean conflictDetected = false;
+
+        WriteOptimisticVerify newStage = 
+            new WriteOptimisticVerify( conflictLog, uvstrat, scheduler );
+
         try {
-            result = newStage.call( new CollectionIoEvent<MvccEntity>(collectionScope, mvccEntity));
-        } catch (Exception e) {
+            newStage.call( new CollectionIoEvent<MvccEntity>(scope, mvccEntity));
+
+        } catch (WriteOptimisticVerifyException e) {
             conflictDetected = true;
         }
         assertTrue( conflictDetected );
+
+        // check that unique values were deleted
+        verify( uvstrat, times(1) ).delete( uv1 );
+        verify( uvstrat, times(1) ).delete( uv2 );
     }
+
 }
 
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerifyIT.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerifyIT.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerifyIT.java
new file mode 100644
index 0000000..3deb235
--- /dev/null
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerifyIT.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.usergrid.persistence.collection.mvcc.stage.write;
+
+
+import org.jukito.JukitoRunner;
+import org.jukito.UseModules;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.apache.usergrid.persistence.collection.CollectionScope;
+import org.apache.usergrid.persistence.collection.cassandra.CassandraRule;
+import org.apache.usergrid.persistence.collection.guice.MigrationManagerRule;
+import org.apache.usergrid.persistence.collection.guice.TestCollectionModule;
+import org.apache.usergrid.persistence.model.entity.Entity;
+import com.google.inject.Inject;
+import org.apache.usergrid.persistence.collection.EntityCollectionManager;
+import org.apache.usergrid.persistence.collection.EntityCollectionManagerFactory;
+import org.apache.usergrid.persistence.collection.exception.WriteUniqueVerifyException;
+import org.apache.usergrid.persistence.collection.impl.CollectionScopeImpl;
+import org.apache.usergrid.persistence.collection.mvcc.stage.TestEntityGenerator;
+import org.apache.usergrid.persistence.model.entity.Id;
+import org.apache.usergrid.persistence.model.entity.SimpleId;
+import org.apache.usergrid.persistence.model.field.IntegerField;
+import org.apache.usergrid.persistence.model.field.StringField;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+
+/**
+ * Simple integration test of uniqueness verification.
+ */
+@RunWith( JukitoRunner.class )
+@UseModules( TestCollectionModule.class )
+public class WriteUniqueVerifyIT {
+
+    @ClassRule
+    public static CassandraRule rule = new CassandraRule();
+
+    @Inject
+    @Rule
+    public MigrationManagerRule migrationManagerRule;
+
+    @Inject
+    public EntityCollectionManagerFactory cmf;
+
+    @Test
+    public void testConflict() {
+
+        final Id orgId = new SimpleId("WriteUniqueVerifyIT");
+        final Id appId = new SimpleId("testConflict");
+
+        final CollectionScope scope = new CollectionScopeImpl( appId, orgId, "fastcars" );
+        final EntityCollectionManager entityManager = cmf.createCollectionManager( scope );
+
+        final Entity entity = TestEntityGenerator.generateEntity();
+        entity.setField(new StringField("name", "Aston Martin Vanquish", true));
+        entity.setField(new StringField("identifier", "v12", true));
+        entity.setField(new IntegerField("top_speed_mph", 200));
+        entityManager.write( entity ).toBlockingObservable().last();
+
+        // another enity that tries to use two unique values already taken by first
+        final Entity entity2 = TestEntityGenerator.generateEntity();
+        entity2.setField(new StringField("name", "Aston Martin Vanquish", true));
+        entity2.setField(new StringField("identifier", "v12", true));
+        entity2.setField(new IntegerField("top_speed_mph", 120));
+
+        try {
+            entityManager.write( entity2 ).toBlockingObservable().last();
+            fail("Write should have thrown an exception");
+
+        } catch ( WriteUniqueVerifyException e ) {
+            // verify two unique value violations
+            assertEquals( 2, e.getVioliations().size() );
+        }
+
+    }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerifyTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerifyTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerifyTest.java
index a5d360a..6fcbf29 100644
--- a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerifyTest.java
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/stage/write/WriteUniqueVerifyTest.java
@@ -14,22 +14,6 @@
  * limitations under the License.  For additional information regarding
  * copyright in this work, please see the NOTICE file in the top level
  * directory of this distribution.
- *//*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  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.  For additional information regarding
- * copyright in this work, please see the NOTICE file in the top level
- * directory of this distribution.
  */
 package org.apache.usergrid.persistence.collection.mvcc.stage.write;
 
@@ -60,11 +44,6 @@ import static org.junit.Assert.assertSame;
 import static org.mockito.Mockito.mock;
 
 
-/**
- * TODO: Update the test to correctly test for detecting more than 1 duplicate and exception handling correctly
- *
- * @author tnine
- */
 @RunWith( JukitoRunner.class )
 @UseModules( TestCollectionModule.class )
 public class WriteUniqueVerifyTest {
@@ -96,7 +75,6 @@ public class WriteUniqueVerifyTest {
 
         final CollectionScope collectionScope = mock( CollectionScope.class );
 
-
         // set up the mock to return the entity from the start phase
         final Entity entity = generateEntity();
 
@@ -127,7 +105,6 @@ public class WriteUniqueVerifyTest {
     public void testNoFields() {
         final CollectionScope collectionScope = mock( CollectionScope.class );
 
-
         // set up the mock to return the entity from the start phase
         final Entity entity = generateEntity();
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/util/EntityBuilder.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/util/EntityBuilder.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/util/EntityBuilder.java
new file mode 100644
index 0000000..2c53041
--- /dev/null
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/util/EntityBuilder.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+
+package org.apache.usergrid.persistence.collection.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.usergrid.persistence.model.entity.Entity;
+import org.apache.usergrid.persistence.model.field.BooleanField;
+import org.apache.usergrid.persistence.model.field.DoubleField;
+import org.apache.usergrid.persistence.model.field.EntityObjectField;
+import org.apache.usergrid.persistence.model.field.Field;
+import org.apache.usergrid.persistence.model.field.FloatField;
+import org.apache.usergrid.persistence.model.field.IntegerField;
+import org.apache.usergrid.persistence.model.field.ListField;
+import org.apache.usergrid.persistence.model.field.LocationField;
+import org.apache.usergrid.persistence.model.field.LongField;
+import org.apache.usergrid.persistence.model.field.StringField;
+import org.apache.usergrid.persistence.model.field.value.Location;
+
+
+public class EntityBuilder {
+
+    public static Entity fromMap( String scope, Map<String, Object> item ) {
+        return fromMap( scope, null, item );
+    }
+
+    public static Entity fromMap( String scope, Entity entity, Map<String, Object> map ) {
+
+        if ( entity == null ) {
+            entity = new Entity();
+        }
+
+        for ( String fieldName : map.keySet() ) {
+
+            Object value = map.get( fieldName );
+
+            if ( value instanceof String ) {
+                entity.setField( new StringField( fieldName, (String)value ));
+
+            } else if ( value instanceof Boolean ) {
+                entity.setField( new BooleanField( fieldName, (Boolean)value ));
+                        
+            } else if ( value instanceof Integer ) {
+                entity.setField( new IntegerField( fieldName, (Integer)value ));
+
+            } else if ( value instanceof Double ) {
+                entity.setField( new DoubleField( fieldName, (Double)value ));
+
+		    } else if ( value instanceof Float ) {
+                entity.setField( new FloatField( fieldName, (Float)value ));
+				
+            } else if ( value instanceof Long ) {
+                entity.setField( new LongField( fieldName, (Long)value ));
+
+            } else if ( value instanceof List) {
+                entity.setField( listToListField( scope, fieldName, (List)value ));
+
+            } else if ( value instanceof Map ) {
+
+				Field field = null;
+
+				// is the map really a location element?
+				Map<String, Object> m = (Map<String, Object>)value;
+				if ( m.size() == 2) {
+					Double lat = null;
+					Double lon = null;
+					try {
+						if ( m.get("latitude") != null && m.get("longitude") != null ) {
+							lat = Double.parseDouble( m.get("latitude").toString() );
+							lon = Double.parseDouble( m.get("longitude").toString() );
+
+						} else if ( m.get("lat") != null && m.get("lon") != null ) { 
+							lat = Double.parseDouble( m.get("lat").toString() );
+							lon = Double.parseDouble( m.get("lon").toString() );
+						}
+					} catch ( NumberFormatException ignored ) {}
+
+					if ( lat != null && lon != null ) {
+						field = new LocationField( fieldName, new Location( lat, lon ));
+					}
+				}
+
+				if ( field == null ) { 
+
+					// not a location element, process it as map
+					entity.setField( new EntityObjectField( fieldName, 
+						fromMap( scope, (Map<String, Object>)value ))); // recursion
+
+				} else {
+					entity.setField( field );
+				}
+	
+			} else {
+                throw new RuntimeException("Unknown type " + value.getClass().getName());
+            }
+        }
+
+        return entity;
+    }
+
+    
+    private static ListField listToListField( String scope, String fieldName, List list ) {
+
+        if (list.isEmpty()) {
+            return new ListField( fieldName );
+        }
+
+        Object sample = list.get(0);
+
+        if ( sample instanceof Map ) {
+            return new ListField<Entity>( fieldName, processListForField( scope, list ));
+
+        } else if ( sample instanceof List ) {
+            return new ListField<List>( fieldName, processListForField( scope, list ));
+            
+        } else if ( sample instanceof String ) {
+            return new ListField<String>( fieldName, (List<String>)list );
+                    
+        } else if ( sample instanceof Boolean ) {
+            return new ListField<Boolean>( fieldName, (List<Boolean>)list );
+                    
+        } else if ( sample instanceof Integer ) {
+            return new ListField<Integer>( fieldName, (List<Integer>)list );
+
+        } else if ( sample instanceof Double ) {
+            return new ListField<Double>( fieldName, (List<Double>)list );
+
+        } else if ( sample instanceof Long ) {
+            return new ListField<Long>( fieldName, (List<Long>)list );
+
+        } else {
+            throw new RuntimeException("Unknown type " + sample.getClass().getName());
+        }
+    }
+
+    
+    private static List processListForField( String scope, List list ) {
+        if ( list.isEmpty() ) {
+            return list;
+        }
+        Object sample = list.get(0);
+
+        if ( sample instanceof Map ) {
+            List<Entity> newList = new ArrayList<Entity>();
+            for ( Map<String, Object> map : (List<Map<String, Object>>)list ) {
+                newList.add( fromMap( scope, map ) );
+            }
+            return newList;
+
+        } else if ( sample instanceof List ) {
+            return processListForField( scope, list ); // recursion
+            
+        } else { 
+            return list;
+        } 
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/collection/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/resources/log4j.properties b/stack/corepersistence/collection/src/test/resources/log4j.properties
index f6f50ef..95a0a79 100644
--- a/stack/corepersistence/collection/src/test/resources/log4j.properties
+++ b/stack/corepersistence/collection/src/test/resources/log4j.properties
@@ -1,5 +1,5 @@
 # suppress inspection "UnusedProperty" for whole file
-log4j.rootLogger=INFO,stdout
+log4j.rootLogger=DEBUG
 
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
@@ -11,4 +11,4 @@ log4j.logger.org.safehaus.chop.api.store.amazon=DEBUG
 log4j.logger.org.apache.http=ERROR
 log4j.logger.com.amazonaws.request=ERROR
 
-log4j.logger.org.apache.usergrid=DEBUG
+log4j.logger.org.apache.usergrid.persistence.collection=DEBUG

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityCollectionIndexTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityCollectionIndexTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityCollectionIndexTest.java
index e951098..68d7755 100644
--- a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityCollectionIndexTest.java
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityCollectionIndexTest.java
@@ -33,6 +33,7 @@ import org.apache.usergrid.persistence.collection.EntityCollectionManagerFactory
 import org.apache.usergrid.persistence.collection.cassandra.CassandraRule;
 import org.apache.usergrid.persistence.collection.guice.MigrationManagerRule;
 import org.apache.usergrid.persistence.collection.impl.CollectionScopeImpl;
+import org.apache.usergrid.persistence.collection.util.EntityBuilder;
 import org.apache.usergrid.persistence.collection.util.EntityUtils;
 import org.apache.usergrid.persistence.index.EntityCollectionIndex;
 import org.apache.usergrid.persistence.index.EntityCollectionIndexFactory;
@@ -43,7 +44,6 @@ import org.apache.usergrid.persistence.model.entity.SimpleId;
 import org.apache.usergrid.persistence.model.util.UUIDGenerator;
 import org.apache.usergrid.persistence.query.Query;
 import org.apache.usergrid.persistence.query.Results;
-import org.apache.usergrid.persistence.index.legacy.EntityBuilder;
 import org.jukito.JukitoRunner;
 import org.jukito.UseModules;
 import static org.junit.Assert.assertEquals;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/legacy/EntityBuilder.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/legacy/EntityBuilder.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/legacy/EntityBuilder.java
deleted file mode 100644
index fefb8fb..0000000
--- a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/legacy/EntityBuilder.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  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.  For additional information regarding
- * copyright in this work, please see the NOTICE file in the top level
- * directory of this distribution.
- */
-
-
-package org.apache.usergrid.persistence.index.legacy;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import org.apache.usergrid.persistence.model.entity.Entity;
-import org.apache.usergrid.persistence.model.field.BooleanField;
-import org.apache.usergrid.persistence.model.field.DoubleField;
-import org.apache.usergrid.persistence.model.field.EntityObjectField;
-import org.apache.usergrid.persistence.model.field.Field;
-import org.apache.usergrid.persistence.model.field.FloatField;
-import org.apache.usergrid.persistence.model.field.IntegerField;
-import org.apache.usergrid.persistence.model.field.ListField;
-import org.apache.usergrid.persistence.model.field.LocationField;
-import org.apache.usergrid.persistence.model.field.LongField;
-import org.apache.usergrid.persistence.model.field.StringField;
-import org.apache.usergrid.persistence.model.field.value.Location;
-
-
-public class EntityBuilder {
-
-    public static Entity fromMap( String scope, Map<String, Object> item ) {
-        return fromMap( scope, null, item );
-    }
-
-    public static Entity fromMap( String scope, Entity entity, Map<String, Object> map ) {
-
-        if ( entity == null ) {
-            entity = new Entity();
-        }
-
-        for ( String fieldName : map.keySet() ) {
-
-            Object value = map.get( fieldName );
-
-            if ( value instanceof String ) {
-                entity.setField( new StringField( fieldName, (String)value ));
-
-            } else if ( value instanceof Boolean ) {
-                entity.setField( new BooleanField( fieldName, (Boolean)value ));
-                        
-            } else if ( value instanceof Integer ) {
-                entity.setField( new IntegerField( fieldName, (Integer)value ));
-
-            } else if ( value instanceof Double ) {
-                entity.setField( new DoubleField( fieldName, (Double)value ));
-
-		    } else if ( value instanceof Float ) {
-                entity.setField( new FloatField( fieldName, (Float)value ));
-				
-            } else if ( value instanceof Long ) {
-                entity.setField( new LongField( fieldName, (Long)value ));
-
-            } else if ( value instanceof List) {
-                entity.setField( listToListField( scope, fieldName, (List)value ));
-
-            } else if ( value instanceof Map ) {
-
-				Field field = null;
-
-				// is the map really a location element?
-				Map<String, Object> m = (Map<String, Object>)value;
-				if ( m.size() == 2) {
-					Double lat = null;
-					Double lon = null;
-					try {
-						if ( m.get("latitude") != null && m.get("longitude") != null ) {
-							lat = Double.parseDouble( m.get("latitude").toString() );
-							lon = Double.parseDouble( m.get("longitude").toString() );
-
-						} else if ( m.get("lat") != null && m.get("lon") != null ) { 
-							lat = Double.parseDouble( m.get("lat").toString() );
-							lon = Double.parseDouble( m.get("lon").toString() );
-						}
-					} catch ( NumberFormatException ignored ) {}
-
-					if ( lat != null && lon != null ) {
-						field = new LocationField( fieldName, new Location( lat, lon ));
-					}
-				}
-
-				if ( field == null ) { 
-
-					// not a location element, process it as map
-					entity.setField( new EntityObjectField( fieldName, 
-						fromMap( scope, (Map<String, Object>)value ))); // recursion
-
-				} else {
-					entity.setField( field );
-				}
-	
-			} else {
-                throw new RuntimeException("Unknown type " + value.getClass().getName());
-            }
-        }
-
-        return entity;
-    }
-
-    
-    private static ListField listToListField( String scope, String fieldName, List list ) {
-
-        if (list.isEmpty()) {
-            return new ListField( fieldName );
-        }
-
-        Object sample = list.get(0);
-
-        if ( sample instanceof Map ) {
-            return new ListField<Entity>( fieldName, processListForField( scope, list ));
-
-        } else if ( sample instanceof List ) {
-            return new ListField<List>( fieldName, processListForField( scope, list ));
-            
-        } else if ( sample instanceof String ) {
-            return new ListField<String>( fieldName, (List<String>)list );
-                    
-        } else if ( sample instanceof Boolean ) {
-            return new ListField<Boolean>( fieldName, (List<Boolean>)list );
-                    
-        } else if ( sample instanceof Integer ) {
-            return new ListField<Integer>( fieldName, (List<Integer>)list );
-
-        } else if ( sample instanceof Double ) {
-            return new ListField<Double>( fieldName, (List<Double>)list );
-
-        } else if ( sample instanceof Long ) {
-            return new ListField<Long>( fieldName, (List<Long>)list );
-
-        } else {
-            throw new RuntimeException("Unknown type " + sample.getClass().getName());
-        }
-    }
-
-    
-    private static List processListForField( String scope, List list ) {
-        if ( list.isEmpty() ) {
-            return list;
-        }
-        Object sample = list.get(0);
-
-        if ( sample instanceof Map ) {
-            List<Entity> newList = new ArrayList<Entity>();
-            for ( Map<String, Object> map : (List<Map<String, Object>>)list ) {
-                newList.add( fromMap( scope, map ) );
-            }
-            return newList;
-
-        } else if ( sample instanceof List ) {
-            return processListForField( scope, list ); // recursion
-            
-        } else { 
-            return list;
-        } 
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/29a4966b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java
index e8eb5e1..6e52a9e 100644
--- a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/legacy/EntityManagerFacade.java
@@ -36,6 +36,7 @@ import org.apache.usergrid.persistence.model.util.UUIDGenerator;
 import org.apache.usergrid.persistence.query.EntityRef;
 import org.apache.usergrid.persistence.query.Query;
 import org.apache.usergrid.persistence.query.Results;
+import org.apache.usergrid.persistence.collection.util.EntityBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;