You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by to...@apache.org on 2013/11/27 23:24:43 UTC
[2/3] Initial import of 2.0 core persistence code.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/MvccLogEntrySerializationStrategyImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/MvccLogEntrySerializationStrategyImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/MvccLogEntrySerializationStrategyImpl.java
new file mode 100644
index 0000000..f6217a2
--- /dev/null
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/MvccLogEntrySerializationStrategyImpl.java
@@ -0,0 +1,219 @@
+package org.apache.usergrid.persistence.collection.serialization;
+
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.cassandra.db.marshal.ReversedType;
+import org.apache.cassandra.db.marshal.UUIDType;
+
+import org.apache.usergrid.persistence.collection.CollectionContext;
+import org.apache.usergrid.persistence.collection.migration.CollectionColumnFamily;
+import org.apache.usergrid.persistence.collection.migration.Migration;
+import org.apache.usergrid.persistence.collection.mvcc.entity.MvccLogEntry;
+import org.apache.usergrid.persistence.collection.mvcc.entity.MvccLogEntryImpl;
+import org.apache.usergrid.persistence.collection.mvcc.entity.Stage;
+
+import com.google.common.base.Preconditions;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import com.netflix.astyanax.ColumnListMutation;
+import com.netflix.astyanax.Keyspace;
+import com.netflix.astyanax.MutationBatch;
+import com.netflix.astyanax.connectionpool.OperationResult;
+import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+import com.netflix.astyanax.connectionpool.exceptions.NotFoundException;
+import com.netflix.astyanax.model.Column;
+import com.netflix.astyanax.model.ColumnFamily;
+import com.netflix.astyanax.serializers.UUIDSerializer;
+
+
+/**
+ * Simple implementation for reading and writing log entries
+ *
+ * @author tnine
+ */
+@Singleton
+public class MvccLogEntrySerializationStrategyImpl implements MvccLogEntrySerializationStrategy, Migration {
+
+ public static final String TIMEOUT_PROP = "collection.stage.transient.timeout";
+
+ private static final ColumnFamily<UUID, UUID> CF_ENTITY_LOG =
+ new ColumnFamily<UUID, UUID>( "Entity_Log", UUIDSerializer.get(), UUIDSerializer.get() );
+
+ /**
+ * Used for caching the byte => stage mapping
+ */
+ private static final StageCache CACHE = new StageCache();
+
+
+ protected final Keyspace keyspace;
+ protected final int timeout;
+
+
+ @Inject
+ public MvccLogEntrySerializationStrategyImpl( final Keyspace keyspace, @Named( TIMEOUT_PROP ) final int timeout ) {
+ this.keyspace = keyspace;
+ this.timeout = timeout;
+ }
+
+
+ @Override
+ public MutationBatch write( final MvccLogEntry entry ) {
+
+ Preconditions.checkNotNull( entry, "entry is required" );
+
+
+ final Stage stage = entry.getStage();
+ final UUID colName = entry.getVersion();
+ final byte colValue = stage.getId();
+
+ return doWrite( entry.getContext(), entry.getEntityId(), new RowOp() {
+ @Override
+ public void doOp( final ColumnListMutation<UUID> colMutation ) {
+
+ //Write the stage with a timeout, it's set as transient
+ if ( stage.isTransient() ) {
+ colMutation.putColumn( colName, colValue, timeout );
+ return;
+ }
+
+ //otherwise it's persistent, write it with no expiration
+ colMutation.putColumn( colName, colValue );
+ }
+ } );
+ }
+
+
+ @Override
+ public MvccLogEntry load( final CollectionContext context, final UUID entityId, final UUID version )
+ throws ConnectionException {
+ Preconditions.checkNotNull( context, "context is required" );
+ Preconditions.checkNotNull( entityId, "entity id is required" );
+ Preconditions.checkNotNull( version, "version is required" );
+
+
+ Column<UUID> result = null;
+
+ try {
+ OperationResult<Column<UUID>>
+ foo = keyspace.prepareQuery( CF_ENTITY_LOG ).getKey( entityId ).getColumn( version ).execute();
+
+ result = foo.getResult();
+ }
+ catch ( NotFoundException nfe ) {
+ return null;
+ }
+
+ if ( result == null ) {
+ return null;
+ }
+
+ final byte stored = result.getByteValue();
+
+
+ final Stage stage = CACHE.getStage( stored );
+
+ Preconditions.checkNotNull( "No stage was found for byte value " + stored + ". This is a migration data bug" );
+
+ return new MvccLogEntryImpl( context, entityId, version, stage );
+ }
+
+
+ @Override
+ public List<MvccLogEntry> load( final CollectionContext context, final UUID entityId, final UUID version,
+ final int maxSize ) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+
+ @Override
+ public MutationBatch delete( final CollectionContext context, final UUID entityId, final UUID version ) {
+
+ Preconditions.checkNotNull( context, "context is required" );
+ Preconditions.checkNotNull( entityId, "entityId is required" );
+ Preconditions.checkNotNull( version, "version context is required" );
+
+ return doWrite( context, entityId, new RowOp() {
+ @Override
+ public void doOp( final ColumnListMutation<UUID> colMutation ) {
+ colMutation.deleteColumn( version );
+ }
+ } );
+ }
+
+
+ @Override
+ public Collection<CollectionColumnFamily> getColumnFamilies() {
+ //create the CF entity data. We want it reversed b/c we want the most recent version at the top of the
+ //row for fast seeks
+ CollectionColumnFamily cf = new CollectionColumnFamily( CF_ENTITY_LOG,
+ ReversedType.class.getName() + "(" + UUIDType.class.getName() + ")", true );
+
+
+ return Collections.singleton( cf );
+ }
+
+
+ /**
+ * Simple callback to perform puts and deletes with a common row setup code
+ */
+ private static interface RowOp {
+
+ /**
+ * The operation to perform on the row
+ */
+ void doOp( ColumnListMutation<UUID> colMutation );
+ }
+
+
+ /**
+ * Do the column update or delete for the given column and row key
+ *
+ * @param context We need to use this when getting the keyspace
+ */
+ private MutationBatch doWrite( CollectionContext context, UUID entityId, RowOp op ) {
+
+ final MutationBatch batch = keyspace.prepareMutationBatch();
+
+ op.doOp( batch.withRow( CF_ENTITY_LOG, entityId ) );
+
+ return batch;
+ }
+
+
+ /**
+ * Internal stage cache
+ */
+ private static class StageCache {
+ private Map<Byte, Stage> values = new HashMap<Byte, Stage>( Stage.values().length );
+
+
+ private StageCache() {
+ for ( Stage stage : Stage.values() ) {
+
+ final byte stageValue = stage.getId();
+
+ if ( values.containsKey( stageValue ) ) {
+ throw new RuntimeException(
+ "There are two Stages assigned to the byte " + stageValue + ". This is a bug" );
+ }
+
+ values.put( stageValue, stage );
+ }
+ }
+
+
+ /**
+ * Get the stage with the byte value
+ */
+ private Stage getStage( final byte value ) {
+ return values.get( value );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/CollectionManagerFactoryTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/CollectionManagerFactoryTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/CollectionManagerFactoryTest.java
new file mode 100644
index 0000000..4450efe
--- /dev/null
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/CollectionManagerFactoryTest.java
@@ -0,0 +1,8 @@
+package org.apache.usergrid.persistence.collection;
+
+
+/**
+ * Basic tests
+ * @author tnine
+ */
+public class CollectionManagerFactoryTest {}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/guice/TestCollectionModule.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/guice/TestCollectionModule.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/guice/TestCollectionModule.java
new file mode 100644
index 0000000..3ea6e62
--- /dev/null
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/guice/TestCollectionModule.java
@@ -0,0 +1,103 @@
+package org.apache.usergrid.persistence.collection.guice;
+
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.cassandra.locator.SimpleStrategy;
+
+import org.apache.usergrid.persistence.collection.astynax.AstynaxKeyspaceProvider;
+import org.apache.usergrid.persistence.collection.migration.MigrationException;
+import org.apache.usergrid.persistence.collection.migration.MigrationManager;
+import org.apache.usergrid.persistence.collection.migration.MigrationManagerImpl;
+import org.apache.usergrid.persistence.collection.serialization.MvccLogEntrySerializationStrategyImpl;
+import org.apache.usergrid.persistence.test.CassandraRule;
+
+import com.google.guiceberry.GuiceBerryEnvMain;
+import com.google.guiceberry.GuiceBerryModule;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.name.Names;
+
+
+/**
+ * Simple module for wiring our collection api
+ *
+ * @author tnine
+ */
+public class TestCollectionModule extends AbstractModule {
+
+
+ public TestCollectionModule() {
+ }
+
+
+ @Override
+ protected void configure() {
+
+
+ //import the guice berry module
+ install( new GuiceBerryModule() );
+
+ //now configure our db
+ bind( GuiceBerryEnvMain.class ).to( CassAppMain.class );
+
+ //import the runtime module
+ install( new CollectionModule() );
+
+
+ //configure our integration test properties. This should remain the same across all tests
+
+ Map<String, String> configProperties = new HashMap<String, String>();
+ configProperties.put( AstynaxKeyspaceProvider.CASSANDRA_HOSTS, "localhost" );
+ configProperties.put( AstynaxKeyspaceProvider.CASSANDRA_PORT, "" + CassandraRule.THRIFT_PORT );
+ configProperties.put( AstynaxKeyspaceProvider.CASSANDRA_CONNECTIONS, "10" );
+ configProperties.put( AstynaxKeyspaceProvider.CASSANDRA_CLUSTER_NAME, "Usergrid" );
+ configProperties.put( AstynaxKeyspaceProvider.CASSANDRA_VERSION, "1.2" );
+ configProperties.put( AstynaxKeyspaceProvider.COLLECTIONS_KEYSPACE_NAME, "Usergrid_Collections" );
+
+ configProperties.put( MigrationManagerImpl.REPLICATION_FACTOR, "1" );
+ configProperties.put( MigrationManagerImpl.STRATEGY_CLASS, SimpleStrategy.class.getName() );
+
+ /**
+ * Set the timeout to 60 seconds, no test should take that long for load+delete without a failure
+ */
+ configProperties.put( MvccLogEntrySerializationStrategyImpl.TIMEOUT_PROP, 60+"" );
+
+ Map<String, String> props = getOverrides();
+
+ if(props != null){
+ configProperties.putAll( props );
+ }
+
+ //bind to the props
+ Names.bindProperties( binder(), configProperties );
+ }
+
+
+ /**
+ * Get any overrides we need for system properties
+ */
+ public Map<String, String> getOverrides() {
+ return null;
+ }
+
+
+ static class CassAppMain implements GuiceBerryEnvMain {
+
+ @Inject
+ protected MigrationManager migrationManager;
+
+
+ public void run() {
+ try {
+ //run the injected migration manager to set up cassandra
+ migrationManager.migrate();
+ }
+ catch ( MigrationException e ) {
+ throw new RuntimeException( e );
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/entity/StageTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/entity/StageTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/entity/StageTest.java
new file mode 100644
index 0000000..0090e64
--- /dev/null
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/mvcc/entity/StageTest.java
@@ -0,0 +1,91 @@
+package org.apache.usergrid.persistence.collection.mvcc.entity;
+
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+/**
+ * @author tnine
+ */
+public class StageTest {
+
+ @Test
+ public void active() {
+
+ assertTrue( Stage.ACTIVE.isTransient() );
+
+ assertEquals( ( byte ) 0, Stage.ACTIVE.getId() );
+
+ testUnique( Stage.ACTIVE );
+ }
+
+
+ @Test
+ public void rollback() {
+
+ assertTrue( Stage.ROLLBACK.isTransient() );
+
+ assertEquals( ( byte ) 1, Stage.ROLLBACK.getId() );
+
+ testUnique( Stage.ROLLBACK );
+ }
+
+
+ @Test
+ public void comitted() {
+
+ assertFalse( Stage.COMMITTED.isTransient() );
+
+ assertEquals( ( byte ) 2, Stage.COMMITTED.getId() );
+
+ testUnique( Stage.COMMITTED );
+ }
+
+
+
+
+ @Test
+ public void postProcess() {
+
+ assertFalse( Stage.POSTPROCESS.isTransient() );
+
+ assertEquals( ( byte ) 6, Stage.POSTPROCESS.getId() );
+
+ testUnique( Stage.POSTPROCESS );
+ }
+
+
+ @Test
+ public void complete() {
+
+ assertFalse( Stage.COMPLETE.isTransient() );
+
+ assertEquals( ( byte ) 14, Stage.COMPLETE.getId() );
+
+ testUnique( Stage.COMPLETE );
+ }
+
+
+ /**
+ * Test we don't have dups in the byte value
+ * @param test
+ */
+ private void testUnique( Stage test ) {
+
+ for ( Stage stage : Stage.values() ) {
+
+ //skip self
+ if ( stage == test ) {
+ continue;
+ }
+
+ assertFalse( stage.getId() == test.getId() );
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/MvccEntitySerializationStrategyImplTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/MvccEntitySerializationStrategyImplTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/MvccEntitySerializationStrategyImplTest.java
new file mode 100644
index 0000000..a3bcead
--- /dev/null
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/MvccEntitySerializationStrategyImplTest.java
@@ -0,0 +1,343 @@
+package org.apache.usergrid.persistence.collection.serialization;
+
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.cassandra.db.marshal.UUIDType;
+
+import org.apache.usergrid.persistence.collection.CollectionContext;
+import org.apache.usergrid.persistence.collection.CollectionContextImpl;
+import org.apache.usergrid.persistence.collection.guice.TestCollectionModule;
+import org.apache.usergrid.persistence.collection.mvcc.entity.MvccEntity;
+import org.apache.usergrid.persistence.collection.mvcc.entity.MvccEntityImpl;
+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.Field;
+import org.apache.usergrid.persistence.model.field.IntegerField;
+import org.apache.usergrid.persistence.model.field.LongField;
+import org.apache.usergrid.persistence.model.field.StringField;
+import org.apache.usergrid.persistence.model.field.UUIDField;
+import org.apache.usergrid.persistence.model.util.UUIDGenerator;
+import org.apache.usergrid.persistence.test.CassandraRule;
+
+import com.google.common.base.Optional;
+import com.google.guiceberry.junit4.GuiceBerryRule;
+import com.google.inject.Inject;
+import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+import com.netflix.astyanax.serializers.UUIDSerializer;
+import com.netflix.astyanax.util.TimeUUIDUtils;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNull;
+import static org.junit.Assert.assertTrue;
+
+
+/**
+ * @author tnine
+ */
+public class MvccEntitySerializationStrategyImplTest {
+
+ @Rule
+ public final GuiceBerryRule guiceBerry = new GuiceBerryRule( TestCollectionModule.class );
+
+ @Rule
+ public final CassandraRule rule = new CassandraRule();
+
+ @Inject
+ private MvccEntitySerializationStrategy serializationStrategy;
+
+
+ @Test
+ public void writeLoadDelete() throws ConnectionException {
+
+ final UUID applicationId = UUIDGenerator.newTimeUUID();
+ final String name = "test";
+
+ CollectionContext context = new CollectionContextImpl( applicationId, applicationId, name );
+
+
+ final UUID entityId = UUIDGenerator.newTimeUUID();
+ final UUID version = UUIDGenerator.newTimeUUID();
+ final String type = "test";
+ final long created = 1l;
+ final long updated = 2l;
+
+ Entity entity = new Entity( entityId, type );
+
+ entity.setVersion( version );
+ entity.setCreated( created );
+ entity.setUpdated( updated );
+
+
+ BooleanField boolField = new BooleanField( "boolean", false );
+ DoubleField doubleField = new DoubleField( "double", 1d );
+ IntegerField intField = new IntegerField( "long", 1 );
+ LongField longField = new LongField( "int", 1l );
+ StringField stringField = new StringField( "name", "test" );
+ UUIDField uuidField = new UUIDField( "uuid", UUIDGenerator.newTimeUUID() );
+
+ entity.setField( boolField );
+ entity.setField( doubleField );
+ entity.setField( intField );
+ entity.setField( longField );
+ entity.setField( stringField );
+ entity.setField( uuidField );
+
+
+ MvccEntity saved = new MvccEntityImpl( context, entityId, version, Optional.of( entity ) );
+
+
+ //persist the entity
+ serializationStrategy.write( saved ).execute();
+
+ //now read it back
+
+ MvccEntity returned = serializationStrategy.load( context, entityId, version );
+
+ assertEquals( "Mvcc entities are the same", saved, returned );
+
+
+ assertEquals( entityId, entity.getUuid() );
+ assertEquals( type, entity.getType() );
+ assertEquals( created, entity.getCreated() );
+ assertEquals( updated, entity.getUpdated() );
+
+
+ Field<Boolean> boolFieldReturned = entity.getField( boolField.getName() );
+
+ assertSame( boolField, boolFieldReturned );
+
+ Field<Double> doubleFieldReturned = entity.getField( doubleField.getName() );
+
+ assertSame( doubleField, doubleFieldReturned );
+
+ Field<Integer> intFieldReturned = entity.getField( intField.getName() );
+
+ assertSame( intField, intFieldReturned );
+
+ Field<Long> longFieldReturned = entity.getField( longField.getName() );
+
+ assertSame( longField, longFieldReturned );
+
+ Field<String> stringFieldReturned = entity.getField( stringField.getName() );
+
+ assertSame( stringField, stringFieldReturned );
+
+ Field<UUID> uuidFieldReturned = entity.getField( uuidField.getName() );
+
+ assertSame( uuidField, uuidFieldReturned );
+
+
+ Set<Field> results = new HashSet<Field>();
+ results.addAll( entity.getFields() );
+
+
+ assertTrue( results.contains( boolField ) );
+ assertTrue( results.contains( doubleField ) );
+ assertTrue( results.contains( intField ) );
+ assertTrue( results.contains( longField ) );
+ assertTrue( results.contains( stringField ) );
+ assertTrue( results.contains( uuidField ) );
+
+ assertEquals( 6, results.size() );
+
+
+ assertEquals( entityId, entity.getUuid() );
+ assertEquals( version, entity.getVersion() );
+
+
+ //now delete it
+ serializationStrategy.delete( context, entityId, version ).execute();
+
+ //now get it, should be gone
+
+ returned = serializationStrategy.load( context, entityId, version );
+
+ assertNull( returned );
+ }
+
+
+ @Test
+ public void writeLoadClearDelete() throws ConnectionException {
+
+ final UUID applicationId = UUIDGenerator.newTimeUUID();
+ final String name = "test";
+
+ CollectionContext context = new CollectionContextImpl( applicationId, applicationId, name );
+
+
+ final UUID entityId = UUIDGenerator.newTimeUUID();
+ final UUID version = UUIDGenerator.newTimeUUID();
+ final String type = "test";
+ final long created = 1l;
+ final long updated = 2l;
+
+ Entity entity = new Entity( entityId, type );
+
+ entity.setVersion( version );
+ entity.setCreated( created );
+ entity.setUpdated( updated );
+
+
+ MvccEntity saved = new MvccEntityImpl( context, entityId, version, Optional.of( entity ) );
+
+
+ //persist the entity
+ serializationStrategy.write( saved ).execute();
+
+ //now read it back
+
+ MvccEntity returned = serializationStrategy.load( context, entityId, version );
+
+ assertEquals( "Mvcc entities are the same", saved, returned );
+
+
+ assertEquals( entityId, entity.getUuid() );
+ assertEquals( type, entity.getType() );
+ assertEquals( created, entity.getCreated() );
+ assertEquals( updated, entity.getUpdated() );
+
+
+ //now clear it
+
+ serializationStrategy.clear( context, entityId, version ).execute();
+
+ returned = serializationStrategy.load( context, entityId, version );
+
+ assertEquals( context, returned.getContext() );
+ assertEquals( entityId, returned.getUuid() );
+ assertEquals( version, returned.getVersion() );
+ assertFalse( returned.getEntity().isPresent() );
+
+ //now delete it
+ serializationStrategy.delete( context, entityId, version ).execute();
+
+ //now get it, should be gone
+
+ returned = serializationStrategy.load( context, entityId, version );
+
+ assertNull( returned );
+ }
+
+
+ @Test
+ public void writeX2ClearDelete() throws ConnectionException {
+
+ final UUID applicationId = UUIDGenerator.newTimeUUID();
+ final String name = "test";
+
+ CollectionContext context = new CollectionContextImpl( applicationId, applicationId, name );
+
+
+ final UUID entityId = UUIDGenerator.newTimeUUID();
+ final UUID version1 = UUIDGenerator.newTimeUUID();
+ final String type = "test";
+
+ Entity entityv1 = new Entity( entityId, type );
+
+ entityv1.setVersion( version1 );
+
+
+ MvccEntity saved = new MvccEntityImpl( context, entityId, version1, Optional.of( entityv1 ) );
+
+
+ //persist the entity
+ serializationStrategy.write( saved ).execute();
+
+ //now read it back
+
+ MvccEntity returnedV1 = serializationStrategy.load( context, entityId, version1 );
+
+ assertEquals( "Mvcc entities are the same", saved, returnedV1 );
+
+
+ assertEquals( entityId, entityv1.getUuid() );
+ assertEquals( type, entityv1.getType() );
+
+
+ //now write a new version of it
+
+
+ Entity entityv2 = new Entity( entityId, type );
+
+ UUID version2 = UUIDGenerator.newTimeUUID();
+ entityv2.setVersion( version2 );
+
+
+ UUIDType comparator = UUIDType.instance;
+
+ int value = comparator.compare( UUIDSerializer.get().toByteBuffer( version1 ), UUIDSerializer.get().toByteBuffer( version2 ) );
+
+ assertTrue(value < 0);
+
+ value = comparator.compare( UUIDSerializer.get().toByteBuffer( version2 ), UUIDSerializer.get().toByteBuffer( version2 ) );
+
+ assertEquals(0, value);
+
+ MvccEntity savedV2 = new MvccEntityImpl( context, entityId, version2, Optional.of( entityv2 ) );
+
+ serializationStrategy.write( savedV2 ).execute();
+
+ MvccEntity returnedV2 = serializationStrategy.load( context, entityId, version2 );
+
+ assertEquals( "Mvcc entities are the same", savedV2, returnedV2 );
+
+
+ //now clear it at v3
+
+ UUID version3 = UUIDGenerator.newTimeUUID();
+
+ serializationStrategy.clear( context, entityId, version3 ).execute();
+
+
+ final Optional<Entity> empty = Optional.absent();
+
+ MvccEntity clearedV3 = new MvccEntityImpl( context, entityId, version3, empty );
+
+ MvccEntity returnedV3 = serializationStrategy.load( context, entityId, version3 );
+
+ assertEquals("entities are the same", clearedV3, returnedV3);
+
+ //now ask for up to 10 versions from the current version, we should get cleared, v2, v1
+ UUID current = UUIDGenerator.newTimeUUID();
+
+ List<MvccEntity> entities = serializationStrategy.load( context, entityId, current, 3 );
+
+ assertEquals( 3, entities.size() );
+
+ assertEquals( clearedV3, entities.get( 0 ) );
+
+ assertEquals( returnedV2, entities.get( 1 ) );
+
+ assertEquals( returnedV1, entities.get( 2 ) );
+
+
+ //now delete v2 and v1, we should still get v3
+ serializationStrategy.delete( context, entityId, version1 ).execute();
+ serializationStrategy.delete( context, entityId, version2 ).execute();
+
+ entities = serializationStrategy.load( context, entityId, current, 3 );
+
+ assertEquals( 1, entities.size() );
+
+ assertEquals( clearedV3, entities.get( 0 ) );
+
+
+ //now get it, should be gone
+ serializationStrategy.delete( context, entityId, version3 ).execute();
+
+
+ entities = serializationStrategy.load( context, entityId, current, 3 );
+
+ assertEquals( 0, entities.size() );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/MvccLogEntrySerializationStrategyImplTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/MvccLogEntrySerializationStrategyImplTest.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/MvccLogEntrySerializationStrategyImplTest.java
new file mode 100644
index 0000000..c66fac2
--- /dev/null
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/MvccLogEntrySerializationStrategyImplTest.java
@@ -0,0 +1,150 @@
+package org.apache.usergrid.persistence.collection.serialization;
+
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.usergrid.persistence.collection.CollectionContext;
+import org.apache.usergrid.persistence.collection.CollectionContextImpl;
+import org.apache.usergrid.persistence.collection.guice.TestCollectionModule;
+import org.apache.usergrid.persistence.collection.mvcc.entity.MvccLogEntry;
+import org.apache.usergrid.persistence.collection.mvcc.entity.MvccLogEntryImpl;
+import org.apache.usergrid.persistence.collection.mvcc.entity.Stage;
+import org.apache.usergrid.persistence.model.util.UUIDGenerator;
+import org.apache.usergrid.persistence.test.CassandraRule;
+
+import com.google.guiceberry.GuiceBerryEnvSelector;
+import com.google.guiceberry.TestDescription;
+import com.google.guiceberry.junit4.GuiceBerryRule;
+import com.google.inject.Inject;
+import com.google.inject.Module;
+import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+
+import static junit.framework.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+
+/**
+ * @author tnine
+ */
+public class MvccLogEntrySerializationStrategyImplTest {
+
+
+ /**
+ * Set our timeout to 1 seconds. If it works for 1 seconds, we'll be good a any value
+ */
+ private static final int TIMEOUT = 1;
+
+
+ @Rule
+ public final GuiceBerryRule guiceBerry = new GuiceBerryRule( new TimeoutModMapper() );
+
+ @Rule
+ public final CassandraRule rule = new CassandraRule();
+
+ @Inject
+ private MvccLogEntrySerializationStrategy logEntryStrategy;
+
+
+ @Test
+ public void createAndDelete() throws ConnectionException {
+
+ final UUID applicationId = UUIDGenerator.newTimeUUID();
+ final String name = "test";
+
+
+ CollectionContext context = new CollectionContextImpl( applicationId, applicationId, name );
+
+
+ final UUID uuid = UUIDGenerator.newTimeUUID();
+ final UUID version = UUIDGenerator.newTimeUUID();
+
+ for ( Stage stage : Stage.values() ) {
+ MvccLogEntry saved = new MvccLogEntryImpl( context, uuid, version, stage );
+ logEntryStrategy.write( saved ).execute();
+
+ //Read it back
+
+ MvccLogEntry returned = logEntryStrategy.load( context, uuid, version );
+
+ assertNotNull( "Returned value should not be null", returned );
+
+ assertEquals( "Returned should equal the saved", saved, returned );
+ }
+ }
+
+
+ @Test
+ public void transientTimeout() throws ConnectionException, InterruptedException {
+
+ final UUID applicationId = UUIDGenerator.newTimeUUID();
+ final String name = "test";
+
+
+ CollectionContext context = new CollectionContextImpl( applicationId, applicationId, name );
+
+
+ final UUID uuid = UUIDGenerator.newTimeUUID();
+ final UUID version = UUIDGenerator.newTimeUUID();
+
+ for ( Stage stage : Stage.values() ) {
+
+ MvccLogEntry saved = new MvccLogEntryImpl( context, uuid, version, stage );
+ logEntryStrategy.write( saved ).execute();
+
+ //Read it back after the timeout
+
+ Thread.sleep( TIMEOUT * 1000 );
+
+ MvccLogEntry returned = logEntryStrategy.load( context, uuid, version );
+
+
+ if ( stage.isTransient() ) {
+
+ assertNull( "Active is transient and should time out", returned );
+ }
+ else {
+ assertNotNull( "Committed is not transient and should be returned", returned );
+
+ assertEquals( "Returned should equal the saved", saved, returned );
+ }
+ }
+ }
+
+
+ /**
+ * Mapper that will change which module we implement based on the test case
+ */
+ public static class TimeoutModMapper implements GuiceBerryEnvSelector {
+
+ @Override
+ public Class<? extends Module> guiceBerryEnvToUse( final TestDescription testDescription ) {
+
+ //in this edge case, we want to truncate the timeout to 1 second for this test, override the env to use
+ //this module setup
+ if ( (MvccLogEntrySerializationStrategyImplTest.class.getName()+".transientTimeout").equals( testDescription.getName() ) ) {
+ return TimeoutEnv.class;
+ }
+
+ //by default, we wnat to run the TestCollectionModule
+ return TestCollectionModule.class;
+ }
+ }
+
+
+ public static class TimeoutEnv extends TestCollectionModule {
+
+ @Override
+ public Map<String, String> getOverrides() {
+ Map<String, String> timeout = new HashMap<String, String>();
+ timeout.put( MvccLogEntrySerializationStrategyImpl.TIMEOUT_PROP, TIMEOUT + "" );
+ return timeout;
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/SerializationComparison.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/SerializationComparison.java b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/SerializationComparison.java
new file mode 100644
index 0000000..a78293b
--- /dev/null
+++ b/stack/corepersistence/collection/src/test/java/org/apache/usergrid/persistence/collection/serialization/SerializationComparison.java
@@ -0,0 +1,182 @@
+package org.apache.usergrid.persistence.collection.serialization;
+
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.smile.SmileFactory;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.usergrid.persistence.model.entity.Entity;
+import org.apache.usergrid.persistence.model.field.ArrayField;
+import org.apache.usergrid.persistence.model.field.BooleanField;
+import org.apache.usergrid.persistence.model.field.ByteBufferField;
+import org.apache.usergrid.persistence.model.field.DoubleField;
+import org.apache.usergrid.persistence.model.field.EntityObjectField;
+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.SetField;
+import org.apache.usergrid.persistence.model.field.StringField;
+import org.apache.usergrid.persistence.model.field.UUIDField;
+import org.apache.usergrid.persistence.model.util.UUIDGenerator;
+import org.apache.usergrid.persistence.model.value.EntityObject;
+import org.apache.usergrid.persistence.model.value.Location;
+
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.io.ByteBufferInputStream;
+import com.esotericsoftware.kryo.io.ByteBufferOutputStream;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+
+
+/**
+ * TODO We need to get both of these serialization methods working, and benchmark them for comparison
+ * Neither works out of the box for us without custom work.
+ * @author tnine
+ */
+public class SerializationComparison {
+
+ private static final Logger logger = LoggerFactory.getLogger( SerializationComparison.class );
+
+ private static final int count = 10000;
+
+
+ @Test
+ @Ignore
+ public void smileSerialization() throws IOException {
+ SmileFactory smile = new SmileFactory();
+
+ ObjectMapper smileMapper = new ObjectMapper( smile );
+
+
+ Entity entity = createEntity();
+
+ long writeTime = 0;
+ long readTime = 0;
+
+ for ( int i = 0; i < count; i++ ) {
+
+ //capture time in nannos for write
+ long writeStart = System.nanoTime();
+
+ byte[] smileData = smileMapper.writeValueAsBytes( entity );
+
+ writeTime += System.nanoTime() - writeStart;
+
+ long readStart = System.nanoTime();
+
+ Entity otherValue = smileMapper.readValue( smileData, Entity.class );
+
+ readTime += System.nanoTime() - readStart;
+ }
+
+ logger.info( "Smile took {} nanos for writing {} entities", writeTime, count );
+ logger.info( "Smile took {} nanos for reading {} entities", readTime, count );
+ }
+
+
+ @Test
+ @Ignore
+ public void kyroSerialization() {
+ Kryo kryo = new Kryo();
+
+ //container classes
+ kryo.register( Entity.class );
+
+ kryo.register( EntityObject.class );
+ kryo.register( Location.class );
+
+
+ //field classes
+ kryo.register( ArrayField.class );
+ kryo.register( BooleanField.class );
+ kryo.register( ByteBufferField.class );
+ kryo.register( DoubleField.class );
+ kryo.register( EntityObjectField.class );
+ kryo.register( IntegerField.class );
+ kryo.register( ListField.class );
+ kryo.register( LocationField.class );
+ kryo.register( LongField.class );
+ kryo.register( SetField.class );
+ kryo.register( StringField.class );
+ kryo.register( UUIDField.class, new de.javakaffee.kryoserializers.UUIDSerializer() );
+
+
+ long writeTime = 0;
+ long readTime = 0;
+
+ for ( int i = 0; i < count; i++ ) {
+
+ //capture time in nanos for write
+ long writeStart = System.nanoTime();
+
+ ByteBuffer data = ByteBuffer.allocate( 1024 );
+ ByteBufferOutputStream byteBuffOutputStream = new ByteBufferOutputStream(data);
+ Output output = new Output( byteBuffOutputStream );
+
+ Entity entity = createEntity();
+
+ kryo.writeObject( output, entity );
+ output.close();
+
+ writeTime += System.nanoTime() - writeStart;
+
+ data.rewind();
+
+ long readStart = System.nanoTime();
+
+
+ Input input = new Input( new ByteBufferInputStream( data ) );
+ Entity loaded = kryo.readObject( input, Entity.class );
+ input.close();
+
+ readTime += System.nanoTime() - readStart;
+ }
+
+ logger.info( "Smile took {} nanos for writing {} entities", writeTime, count );
+ logger.info( "Smile took {} nanos for reading {} entities", readTime, count );
+ }
+
+
+ private Entity createEntity() {
+
+ final UUID entityId = UUIDGenerator.newTimeUUID();
+
+ final UUID version = UUIDGenerator.newTimeUUID();
+
+ Entity entity = new Entity( entityId, "test" );
+ entity.setCreated( 1l );
+ entity.setUpdated( 2l );
+ entity.setVersion( version );
+
+
+ BooleanField boolField = new BooleanField( "boolean", false );
+ DoubleField doubleField = new DoubleField( "double", 1d );
+ IntegerField intField = new IntegerField( "long", 1 );
+ LongField longField = new LongField( "int", 1l );
+ StringField stringField = new StringField( "name", "test" );
+ UUIDField uuidField = new UUIDField( "uuid", UUIDGenerator.newTimeUUID() );
+
+ entity.setField( boolField );
+ entity.setField( doubleField );
+ entity.setField( intField );
+ entity.setField( longField );
+ entity.setField( stringField );
+ entity.setField( uuidField );
+
+ return entity;
+ }
+
+
+}
+
+
+
+
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/collection/src/test/resources/cassandra.properties
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/test/resources/cassandra.properties b/stack/corepersistence/collection/src/test/resources/cassandra.properties
new file mode 100644
index 0000000..a69c771
--- /dev/null
+++ b/stack/corepersistence/collection/src/test/resources/cassandra.properties
@@ -0,0 +1,5 @@
+#Purposefully left empty, we override this in our module code to KISS The runtime requires this file however
+#Boostrapping should fail fast if it's not present
+
+
+
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/index/pom.xml
----------------------------------------------------------------------
diff --git a/stack/corepersistence/index/pom.xml b/stack/corepersistence/index/pom.xml
new file mode 100644
index 0000000..85c2a0b
--- /dev/null
+++ b/stack/corepersistence/index/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>persistence</artifactId>
+ <groupId>org.apache.usergrid</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>index</artifactId>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.usergrid</groupId>
+ <artifactId>collection</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/Query.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/Query.java b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/Query.java
new file mode 100644
index 0000000..69fdb3f
--- /dev/null
+++ b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/Query.java
@@ -0,0 +1,6 @@
+package org.apache.usergrid.persistence.index;
+
+
+/** Interface of our query implementation */
+public interface Query
+{}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/QueryEngine.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/QueryEngine.java b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/QueryEngine.java
new file mode 100644
index 0000000..631c027
--- /dev/null
+++ b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/QueryEngine.java
@@ -0,0 +1,22 @@
+package org.apache.usergrid.persistence.index;
+
+
+import org.apache.usergrid.persistence.model.entity.Entity;
+
+
+/**
+ *
+ * @author: tnine
+ *
+ */
+public interface QueryEngine
+{
+
+
+ /** Search and return the entities */
+ public Results<Entity> search( Query query );
+
+
+ /** Search the query, but parse the entities into the given class We may not need to implement this at first */
+ public <T> Results<T> search( Query query, Class<T> clazz );
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/QueryEngineFactory.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/QueryEngineFactory.java b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/QueryEngineFactory.java
new file mode 100644
index 0000000..1358a4e
--- /dev/null
+++ b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/QueryEngineFactory.java
@@ -0,0 +1,21 @@
+package org.apache.usergrid.persistence.index;
+
+
+import org.apache.usergrid.persistence.collection.CollectionContext;
+
+
+/**
+ *
+ * @author: tnine
+ *
+ */
+public interface QueryEngineFactory
+{
+
+ /**
+ * Create an index manager for the collection context
+ *
+ * @param context The context to use when creating the index manager
+ */
+ public QueryEngineFactory createIndexManager( CollectionContext context );
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/Results.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/Results.java b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/Results.java
new file mode 100644
index 0000000..bc4646e
--- /dev/null
+++ b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/Results.java
@@ -0,0 +1,16 @@
+package org.apache.usergrid.persistence.index;
+
+
+import java.util.Iterator;
+
+
+/**
+ *
+ * @author: tnine
+ *
+ */
+public interface Results<Entity> extends Iterable<Entity>, Iterator<Entity>
+{
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Complete.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Complete.java b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Complete.java
new file mode 100644
index 0000000..da051b6
--- /dev/null
+++ b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Complete.java
@@ -0,0 +1,21 @@
+package org.apache.usergrid.persistence.index.stage;
+
+
+import org.apache.usergrid.persistence.collection.mvcc.entity.MvccEntity;
+import org.apache.usergrid.persistence.collection.mvcc.stage.WriteStage;
+
+
+/**
+ *
+ * @author: tnine
+ *
+ */
+public class Complete implements WriteStage
+{
+
+ @Override
+ public MvccEntity performStage( final MvccEntity entity ) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Start.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Start.java b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Start.java
new file mode 100644
index 0000000..a89e2af
--- /dev/null
+++ b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Start.java
@@ -0,0 +1,16 @@
+package org.apache.usergrid.persistence.index.stage;
+
+
+import org.apache.usergrid.persistence.collection.mvcc.entity.MvccEntity;
+import org.apache.usergrid.persistence.collection.mvcc.stage.WriteStage;
+
+
+/** This state should signal an index update has started */
+public class Start implements WriteStage
+{
+
+ @Override
+ public MvccEntity performStage( final MvccEntity entity ) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Write.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Write.java b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Write.java
new file mode 100644
index 0000000..8e75812
--- /dev/null
+++ b/stack/corepersistence/index/src/main/java/org/apache/usergrid/persistence/index/stage/Write.java
@@ -0,0 +1,17 @@
+package org.apache.usergrid.persistence.index.stage;
+
+
+import org.apache.usergrid.persistence.collection.mvcc.entity.MvccEntity;
+import org.apache.usergrid.persistence.collection.mvcc.stage.WriteStage;
+
+
+/** This state should perform an update of the index. */
+public class Write implements WriteStage
+{
+
+ @Override
+ public MvccEntity performStage( final MvccEntity entity ) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/pom.xml
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/pom.xml b/stack/corepersistence/model/pom.xml
new file mode 100644
index 0000000..a79af0b
--- /dev/null
+++ b/stack/corepersistence/model/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>persistence</artifactId>
+ <groupId>org.apache.usergrid</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>model</artifactId>
+
+ <!-- Runtime Dependencies -->
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>15.0</version>
+ </dependency>
+
+ <!-- Time UUID library -->
+ <dependency>
+ <groupId>com.fasterxml.uuid</groupId>
+ <artifactId>java-uuid-generator</artifactId>
+ <version>3.1.3</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.11</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/entity/Entity.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/entity/Entity.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/entity/Entity.java
new file mode 100644
index 0000000..83cca40
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/entity/Entity.java
@@ -0,0 +1,149 @@
+package org.apache.usergrid.persistence.model.entity;
+
+
+import java.util.UUID;
+
+import org.apache.usergrid.persistence.model.value.EntityObject;
+
+import com.google.common.base.Preconditions;
+
+
+/**
+ * Simple entity that is used for persistence. It has 4 required properties. <p/> uuid: The uuid of the entity type:
+ * The entity name (user, car, restaurant etc) created: The time the entity was created in millis since epoch updated:
+ * The time the entity was updated in millis since epoch;
+ */
+public class Entity extends EntityObject {
+
+
+ /**
+ * The entity type. This must be set
+ */
+ private String type;
+
+ /**
+ * The generated uuid. This should never be set by a user
+ */
+ private UUID uuid;
+
+ /**
+ * The version of this entity. Options, since it can be used for optimistic locking
+ */
+ private UUID version;
+
+ /**
+ * The time in milliseconds since epoch the entity was created
+ */
+ private long created;
+
+ /**
+ * The time in milliseconds since epoch the entity was updated
+ */
+ private long updated;
+
+
+ /**
+ * Create an entity with no uuid. This should be used for creating new entities
+ */
+ public Entity( String type ) {
+ Preconditions.checkNotNull( type, "Type must not be null" );
+ Preconditions.checkArgument( type.length() > 0, "Type must have a length" );
+ this.type = type;
+ }
+
+
+ /**
+ * Create an entity with the given type and uuid. Should be used for all update operations to an existing entity
+ */
+ public Entity( UUID uuid, String type ) {
+ this( type );
+
+ Preconditions.checkNotNull( uuid, "uuid must not be null" );
+
+ this.uuid = uuid;
+ }
+
+
+ /**
+ * Do not use! This is only for serialization.
+ */
+ public Entity() {
+
+ }
+
+
+ public UUID getUuid() {
+ return uuid;
+ }
+
+
+ public String getType() {
+ return type;
+ }
+
+
+ public UUID getVersion() {
+ return version;
+ }
+
+
+ public void setVersion( final UUID version ) {
+ this.version = version;
+ }
+
+
+ /**
+ * Should only be invoked by the persistence framework
+ */
+ public void setCreated( long created ) {
+ this.created = created;
+ }
+
+
+ /**
+ * Should only be invoked by the persistence framework
+ */
+ public void setUpdated( long updated ) {
+ this.updated = updated;
+ }
+
+
+ public long getCreated() {
+ return created;
+ }
+
+
+ public long getUpdated() {
+ return updated;
+ }
+
+
+ @Override
+ public boolean equals( Object o ) {
+ if ( this == o ) {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+
+ Entity entity = ( Entity ) o;
+
+ if ( type != null ? !type.equals( entity.type ) : entity.type != null ) {
+ return false;
+ }
+ if ( uuid != null ? !uuid.equals( entity.uuid ) : entity.uuid != null ) {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + ( uuid != null ? uuid.hashCode() : 0 );
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/AbstractField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/AbstractField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/AbstractField.java
new file mode 100644
index 0000000..674c7a7
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/AbstractField.java
@@ -0,0 +1,85 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import org.apache.usergrid.persistence.model.value.EntityObject;
+
+
+/** Base class for data information */
+public abstract class AbstractField<T> implements Field<T>
+{
+
+
+ /**
+ * Set the object this field belongs to
+ */
+ protected EntityObject parent;
+ protected String name;
+ protected T value;
+
+
+ /**
+ * Name and value must always be present.
+ *
+ * @param name The name of this field
+ * @param value The value to set. If value is null, this means that the value should be explicitly removed from
+ * the field storage
+ */
+ protected AbstractField( String name, T value )
+ {
+ this.name = name;
+ this.value = value;
+ }
+
+
+ /**
+ * Default constructor for serialization
+ */
+ protected AbstractField(){
+
+ }
+
+
+
+
+ public String getName()
+ {
+ return name;
+ }
+
+
+ @Override
+ public T getValue()
+ {
+ return value;
+ }
+
+
+ @Override
+ public boolean equals( Object o )
+ {
+ if ( this == o )
+ {
+ return true;
+ }
+ if ( o == null || getClass() != o.getClass() )
+ {
+ return false;
+ }
+
+ AbstractField that = ( AbstractField ) o;
+
+ if ( !name.equals( that.name ) )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public int hashCode()
+ {
+ return name.hashCode();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ArrayField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ArrayField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ArrayField.java
new file mode 100644
index 0000000..cb5f45d
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ArrayField.java
@@ -0,0 +1,27 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/** A marker to signal array handling. Just delegates to list field for easier handling internally */
+public class ArrayField extends ListField
+{
+
+ /** Contructor that intializes with an empty set for adding to later */
+ public ArrayField( String name )
+ {
+ super(name);
+ }
+
+ public ArrayField(){
+ super();
+ }
+
+ /** Add the value to the list */
+ public void add( Field field )
+ {
+ value.add( field );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/BooleanField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/BooleanField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/BooleanField.java
new file mode 100644
index 0000000..3948b27
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/BooleanField.java
@@ -0,0 +1,19 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+/**
+ *
+ * @author: tnine
+ *
+ */
+public class BooleanField extends AbstractField<Boolean> {
+
+ public BooleanField( String name, Boolean value ) {
+ super( name, value );
+ }
+
+
+ public BooleanField() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ByteBufferField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ByteBufferField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ByteBufferField.java
new file mode 100644
index 0000000..2dbc193
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ByteBufferField.java
@@ -0,0 +1,29 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import java.nio.ByteBuffer;
+
+
+/** A field for storing byte buffers */
+public class ByteBufferField extends AbstractField<ByteBuffer>
+{
+
+
+ /** Creates an immutable copy of the byte buffer */
+ public ByteBufferField( String name, ByteBuffer value )
+ {
+ //always return a duplicate so we don't mess with the markers
+ super( name, value.duplicate() );
+ }
+
+ public ByteBufferField() {
+
+ }
+
+ @Override
+ public ByteBuffer getValue()
+ {
+ //always return a duplicate so we don't mess with the markers
+ return value.duplicate();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/DoubleField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/DoubleField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/DoubleField.java
new file mode 100644
index 0000000..729560c
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/DoubleField.java
@@ -0,0 +1,20 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+/**
+ *
+ * @author: tnine
+ *
+ */
+public class DoubleField extends AbstractField<Double>
+{
+
+ public DoubleField( String name, Double value )
+ {
+ super( name, value );
+ }
+
+ public DoubleField() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/EntityObjectField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/EntityObjectField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/EntityObjectField.java
new file mode 100644
index 0000000..4031a81
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/EntityObjectField.java
@@ -0,0 +1,20 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import org.apache.usergrid.persistence.model.value.EntityObject;
+
+
+/** An object field */
+public class EntityObjectField extends AbstractField<EntityObject>
+{
+
+
+ public EntityObjectField( String name, EntityObject value )
+ {
+ super( name, value );
+ }
+
+ public EntityObjectField() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/Field.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/Field.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/Field.java
new file mode 100644
index 0000000..5061d49
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/Field.java
@@ -0,0 +1,28 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import java.io.Serializable;
+
+import org.apache.usergrid.persistence.model.value.EntityObject;
+
+
+/**
+ * Interface for fields. All fields must implement this method The T is the type of field (in the java runtime) The V
+ * is the value of the field
+ */
+public interface Field<T> extends Serializable {
+
+ /**
+ * Get the name of the field
+ * @return
+ */
+ public String getName();
+
+ /**
+ * Get the value of the field
+ * @return
+ */
+ public T getValue();
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/IntegerField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/IntegerField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/IntegerField.java
new file mode 100644
index 0000000..9c807e0
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/IntegerField.java
@@ -0,0 +1,20 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+/**
+ *
+ * @author: tnine
+ *
+ */
+public class IntegerField extends AbstractField<Integer>
+{
+
+ public IntegerField( String name, Integer value )
+ {
+ super( name, value );
+ }
+
+ public IntegerField() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ListField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ListField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ListField.java
new file mode 100644
index 0000000..0795201
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/ListField.java
@@ -0,0 +1,28 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/** An object field that represents a list of objects. This can also be used to represent arrays */
+public class ListField extends AbstractField<List<Field>>
+{
+
+ /** Contructor that intializes with an empty set for adding to later */
+ public ListField( String name )
+ {
+ super( name, new ArrayList<Field>() );
+ }
+
+ public ListField(){
+ super();
+ }
+
+
+ /** Add the value to the list */
+ public void add( Field field )
+ {
+ value.add( field );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/LocationField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/LocationField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/LocationField.java
new file mode 100644
index 0000000..5d9fd57
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/LocationField.java
@@ -0,0 +1,20 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import org.apache.usergrid.persistence.model.value.Location;
+
+
+/** Basic field for storing location data */
+public class LocationField extends AbstractField<Location>
+{
+
+ /** Create a location field with the given point */
+ public LocationField( String name, Location value )
+ {
+ super( name, value );
+ }
+
+ public LocationField() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/LongField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/LongField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/LongField.java
new file mode 100644
index 0000000..c56b514
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/LongField.java
@@ -0,0 +1,23 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+/**
+ *
+ * @author: tnine
+ *
+ */
+public class LongField extends AbstractField<Long>
+{
+
+ public LongField( String name, Long value )
+ {
+ super( name, value );
+ }
+
+ public LongField() {
+
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/SetField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/SetField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/SetField.java
new file mode 100644
index 0000000..f28b5ec
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/SetField.java
@@ -0,0 +1,28 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+
+/** An object field that represents a set of objects */
+public class SetField extends AbstractField<Set<Field>>
+{
+
+
+ /** Contructor that intializes with an empty set for adding to later */
+ public SetField( String name )
+ {
+ super( name, new LinkedHashSet<Field>() );
+ }
+
+ public SetField() {
+
+ }
+
+ /** Add an entry to the set */
+ public void addEntry( Field field )
+ {
+ value.add( field );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/StringField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/StringField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/StringField.java
new file mode 100644
index 0000000..bcb8b2d
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/StringField.java
@@ -0,0 +1,17 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+/** A String field */
+public class StringField extends AbstractField<String>
+{
+
+
+ public StringField( String name, String value )
+ {
+ super( name, value );
+ }
+
+ public StringField() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/UUIDField.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/UUIDField.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/UUIDField.java
new file mode 100644
index 0000000..11dfc22
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/UUIDField.java
@@ -0,0 +1,20 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import java.util.UUID;
+
+
+/** A String field */
+public class UUIDField extends AbstractField<UUID>
+{
+
+
+ public UUIDField( String name, UUID value )
+ {
+ super( name, value );
+ }
+
+ public UUIDField() {
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/util/UUIDGenerator.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/util/UUIDGenerator.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/util/UUIDGenerator.java
new file mode 100644
index 0000000..687e27b
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/util/UUIDGenerator.java
@@ -0,0 +1,106 @@
+package org.apache.usergrid.persistence.model.util;
+
+
+import java.io.IOException;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import com.fasterxml.uuid.EthernetAddress;
+import com.fasterxml.uuid.TimestampSynchronizer;
+import com.fasterxml.uuid.UUIDTimer;
+import com.fasterxml.uuid.impl.TimeBasedGenerator;
+
+
+/**
+ *
+ * @author: tnine
+ *
+ */
+public class UUIDGenerator
+{
+
+
+ private static final TimestampSynchronizer synchronizer = new TimestampSynchronizer()
+ {
+
+ /**
+ * Pointer to the last value we returned
+ */
+ private long last = 0;
+
+ /**
+ * The number of ticks that can be used in the millisecond. In a time UUID a tick is divided into 1/10000 of
+ * a millisecond
+ *
+ */
+ private AtomicInteger ticks = new AtomicInteger();
+
+
+ @Override
+ protected long initialize() throws IOException
+ {
+
+ last = System.currentTimeMillis();
+ return last;
+ }
+
+
+ @Override
+ protected void deactivate() throws IOException
+ {
+ //no op
+ }
+
+
+ @Override
+ protected long update( long now ) throws IOException
+ {
+ /**
+ * It's greater
+ */
+ if ( now > last )
+ {
+ last = now;
+ ticks.set( 0 );
+ return last;
+ }
+
+ //we have the same value (since now should always be increasing) increment a tick
+ last = now + ticks.incrementAndGet();
+
+ return last;
+ }
+ };
+
+
+ private static final Random random = new Random();
+ private static final UUIDTimer timer;
+
+
+ /**
+ * Lame, but required
+ */
+ static
+ {
+ try
+ {
+ timer = new UUIDTimer( random, synchronizer );
+ }
+ catch ( IOException e )
+ {
+ throw new RuntimeException( "Couldn't intialize timer", e );
+ }
+ }
+
+
+ private static final TimeBasedGenerator generator =
+ new TimeBasedGenerator( EthernetAddress.fromInterface(), timer );
+
+
+ /** Create a new time uuid */
+ public static UUID newTimeUUID()
+ {
+ return generator.generate();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/value/EntityObject.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/value/EntityObject.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/value/EntityObject.java
new file mode 100644
index 0000000..5f02053
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/value/EntityObject.java
@@ -0,0 +1,40 @@
+package org.apache.usergrid.persistence.model.value;
+
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.usergrid.persistence.model.field.Field;
+
+
+/** Simple wrapper for holding nested objects */
+public class EntityObject implements Serializable
+{
+
+
+ /** Fields the users can set */
+ private Map<String, Field> fields = new HashMap<String, Field>();
+
+
+ /** Add the field, return the old one if it existed */
+ public <T extends java.lang.Object> Field<T> setField( Field<T> value )
+ {
+ return fields.put( value.getName(), value );
+ }
+
+
+ /** Get the field by name the user has set into the entity */
+ public <T extends java.lang.Object> Field<T> getField( String name )
+ {
+ return fields.get( name );
+ }
+
+
+ /** Get all fields in the entity */
+ public Collection<Field> getFields()
+ {
+ return fields.values();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/value/Location.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/value/Location.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/value/Location.java
new file mode 100644
index 0000000..4370aa1
--- /dev/null
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/value/Location.java
@@ -0,0 +1,32 @@
+package org.apache.usergrid.persistence.model.value;
+
+
+import java.io.Serializable;
+
+
+/** Geographic point. Should be used when we want to store geo information */
+public class Location implements Serializable
+{
+
+ private final double latitude;
+ private final double longtitude;
+
+
+ public Location( double latitude, double longtitude )
+ {
+ this.latitude = latitude;
+ this.longtitude = longtitude;
+ }
+
+
+ public double getLatitude()
+ {
+ return latitude;
+ }
+
+
+ public double getLongtitude()
+ {
+ return longtitude;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/model/src/test/java/org/apache/usergrid/persistence/model/field/EntityTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/test/java/org/apache/usergrid/persistence/model/field/EntityTest.java b/stack/corepersistence/model/src/test/java/org/apache/usergrid/persistence/model/field/EntityTest.java
new file mode 100644
index 0000000..9f94b18
--- /dev/null
+++ b/stack/corepersistence/model/src/test/java/org/apache/usergrid/persistence/model/field/EntityTest.java
@@ -0,0 +1,117 @@
+package org.apache.usergrid.persistence.model.field;
+
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.UUID;
+
+import org.junit.Test;
+
+import org.apache.usergrid.persistence.model.entity.Entity;
+import org.apache.usergrid.persistence.model.util.UUIDGenerator;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+
+/** Simple test for validating stored entities */
+public class EntityTest
+{
+
+ @Test
+ public void testPutAndGet()
+ {
+
+
+ final UUID uuid = UUIDGenerator.newTimeUUID();
+ final UUID version = UUIDGenerator.newTimeUUID();
+ final String type = "test";
+ final long created = 1l;
+ final long updated = 2l;
+
+ Entity entity = new Entity( uuid, type );
+
+ entity.setVersion( version );
+ entity.setCreated( created );
+ entity.setUpdated( updated );
+
+ assertEquals( uuid, entity.getUuid() );
+ assertEquals( type, entity.getType() );
+ assertEquals( created, entity.getCreated() );
+ assertEquals( updated, entity.getUpdated() );
+
+
+ BooleanField boolField = new BooleanField( "boolean", false );
+ DoubleField doubleField = new DoubleField( "double", 1d );
+ IntegerField intField = new IntegerField( "long", 1 );
+ LongField longField = new LongField( "int", 1l );
+ StringField stringField = new StringField( "name", "test" );
+ UUIDField uuidField = new UUIDField( "uuid", UUIDGenerator.newTimeUUID() );
+
+ entity.setField( boolField );
+ entity.setField( doubleField );
+ entity.setField( intField );
+ entity.setField( longField );
+ entity.setField( stringField );
+ entity.setField( uuidField );
+
+ Field<Boolean> boolFieldReturned = entity.getField( boolField.getName() );
+
+ assertSame( boolField, boolFieldReturned );
+
+ Field<Double> doubleFieldReturned = entity.getField( doubleField.getName() );
+
+ assertSame( doubleField, doubleFieldReturned );
+
+ Field<Integer> intFieldReturned = entity.getField( intField.getName() );
+
+ assertSame( intField, intFieldReturned );
+
+ Field<Long> longFieldReturned = entity.getField( longField.getName() );
+
+ assertSame( longField, longFieldReturned );
+
+ Field<String> stringFieldReturned = entity.getField( stringField.getName() );
+
+ assertSame( stringField, stringFieldReturned );
+
+ Field<UUID> uuidFieldReturned = entity.getField( uuidField.getName() );
+
+ assertSame( uuidField, uuidFieldReturned );
+
+
+ Set<Field> results = new HashSet<Field>();
+ results.addAll( entity.getFields() );
+
+
+ assertTrue( results.contains( boolField ) );
+ assertTrue( results.contains( doubleField ) );
+ assertTrue( results.contains( intField ) );
+ assertTrue( results.contains( longField ) );
+ assertTrue( results.contains( stringField ) );
+ assertTrue( results.contains( uuidField ) );
+
+ assertEquals( 6, results.size() );
+
+
+ assertEquals( uuid, entity.getUuid() );
+ assertEquals( version, entity.getVersion() );
+ }
+
+
+ @Test( expected = NullPointerException.class )
+ public void uuidRequired()
+ {
+ new Entity( null, "test" );
+ }
+
+
+ @Test( expected = NullPointerException.class )
+ public void versionRequired()
+ {
+ final UUID uuid = UUIDGenerator.newTimeUUID();
+
+ new Entity( uuid, null );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/perftest/Readme.md
----------------------------------------------------------------------
diff --git a/stack/corepersistence/perftest/Readme.md b/stack/corepersistence/perftest/Readme.md
new file mode 100644
index 0000000..8061dda
--- /dev/null
+++ b/stack/corepersistence/perftest/Readme.md
@@ -0,0 +1,52 @@
+# A Simple Performance Testing Framework on AWS
+
+This is a simple performance testing framework designed to pound the heck out
+of a clustered persistence teir. It is designed as a web application that
+can be run on several tomcat or jetty servers to bombard in unison an in JVM
+API that operates against a clustered data storage layer like Cassandra.
+
+## Setting up a Perftest
+
+The framework simply executes a number of calls which you specify using a
+Perftest implementation class. This class specifies all the parameters as
+methods and is construct by the framework using a TestModule (a guice module)
+which you also provide.
+
+The framework simply loads your TestModule and uses its Guice Injector to
+create the Perftest instance. It coordinates executing calls against the
+Perftest instance across the set of servers containing the framework. SimpleDB
+is used to communicate presence to all the nodes of the workers so they can
+find each other and coordinate their calls at the same time against the
+Perftest instance.
+
+The following endpoints are used to control the framework:
+
+ * /perftest/start
+ * /perftest/stop
+ * /perftest/reset
+ * /perftest/stats
+
+The following ascii text shows the states of the framework which one can
+go through while issuing POSTs to the end points above:
+
+ start stop
+ +-----+ +-------+ +-------+
+ ---+ready+-------+running+-----+stopped|
+ +--+--+ +-------+ +---+---+
+ | |
+ |____________________________|
+ reset
+
+A post to a single node issues the same POST to all the nodes in the cluster.
+
+## Dependencies
+
+It uses the following libraries to do what it does:
+
+* Jersey - for REST services
+* Jackson - for JSON <--> Java marshalling
+* Guice - for the DI container
+* Archaius - for dynamic properties
+* Blitz4j - for asynchronous logging
+* Slf4j - API for binding to Blitz4j
+
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ac634a1d/stack/corepersistence/perftest/pom.xml
----------------------------------------------------------------------
diff --git a/stack/corepersistence/perftest/pom.xml b/stack/corepersistence/perftest/pom.xml
new file mode 100644
index 0000000..b5c70ee
--- /dev/null
+++ b/stack/corepersistence/perftest/pom.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>persistence</artifactId>
+ <groupId>org.apache.usergrid</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>perftest</artifactId>
+ <packaging>war</packaging>
+ <description>Simple Performance Testing Framework</description>
+
+ <properties>
+ <slf4j.version>1.6.1</slf4j.version>
+ <blitz4j.version>1.31</blitz4j.version>
+ <archaius.version>0.4.1</archaius.version>
+ <servo.version>0.4.36</servo.version>
+ <jersey.version>1.9.1</jersey.version>
+ <jackson.version>2.1.5</jackson.version>
+ <fastxml.version>2.3.0-SNAPSHOT</fastxml.version>
+ <jetty.plugin.version>8.1.14.v20131031</jetty.plugin.version>
+ <jetty.version>9.1.0.M0</jetty.version>
+ <log4j.version>1.2.17</log4j.version>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <guice.version>3.0</guice.version>
+ </properties>
+
+ <build>
+ <finalName>${pom.artifactId}</finalName>
+
+ <plugins>
+ <plugin>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-maven-plugin</artifactId>
+ <version>${jetty.plugin.version}</version>
+ <configuration>
+ <scanIntervalSeconds>5</scanIntervalSeconds>
+ <webApp>
+ <contextPath>/</contextPath>
+ </webApp>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-server</artifactId>
+ <version>${jersey.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.sun.jersey.contribs</groupId>
+ <artifactId>jersey-guice</artifactId>
+ <version>${jersey.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.jaxrs</groupId>
+ <artifactId>jackson-jaxrs-json-provider</artifactId>
+ <version>${jackson.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.module</groupId>
+ <artifactId>jackson-module-guice</artifactId>
+ <version>${fastxml.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <version>${guice.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.inject.extensions</groupId>
+ <artifactId>guice-multibindings</artifactId>
+ <version>${guice.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.inject.extensions</groupId>
+ <artifactId>guice-servlet</artifactId>
+ <version>${guice.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-servlet</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.netflix.archaius</groupId>
+ <artifactId>archaius-core</artifactId>
+ <version>${archaius.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.netflix.blitz4j</groupId>
+ <artifactId>blitz4j</artifactId>
+ <version>${blitz4j.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.netflix.archaius</groupId>
+ <artifactId>archaius-aws</artifactId>
+ <version>${archaius.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>${slf4j.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>${slf4j.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <!-- Test RelatedDependencies -->
+
+ <dependency>
+ <groupId>com.google.guiceberry</groupId>
+ <artifactId>guiceberry</artifactId>
+ <version>3.3.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
+