You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/01/28 23:21:52 UTC

[42/96] [abbrv] [partial] Change package namespace to org.apache.usergrid

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/EntityFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityFactory.java b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityFactory.java
new file mode 100644
index 0000000..f633afc
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityFactory.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.usergrid.persistence;
+
+
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/** A factory for creating Entity objects. */
+public class EntityFactory {
+
+    /** The Constant logger. */
+    private static final Logger logger = LoggerFactory.getLogger( EntityFactory.class );
+
+
+    /**
+     * New entity.
+     *
+     * @param <A> the generic type
+     * @param id the id
+     * @param type the type
+     * @param entityClass the entity class
+     *
+     * @return new entity
+     */
+    public static <A extends Entity> A newEntity( UUID id, String type, Class<A> entityClass ) {
+        if ( type == null ) {
+            String errorMsg = "Entity type cannot be null";
+            logger.error( errorMsg );
+            throw new IllegalArgumentException( errorMsg );
+        }
+        if ( "entity".equalsIgnoreCase( type ) || "dynamicentity".equalsIgnoreCase( type ) ) {
+            String errorMsg = "Unable to instantiate entity (" + type + ") because that is not a valid type.";
+            logger.error( errorMsg );
+            throw new IllegalArgumentException( errorMsg );
+        }
+        Class<? extends Entity> expectedCls = Schema.getDefaultSchema().getEntityClass( type );
+
+        if ( entityClass == null ) {
+            if ( expectedCls != null ) {
+                entityClass = ( Class<A> ) expectedCls;
+            }
+            else {
+                entityClass = ( Class<A> ) DynamicEntity.class;
+            }
+        }
+
+        if ( ( expectedCls != null ) && !Entity.class.isAssignableFrom( entityClass ) && !expectedCls
+                .isAssignableFrom( entityClass ) ) {
+            String errorMsg = "Unable to instantiate entity (" + type
+                    + ") because type and entityClass do not match, either use DynamicClass as entityClass or fix " +
+                    "mismatch.";
+            logger.error( errorMsg );
+            throw new IllegalArgumentException( errorMsg );
+        }
+        else {
+            try {
+                A entity = entityClass.newInstance();
+                entity.setUuid( id );
+                entity.setType( type );
+                return entity;
+            }
+            catch ( IllegalAccessException e ) {
+                String errorMsg = "Unable to access entity (" + type + "): " + e.getMessage();
+                logger.error( errorMsg );
+            }
+            catch ( InstantiationException e ) {
+                String errorMsg = "Unable to instantiate entity (" + type + "): " + e.getMessage();
+                logger.error( errorMsg );
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * New entity.
+     *
+     * @param <A> the generic type
+     * @param id the id
+     * @param entityClass the entity class
+     *
+     * @return new entity
+     */
+    public static <A extends Entity> A newEntity( UUID id, Class<A> entityClass ) {
+
+        if ( entityClass == DynamicEntity.class ) {
+            return null;
+        }
+
+        String type = Schema.getDefaultSchema().getEntityType( entityClass );
+
+        return newEntity( id, type, entityClass );
+    }
+
+
+    /**
+     * New entity.
+     *
+     * @param id the id
+     * @param type the type
+     *
+     * @return new entity
+     */
+    public static Entity newEntity( UUID id, String type ) {
+
+        Class<? extends Entity> entityClass = Schema.getDefaultSchema().getEntityClass( type );
+        if ( entityClass == null ) {
+            entityClass = DynamicEntity.class;
+        }
+
+        return newEntity( id, type, entityClass );
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManager.java b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManager.java
new file mode 100644
index 0000000..fac6071
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManager.java
@@ -0,0 +1,605 @@
+package org.apache.usergrid.persistence;
+
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.usergrid.persistence.Results.Level;
+import org.apache.usergrid.persistence.cassandra.GeoIndexManager;
+import org.apache.usergrid.persistence.entities.Application;
+import org.apache.usergrid.persistence.entities.Role;
+
+
+/**
+ * The interface class for the data access object for Applications. Each application contains a set of users as well as
+ * a hierarchy of groups. A application also includes a set of message inboxes and a set of assets.
+ */
+public interface EntityManager {
+
+    public void setApplicationId( UUID applicationId );
+
+    public GeoIndexManager getGeoIndexManager();
+
+    public EntityRef getApplicationRef();
+
+    public Application getApplication() throws Exception;
+
+    public void updateApplication( Application app ) throws Exception;
+
+    public void updateApplication( Map<String, Object> properties ) throws Exception;
+
+    public RelationManager getRelationManager( EntityRef entityRef );
+
+    /** Get all collections for the application. Includes both user defined collections and schema collections */
+    public Set<String> getApplicationCollections() throws Exception;
+
+    public Map<String, Object> getApplicationCollectionMetadata() throws Exception;
+
+    public long getApplicationCollectionSize( String collectionName ) throws Exception;
+
+    /**
+     * Creates an entity of the specified type attached to the specified application.
+     *
+     * @param type the type of the entity to create.
+     * @param properties property values to create in the new entity or null.
+     *
+     * @return the newly created entity object.
+     */
+    public Entity create( String entityType, Map<String, Object> properties ) throws Exception;
+
+    public <A extends Entity> A create( String entityType, Class<A> entityClass, Map<String, Object> properties )
+            throws Exception;
+
+    public <A extends TypedEntity> A create( A entity ) throws Exception;
+
+    /**
+     * Creates an entity of the specified type attached to the specified application.
+     *
+     * @param importId the UUID to assign to the imported entity
+     * @param type the type of the entity to create.
+     * @param properties property values to create in the new entity or null.
+     *
+     * @return the newly created entity object.
+     *
+     * @throws Exception the exception
+     */
+    public Entity create( UUID importId, String entityType, Map<String, Object> properties ) throws Exception;
+
+    public void createApplicationCollection( String entityType ) throws Exception;
+
+    public EntityRef getAlias( String aliasType, String alias ) throws Exception;
+
+    /**
+     * Get the entity ref from the value
+     *
+     * @param ownerId The owner Id of the collection
+     * @param collectionName The name of the collection
+     * @param aliasValue The value of the alias
+     */
+    public EntityRef getAlias( UUID ownerId, String collectionName, String aliasValue ) throws Exception;
+
+    public Map<String, EntityRef> getAlias( String aliasType, List<String> aliases ) throws Exception;
+
+    /**
+     * Get aliases from the index with the given value
+     *
+     * @param ownerId The id of the collection owner
+     * @param collectionName The name of the collection
+     * @param aliases The alias property
+     */
+    public Map<String, EntityRef> getAlias( UUID ownerId, String collectionName, List<String> aliases )
+            throws Exception;
+
+    /**
+     * Validates that the entity exists in the datastore meaning that it exists and the type has been loaded if not
+     * already provided.
+     *
+     * @return an validated EntityRef or null.
+     */
+    public EntityRef validate( EntityRef entityRef ) throws Exception;
+
+    public String getType( UUID entityId ) throws Exception;
+
+    public EntityRef getRef( UUID entityId ) throws Exception;
+
+    public Entity get( UUID entityId ) throws Exception;
+
+    /**
+     * Retrieves the entity for the specified entity reference.
+     *
+     * @param entity an Entity reference
+     *
+     * @return an Entity object for the specified entity reference.
+     */
+    public Entity get( EntityRef entityRef ) throws Exception;
+
+    public <A extends Entity> A get( UUID entityId, Class<A> entityClass ) throws Exception;
+
+    /**
+     * Retrieves a set of Entities. Will return an Entity object containing all of the entity's name/value properties
+     * and properties. For large numbers of entities, retrieving the properties can have additional overhead, passing
+     * false for includeProperties can result in better performance.
+     * <p/>
+     * This method will be deprecated in future releases in favor of a version that supports paging.
+     *
+     * @param entityIds a list of entity UUIDs.
+     * @param includeProperties whether to retrieve properties for the specified entities.
+     *
+     * @return a list of entity objects.
+     */
+    public Results get( Collection<UUID> entityIds, Results.Level resultsLevel ) throws Exception;
+
+    /**
+     * Retrieves a set of Entities. Will return an Entity object containing all of the entity's name/value properties
+     * and properties. For large numbers of entities, retrieving the properties can have additional overhead, passing
+     * false for includeProperties can result in better performance.
+     * <p/>
+     * This method will be deprecated in future releases in favor of a version that supports paging.
+     *
+     * @param entityIds a list of entity UUIDs.
+     * @param includeProperties whether to retrieve properties for the specified entities.
+     *
+     * @return a list of entity objects.
+     */
+    public Results get( Collection<UUID> entityIds ) throws Exception;
+
+    /**
+     * Retrieves a set of Entitues cast to the specified class type.
+     *
+     * @return a list of entity objects.
+     */
+    public Results get( Collection<UUID> entityIds, Class<? extends Entity> entityClass, Results.Level resultsLevel )
+            throws Exception;
+
+    /**
+     * Retrieves a set of Entities cast to the specified class type.
+     *
+     * @return a list of entity objects.
+     */
+    public Results get( Collection<UUID> entityIds, String entityType, Class<? extends Entity> entityClass,
+                        Results.Level resultsLevel ) throws Exception;
+
+    /**
+     * Updates the entity with the properties and values in the Entity Object.
+     *
+     * @param entity an Entity object.
+     */
+    public void update( Entity entity ) throws Exception;
+
+    /**
+     * Gets the value for a named entity property. Entity properties must be defined in the schema
+     *
+     * @param entity an entity reference
+     * @param propertyName the property name to retrieve.
+     *
+     * @return the value of the named property or null.
+     *
+     * @throws Exception the exception
+     */
+    public Object getProperty( EntityRef entityRef, String propertyName ) throws Exception;
+
+    /**
+     * Do a single load of all entities with the given properties.  Efficient if you have a subset of properties, and
+     * know the ids of them.  The entity UUID is in the key, the runtime subtype of Entity is in the value.  Note that
+     * if an entity cannot be loaded (id doesn't exist) it is simply ignored
+     */
+    public List<Entity> getPartialEntities( Collection<UUID> ids, Collection<String> properties ) throws Exception;
+
+    /**
+     * Gets the properties for the specified entity property.
+     *
+     * @param entity an entity reference
+     *
+     * @return the property values.
+     *
+     * @throws Exception the exception
+     */
+    public Map<String, Object> getProperties( EntityRef entityRef ) throws Exception;
+
+    /**
+     * Sets the value for a named entity property. If the property is being index, the index is updated to remove the
+     * old value and add the new value.
+     *
+     * @param entity an entity reference
+     * @param propertyName the property to set.
+     * @param propertyValue new value for property.
+     *
+     * @throws Exception the exception
+     */
+    public void setProperty( EntityRef entityRef, String propertyName, Object propertyValue ) throws Exception;
+
+    /**
+     * You should only use this method if you are absolutely sure what you're doing. Use setProperty without the
+     * override param in most cases. With great power comes great responsibility....
+     *
+     * @param override set to true to force this value to persist. This will ignore all mutable attributes as well as
+     * validation. Use with care
+     */
+    void setProperty( EntityRef entityRef, String propertyName, Object propertyValue, boolean override )
+            throws Exception;
+
+    /**
+     * Updates the properties for the specified entity.
+     *
+     * @param entity an entity reference
+     * @param properties the properties
+     *
+     * @throws Exception the exception
+     */
+    public void updateProperties( EntityRef entityRef, Map<String, Object> properties ) throws Exception;
+
+    public void deleteProperty( EntityRef entityRef, String propertyName ) throws Exception;
+
+    /**
+     * Gets the values from an entity list property. Lists are a special type of entity property that can contain an
+     * unordered set of non-duplicate values.
+     *
+     * @param entity an entity reference
+     * @param dictionaryName the property list name to retrieve.
+     *
+     * @return the value of the named property or null.
+     *
+     * @throws Exception the exception
+     */
+    public Set<Object> getDictionaryAsSet( EntityRef entityRef, String dictionaryName ) throws Exception;
+
+    /**
+     * Adds the specified value to the named entity list property. Lists are a special type of entity property that can
+     * contain an unordered set of non-duplicate values.
+     *
+     * @param entity an entity reference
+     * @param dictionaryName the property to set.
+     * @param elementValue new value for property.
+     *
+     * @throws Exception the exception
+     */
+    public void addToDictionary( EntityRef entityRef, String dictionaryName, Object elementValue ) throws Exception;
+
+    public void addToDictionary( EntityRef entityRef, String dictionaryName, Object elementName, Object elementValue )
+            throws Exception;
+
+    public void addSetToDictionary( EntityRef entityRef, String dictionaryName, Set<?> elementValues ) throws Exception;
+
+    public void addMapToDictionary( EntityRef entityRef, String dictionaryName, Map<?, ?> elementValues )
+            throws Exception;
+
+    public Map<Object, Object> getDictionaryAsMap( EntityRef entityRef, String dictionaryName ) throws Exception;
+
+    public Object getDictionaryElementValue( EntityRef entityRef, String dictionaryName, String elementName )
+            throws Exception;
+
+    /**
+     * Removes the specified value to the named entity list property. Lists are a special type of entity property that
+     * can contain an unordered set of non-duplicate values.
+     *
+     * @param entity an entity reference
+     * @param dictionaryName the property to set.
+     * @param elementValue new value for property.
+     *
+     * @throws Exception the exception
+     */
+    public void removeFromDictionary( EntityRef entityRef, String dictionaryName, Object elementValue )
+            throws Exception;
+
+    public Set<String> getDictionaries( EntityRef entity ) throws Exception;
+
+    /**
+     * Deletes the specified entity.
+     *
+     * @param entity an entity reference
+     *
+     * @throws Exception the exception
+     */
+    public void delete( EntityRef entityRef ) throws Exception;
+
+    /**
+     * Gets the entities and collections that the specified entity is a member of.
+     *
+     * @param entity an entity reference
+     *
+     * @return a map of entity references to set of collection names for the entities and collections that this entity
+     *         is a member of.
+     *
+     * @throws Exception the exception
+     */
+    public Map<String, Map<UUID, Set<String>>> getOwners( EntityRef entityRef ) throws Exception;
+
+    /**
+     * Return true if the owner entity ref is an owner of the entity;
+     *
+     * @param owner The owner of the collection
+     * @param collectionName The collection name
+     * @param entity The entity in the collection
+     */
+    public boolean isCollectionMember( EntityRef owner, String collectionName, EntityRef entity ) throws Exception;
+
+    /**
+     * Return true if the owner entity ref is an owner of the entity;
+     *
+     * @param owner The owner of the collection
+     * @param collectionName The collection name
+     * @param entity The entity in the collection
+     */
+    public boolean isConnectionMember( EntityRef owner, String connectionName, EntityRef entity ) throws Exception;
+
+
+    /**
+     * Gets the collections for the specified entity. Collection for a given type are encoded in the schema, this method
+     * loads the entity type and returns the collections from the schema.
+     *
+     * @param entity an entity reference
+     *
+     * @return the collections for the entity type of the given entity.
+     *
+     * @throws Exception the exception
+     */
+    public Set<String> getCollections( EntityRef entityRef ) throws Exception;
+
+    /**
+     * Gets a list of entities in the specified collection belonging to the specified entity.
+     *
+     * @param entity an entity reference
+     * @param collectionName the collection name.
+     * @param startResult the start result
+     * @param count the count
+     *
+     * @return a list of entities in the specified collection.
+     *
+     * @throws Exception the exception
+     */
+    public Results getCollection( EntityRef entityRef, String collectionName, UUID startResult, int count,
+                                  Results.Level resultsLevel, boolean reversed ) throws Exception;
+
+
+    public Results getCollection( UUID entityId, String collectionName, Query query, Results.Level resultsLevel )
+            throws Exception;
+
+    /**
+     * Adds an entity to the specified collection belonging to the specified entity entity.
+     *
+     * @param entity an entity reference
+     * @param collectionName the collection name.
+     * @param item an entity to be added to the collection.
+     *
+     * @throws Exception the exception
+     */
+    public Entity addToCollection( EntityRef entityRef, String collectionName, EntityRef itemRef ) throws Exception;
+
+    public Entity addToCollections( List<EntityRef> ownerEntities, String collectionName, EntityRef itemRef )
+            throws Exception;
+
+    /**
+     * Create the item in a sub collection
+     *
+     * @param entityRef The owning entity
+     * @param collectionName The name of the collection
+     * @param itemType The type of the item
+     * @param properties The properties for the item
+     */
+    public Entity createItemInCollection( EntityRef entityRef, String collectionName, String itemType,
+                                          Map<String, Object> properties ) throws Exception;
+
+    /**
+     * Removes an entity to the specified collection belonging to the specified entity.
+     *
+     * @param entity an entity reference
+     * @param collectionName the collection name.
+     * @param item a entity to be removed from the collection.
+     *
+     * @throws Exception the exception
+     */
+    public void removeFromCollection( EntityRef entityRef, String collectionName, EntityRef itemRef ) throws Exception;
+
+    public Results searchCollection( EntityRef entityRef, String collectionName, Query query ) throws Exception;
+
+    public Set<String> getCollectionIndexes( EntityRef entity, String collectionName ) throws Exception;
+
+    public void copyRelationships( EntityRef srcEntityRef, String srcRelationName, EntityRef dstEntityRef,
+                                   String dstRelationName ) throws Exception;
+
+    /**
+     * Connect the specified entity to another entity with the specified connection type. Connections are directional
+     * relationships that can be traversed in either direction.
+     *
+     * @param entity an entity reference
+     * @param connectionType type of connection to make.
+     * @param connectedEntity the entity to connect.
+     *
+     * @throws Exception the exception
+     */
+    public ConnectionRef createConnection( ConnectionRef connection ) throws Exception;
+
+    public ConnectionRef createConnection( EntityRef connectingEntity, String connectionType,
+                                           EntityRef connectedEntityRef ) throws Exception;
+
+    public ConnectionRef createConnection( EntityRef connectingEntity, String pairedConnectionType,
+                                           EntityRef pairedEntity, String connectionType, EntityRef connectedEntityRef )
+            throws Exception;
+
+    public ConnectionRef createConnection( EntityRef connectingEntity, ConnectedEntityRef... connections )
+            throws Exception;
+
+    public ConnectionRef connectionRef( EntityRef connectingEntity, String connectionType,
+                                        EntityRef connectedEntityRef ) throws Exception;
+
+    public ConnectionRef connectionRef( EntityRef connectingEntity, String pairedConnectionType, EntityRef pairedEntity,
+                                        String connectionType, EntityRef connectedEntityRef ) throws Exception;
+
+    public ConnectionRef connectionRef( EntityRef connectingEntity, ConnectedEntityRef... connections );
+
+    /**
+     * Disconnects two connected entities with the specified connection type. Connections are directional relationships
+     * that can be traversed in either direction.
+     *
+     * @param entity an entity reference
+     * @param connectionType type of connection to make.
+     * @param connectedEntity the entity to connect
+     *
+     * @throws Exception the exception
+     */
+
+    public void deleteConnection( ConnectionRef connectionRef ) throws Exception;
+
+    public Set<String> getConnectionTypes( EntityRef ref ) throws Exception;
+
+
+    /**
+     * Gets the entities of the specified type connected to the specified entity, optionally matching the specified
+     * connection types and/or entity types. Returns a list of entity ids.
+     *
+     * @param entity an entity reference
+     * @param connectionType type of connection or null.
+     * @param connectedEntityType type of entity or null.
+     *
+     * @return a list of connected entity ids.
+     *
+     * @throws Exception the exception
+     */
+    public Results getConnectedEntities( UUID entityId, String connectionType, String connectedEntityType,
+                                         Results.Level resultsLevel ) throws Exception;
+
+    /**
+     * Gets the entities connecting to this entity, optionally with the specified connection type and/or entity type.
+     * <p/>
+     * e.g. "get users who have favorited this place"
+     *
+     * @param entity an entity reference
+     * @param connectionType type of connection or null.
+     * @param connectingEntityType type of entity or null.
+     *
+     * @return a list of entities connecting to this one.
+     *
+     * @throws Exception the exception
+     */
+    public Results getConnectingEntities( UUID entityId, String connectionType, String connectedEntityType,
+                                          Results.Level resultsLevel ) throws Exception;
+
+
+    public Results getConnectingEntities(UUID uuid, String connectionType,
+    		String entityType, Level level, int count) throws Exception;
+
+	public Results searchConnectedEntities( EntityRef connectingEntity, Query query ) throws Exception;
+
+
+    // Application roles
+
+    public Set<String> getConnectionIndexes( EntityRef entity, String connectionType ) throws Exception;
+
+    public Map<String, String> getRoles() throws Exception;
+
+    public void resetRoles() throws Exception;
+
+    /**
+     * Create the role with the title and inactivity
+     *
+     * @param roleName The name of the role
+     * @param roleTitle The human readable title
+     * @param inactivity The amount of inactivity time to have the role expire. 0 is infinity, I.E no expiration
+     */
+    public Entity createRole( String roleName, String roleTitle, long inactivity ) throws Exception;
+
+    public void grantRolePermission( String roleName, String permission ) throws Exception;
+
+    public void grantRolePermissions( String roleName, Collection<String> permissions ) throws Exception;
+
+    public void revokeRolePermission( String roleName, String permission ) throws Exception;
+
+    public Set<String> getRolePermissions( String roleName ) throws Exception;
+
+    public void deleteRole( String roleName ) throws Exception;
+
+    // Group roles
+
+    public Map<String, String> getGroupRoles( UUID groupId ) throws Exception;
+
+    /** Create a group role with the group id, roleName, and inactivity */
+    public Entity createGroupRole( UUID groupId, String roleName, long inactivity ) throws Exception;
+
+    public void grantGroupRolePermission( UUID groupId, String roleName, String permission ) throws Exception;
+
+    public void revokeGroupRolePermission( UUID groupId, String roleName, String permission ) throws Exception;
+
+    public Set<String> getGroupRolePermissions( UUID groupId, String roleName ) throws Exception;
+
+    public void deleteGroupRole( UUID groupId, String roleName ) throws Exception;
+
+    // User role membership
+
+    public Set<String> getUserRoles( UUID userId ) throws Exception;
+
+    public void addUserToRole( UUID userId, String roleName ) throws Exception;
+
+    public void removeUserFromRole( UUID userId, String roleName ) throws Exception;
+
+    // User permissions
+
+    public Set<String> getUserPermissions( UUID userId ) throws Exception;
+
+    public void grantUserPermission( UUID userId, String permission ) throws Exception;
+
+    public void revokeUserPermission( UUID userId, String permission ) throws Exception;
+
+    // User role membership
+
+    public Map<String, String> getUserGroupRoles( UUID userId, UUID groupId ) throws Exception;
+
+    public void addUserToGroupRole( UUID userId, UUID groupId, String roleName ) throws Exception;
+
+    public void removeUserFromGroupRole( UUID userId, UUID groupId, String roleName ) throws Exception;
+
+    public Results getUsersInGroupRole( UUID groupId, String roleName, Results.Level level ) throws Exception;
+
+    public void incrementAggregateCounters( UUID userId, UUID groupId, String category, String counterName,
+                                            long value );
+
+    public Results getAggregateCounters( UUID userId, UUID groupId, String category, String counterName,
+                                         CounterResolution resolution, long start, long finish, boolean pad );
+
+    public Results getAggregateCounters( UUID userId, UUID groupId, UUID queueId, String category, String counterName,
+                                         CounterResolution resolution, long start, long finish, boolean pad );
+
+    public Results getAggregateCounters( Query query ) throws Exception;
+
+    public EntityRef getUserByIdentifier( Identifier identifier ) throws Exception;
+
+    public EntityRef getGroupByIdentifier( Identifier identifier ) throws Exception;
+
+    public Set<String> getCounterNames() throws Exception;
+
+    public Map<String, Long> getEntityCounters( UUID entityId ) throws Exception;
+
+    public Map<String, Long> getApplicationCounters() throws Exception;
+
+    public void incrementAggregateCounters( UUID userId, UUID groupId, String category, Map<String, Long> counters );
+
+    public boolean isPropertyValueUniqueForEntity( String entityType, String propertyName, Object propertyValue )
+            throws Exception;
+
+    public <A extends Entity> A get( EntityRef entityRef, Class<A> entityClass ) throws Exception;
+
+    public Map<String, Role> getRolesWithTitles( Set<String> roleNames ) throws Exception;
+
+    public String getRoleTitle( String roleName ) throws Exception;
+
+    public Map<String, Role> getUserRolesWithTitles( UUID userId ) throws Exception;
+
+
+    // Group role membership
+
+    public Map<String, Role> getGroupRolesWithTitles( UUID userId ) throws Exception;
+
+    public void addGroupToRole( UUID userId, String roleName ) throws Exception;
+
+    public void removeGroupFromRole( UUID userId, String roleName ) throws Exception;
+
+    // Group permissions
+
+    public Set<String> getGroupPermissions( UUID groupId ) throws Exception;
+
+    public void grantGroupPermission( UUID groupId, String permission ) throws Exception;
+
+    public void revokeGroupPermission( UUID groupId, String permission ) throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManagerFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManagerFactory.java
new file mode 100644
index 0000000..fad80d9
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityManagerFactory.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.usergrid.persistence;
+
+
+import java.util.Map;
+import java.util.UUID;
+
+
+// TODO: Auto-generated Javadoc
+
+
+/**
+ * The interface class that specifies the operations that can be performed on the Usergrid Datastore. This interface is
+ * designed to be implemented by different backends. Although these operations are meant to take advantage of the
+ * capabilities of Cassandra, they should be implementable using other relational databases such as MySql or NoSQL
+ * databases such as GAE or MongoDB.
+ */
+public interface EntityManagerFactory {
+
+    /**
+     * A string description provided by the implementing class.
+     *
+     * @return description text
+     *
+     * @throws Exception the exception
+     */
+    public abstract String getImpementationDescription() throws Exception;
+
+    /**
+     * Gets the entity manager.
+     *
+     * @param applicationId the application id
+     *
+     * @return EntityDao for the specfied parameters
+     */
+    public abstract EntityManager getEntityManager( UUID applicationId );
+
+    /**
+     * Creates a new application.
+     *
+     * @param name a unique application name.
+     *
+     * @return the newly created application id.
+     *
+     * @throws Exception the exception
+     */
+    public abstract UUID createApplication( String organizationName, String name ) throws Exception;
+
+    /**
+     * Creates a Application entity. All entities except for applications must be attached to a Application.
+     *
+     * @param name the name of the application to create.
+     * @param properties property values to create in the new entity or null.
+     *
+     * @return the newly created application id.
+     *
+     * @throws Exception the exception
+     */
+    public abstract UUID createApplication( String organizationName, String name, Map<String, Object> properties )
+            throws Exception;
+
+    public abstract UUID importApplication( String organization, UUID applicationId, String name,
+                                            Map<String, Object> properties ) throws Exception;
+
+    /**
+     * Returns the application id for the application name.
+     *
+     * @param name a unique application name.
+     *
+     * @return the Application id or null.
+     *
+     * @throws Exception the exception
+     */
+    public abstract UUID lookupApplication( String name ) throws Exception;
+
+    /**
+     * Returns all the applications in the system.
+     *
+     * @return all the applications.
+     *
+     * @throws Exception the exception
+     */
+    public abstract Map<String, UUID> getApplications() throws Exception;
+
+    public abstract void setup() throws Exception;
+
+    public abstract Map<String, String> getServiceProperties();
+
+    public abstract boolean updateServiceProperties( Map<String, String> properties );
+
+    public abstract boolean setServiceProperty( String name, String value );
+
+    public abstract boolean deleteServiceProperty( String name );
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/EntityPropertyComparator.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityPropertyComparator.java b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityPropertyComparator.java
new file mode 100644
index 0000000..f6609c7
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityPropertyComparator.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.usergrid.persistence;
+
+
+import java.util.Comparator;
+
+import static org.apache.usergrid.persistence.cassandra.IndexUpdate.compareIndexedValues;
+
+
+public class EntityPropertyComparator implements Comparator<Entity> {
+
+    final String propertyName;
+    final int reverse;
+
+
+    public EntityPropertyComparator( String propertyName, boolean reverse ) {
+        this.propertyName = propertyName;
+        this.reverse = reverse ? -1 : 1;
+    }
+
+
+    @Override
+    public int compare( Entity e1, Entity e2 ) {
+
+        if ( e1 == null ) {
+            //second one is not null and first is, second is larger
+            if ( e2 != null ) {
+                return 1;
+            }
+            else {
+                return 0;
+            }
+        }
+        //first one is not null, second is
+        else if ( e2 == null ) {
+            return -1;
+        }
+
+        return compareIndexedValues( e1.getProperty( propertyName ), e2.getProperty( propertyName ) ) * reverse;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/EntityRef.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityRef.java b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityRef.java
new file mode 100644
index 0000000..089f1a4
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityRef.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.usergrid.persistence;
+
+
+import java.util.UUID;
+
+
+public interface EntityRef {
+
+    /**
+     * Gets the id.
+     *
+     * @return the id
+     */
+    public UUID getUuid();
+
+    /**
+     * Gets the type.
+     *
+     * @return the type
+     */
+    public String getType();
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/EntityUtils.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/EntityUtils.java b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityUtils.java
new file mode 100644
index 0000000..8b1b5d3
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/EntityUtils.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.usergrid.persistence;
+
+
+import java.util.Map;
+import java.util.TreeMap;
+
+
+public class EntityUtils {
+
+    public static Map<String, Object> getSchemaProperties( String entityType, Map<String, Object> properties ) {
+
+        Map<String, Object> sys_props = new TreeMap<String, Object>( String.CASE_INSENSITIVE_ORDER );
+
+        for ( String propName : properties.keySet() ) {
+            if ( Schema.getDefaultSchema().hasProperty( entityType, propName ) ) {
+                Object propValue = properties.get( propName );
+                sys_props.put( propName, propValue );
+            }
+        }
+
+        return sys_props;
+    }
+
+
+    public static Map<String, Object> getDynamicProperties( String entityType, Map<String, Object> properties ) {
+
+        Map<String, Object> sys_props = new TreeMap<String, Object>( String.CASE_INSENSITIVE_ORDER );
+
+        for ( String propName : properties.keySet() ) {
+            if ( !Schema.getDefaultSchema().hasProperty( entityType, propName ) ) {
+                Object propValue = properties.get( propName );
+                sys_props.put( propName, propValue );
+            }
+        }
+
+        return sys_props;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/Identifier.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/Identifier.java b/stack/core/src/main/java/org/apache/usergrid/persistence/Identifier.java
new file mode 100644
index 0000000..00f24ee
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/Identifier.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.usergrid.persistence;
+
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.usergrid.utils.UUIDUtils;
+import org.codehaus.jackson.annotate.JsonIgnore;
+
+
+public class Identifier implements Serializable {
+
+    public enum Type {
+        UUID, NAME, EMAIL
+    }
+
+
+    Type type;
+    Object value;
+
+    static Pattern emailRegEx = Pattern.compile( "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}" );
+    static Pattern nameRegEx = Pattern.compile( "[a-zA-Z0-9_\\-./]*" );
+
+
+    private Identifier( Type type, Object value ) {
+        this.type = type;
+        this.value = value;
+    }
+
+
+    public static Identifier from( Object obj ) {
+        if ( obj == null ) {
+            return null;
+        }
+        if ( obj instanceof UUID ) {
+            return new Identifier( Type.UUID, obj );
+        }
+        if ( obj instanceof String ) {
+            UUID uuid = UUIDUtils.tryGetUUID( ( String ) obj );
+            if ( uuid != null ) {
+                return new Identifier( Type.UUID, uuid );
+            }
+            Matcher m = emailRegEx.matcher( ( String ) obj );
+            if ( m.matches() ) {
+                return new Identifier( Type.EMAIL, ( ( String ) obj ).toLowerCase() );
+            }
+            m = nameRegEx.matcher( ( String ) obj );
+            if ( m.matches() ) {
+                return new Identifier( Type.NAME, ( ( String ) obj ).toLowerCase() );
+            }
+        }
+        return null;
+    }
+
+
+    public static Identifier fromUUID( UUID uuid ) {
+        if ( uuid == null ) {
+            return null;
+        }
+        return new Identifier( Type.UUID, uuid );
+    }
+
+
+    public static Identifier fromName( String name ) {
+        if ( name == null ) {
+            return null;
+        }
+        return new Identifier( Type.NAME, name );
+    }
+
+
+    public static Identifier fromEmail( String email ) {
+        if ( email == null ) {
+            return null;
+        }
+        return new Identifier( Type.EMAIL, email );
+    }
+
+
+    @JsonIgnore
+    public UUID getUUID() {
+        if ( type != Type.UUID ) {
+            return null;
+        }
+        return ( UUID ) value;
+    }
+
+
+    @JsonIgnore
+    public boolean isUUID() {
+        return type == Type.UUID;
+    }
+
+
+    @JsonIgnore
+    public String getEmail() {
+        if ( type != Type.EMAIL ) {
+            return null;
+        }
+        return ( String ) value;
+    }
+
+
+    @JsonIgnore
+    public boolean isEmail() {
+        return type == Type.EMAIL;
+    }
+
+
+    @JsonIgnore
+    public String getName() {
+        if ( type != Type.NAME ) {
+            return null;
+        }
+        return ( String ) value;
+    }
+
+
+    @JsonIgnore
+    public boolean isName() {
+        return type == Type.NAME;
+    }
+
+
+    public Type getType() {
+        return type;
+    }
+
+
+    @Override
+    public String toString() {
+        return value != null ? value.toString() : null;
+    }
+
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ( ( type == null ) ? 0 : type.hashCode() );
+        result = prime * result + ( ( value == null ) ? 0 : value.hashCode() );
+        return result;
+    }
+
+
+    @Override
+    public boolean equals( Object obj ) {
+        if ( this == obj ) {
+            return true;
+        }
+        if ( obj == null ) {
+            return false;
+        }
+        if ( getClass() != obj.getClass() ) {
+            return false;
+        }
+        Identifier other = ( Identifier ) obj;
+        if ( type != other.type ) {
+            return false;
+        }
+        if ( value == null ) {
+            if ( other.value != null ) {
+                return false;
+            }
+        }
+        else if ( !value.equals( other.value ) ) {
+            return false;
+        }
+        return true;
+    }
+
+
+    public static List<Identifier> fromList( List<String> l ) {
+        List<Identifier> identifiers = null;
+        if ( ( l != null ) && ( l.size() > 0 ) ) {
+            for ( String s : l ) {
+                Identifier identifier = Identifier.from( s );
+                if ( identifier != null ) {
+                    if ( identifiers == null ) {
+                        identifiers = new ArrayList<Identifier>();
+                    }
+                    identifiers.add( identifier );
+                }
+            }
+        }
+        return identifiers;
+    }
+
+
+    // for serialization
+    public Identifier() { }
+
+
+    // for serialization
+    public Object getValue() {
+        return value;
+    }
+
+
+    // for serialization
+    public void setValue( Object value ) {
+        if ( isUUID() && value instanceof String ) {
+            value = UUID.fromString( ( String ) value );
+        }
+        this.value = value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/IndexBucketLocator.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/IndexBucketLocator.java b/stack/core/src/main/java/org/apache/usergrid/persistence/IndexBucketLocator.java
new file mode 100644
index 0000000..47a2aad
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/IndexBucketLocator.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright 2012 Apigee Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ******************************************************************************/
+package org.apache.usergrid.persistence;
+
+
+import java.util.List;
+import java.util.UUID;
+
+
+/**
+ * Interface for locating different buckets for indexing entities. These buckets are not intended for user with time
+ * series indexing. Rather this a means of partitioning index puts across multiple rows
+ *
+ * @author tnine
+ */
+public interface IndexBucketLocator {
+
+    public enum IndexType {
+        COLLECTION( "collection" ), CONNECTION( "connection" ), GEO( "geo" ), UNIQUE( "unique" );
+
+        private final String type;
+
+
+        private IndexType( String type ) {
+            this.type = type;
+        }
+
+
+        public String getType() {
+            return type;
+        }
+
+    }
+
+    /**
+     * Return the bucket to use for indexing this entity
+     *
+     * @param applicationId The application id
+     * @param type The type of the index. This way indexing on the same property value for different types of indexes
+     * does not cause collisions on partitioning and lookups
+     * @param entityId The entity id to be indexed
+     * @param components The strings and uniquely identify the path to this index. I.E entityType and propName,
+     * collection name etc This string must remain the same for all reads and writes
+     *
+     * @return A bucket to use.  Note that ALL properties for the given entity should be in the same bucket.  This
+     *         allows us to shard and execute queries in parallel.  Generally speaking, sharding on entityId is the best
+     *         strategy, since this is an immutable value
+     */
+    public String getBucket( UUID applicationId, IndexType type, UUID entityId, String... components );
+
+    /**
+     * Get all buckets that exist for this application with the given entity type, and property name
+     *
+     * @param applicationId The application id
+     * @param type The type of index
+     * @param components The strings and uniquely identify the path to this index. I.E entityType and propName,
+     * collection name etc
+     *
+     * @return All buckets for this application at the given component path
+     */
+    public List<String> getBuckets( UUID applicationId, IndexType type, String... components );
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/MultiQueryIterator.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/MultiQueryIterator.java b/stack/core/src/main/java/org/apache/usergrid/persistence/MultiQueryIterator.java
new file mode 100644
index 0000000..8d714f6
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/MultiQueryIterator.java
@@ -0,0 +1,106 @@
+package org.apache.usergrid.persistence;
+
+
+import java.util.Iterator;
+import java.util.UUID;
+
+
+/**
+ * For each in a set of source UUIDs, executes a sub-query and provides a unified iterator over the union of all
+ * results. Honors page sizes for the Query to ensure memory isn't blown out.
+ */
+public class MultiQueryIterator implements Iterator {
+
+    private EntityManager entityManager;
+    private Iterator<UUID> source;
+    private Query query;
+    private MutableEntityRef entityRef = new MutableEntityRef();
+    private Iterator currentIterator;
+
+
+    public MultiQueryIterator( Results results, Query query ) {
+        this( results.getQueryProcessor().getEntityManager(), new PagingResultsIterator( results, Results.Level.IDS ),
+                query );
+    }
+
+
+    public MultiQueryIterator( EntityManager entityManager, Iterator<UUID> source, Query query ) {
+        if ( query.getCollection() == null && query.getConnectionType() == null ) {
+            throw new IllegalArgumentException( "Query must have a collection or connectionType value" );
+        }
+        this.entityManager = entityManager;
+        this.source = source;
+        this.query = query;
+    }
+
+
+    @Override
+    public boolean hasNext() {
+        if ( source == null ) {
+            return false;
+        }
+        if ( currentIterator != null && currentIterator.hasNext() ) {
+            return true;
+        }
+        while ( source.hasNext() ) {
+            UUID uuid = source.next();
+            Results r = getResultsFor( uuid );
+            if ( r.size() > 0 ) {
+                currentIterator = new PagingResultsIterator( r, query.getResultsLevel() );
+                return currentIterator.hasNext();
+            }
+        }
+        currentIterator = null;
+        source = null;
+        return false;
+    }
+
+
+    @Override
+    public Object next() {
+        return ( currentIterator != null ) ? currentIterator.next() : null;
+    }
+
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+
+    private Results getResultsFor( UUID uuid ) {
+        entityRef.setUUID( uuid );
+        try {
+            return ( query.getCollection() != null ) ?
+                   entityManager.searchCollection( entityRef, query.getCollection(), query ) :
+                   entityManager.searchConnectedEntities( entityRef, query );
+        }
+        catch ( Exception e ) {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    // just avoid some garbage collection
+    private static class MutableEntityRef implements EntityRef {
+
+        private UUID uuid;
+
+
+        public void setUUID( UUID uuid ) {
+            this.uuid = uuid;
+        }
+
+
+        @Override
+        public UUID getUuid() {
+            return uuid;
+        }
+
+
+        @Override
+        public String getType() {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/PagingResultsIterator.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/PagingResultsIterator.java b/stack/core/src/main/java/org/apache/usergrid/persistence/PagingResultsIterator.java
new file mode 100644
index 0000000..acaa13f
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/PagingResultsIterator.java
@@ -0,0 +1,109 @@
+package org.apache.usergrid.persistence;
+
+
+import java.util.Iterator;
+import java.util.List;
+
+
+/** iterates over a Results object, crossing page boundaries automatically */
+public class PagingResultsIterator implements Iterator, Iterable {
+
+    private Results results;
+    private Iterator currentPageIterator;
+    private Results.Level level;
+
+
+    public PagingResultsIterator( Results results ) {
+        this( results, results.level );
+    }
+
+
+    /**
+     * @param level overrides the default level from the Results - in case you want to return, say, UUIDs where the
+     * Query was set for Entities
+     */
+    public PagingResultsIterator( Results results, Results.Level level ) {
+        this.results = results;
+        this.level = level;
+        initCurrentPageIterator();
+    }
+
+
+    @Override
+    public boolean hasNext() {
+        if ( currentPageIterator != null ) {
+            if ( currentPageIterator.hasNext() ) {
+                return true;
+            }
+            else {
+                return loadNextPage();
+            }
+        }
+        return false;
+    }
+
+
+    /** @return the next object (type varies according the Results.Level) */
+    @Override
+    public Object next() {
+        return currentPageIterator.next();
+    }
+
+
+    /** not supported */
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+
+    /**
+     * initialize the iterator for the current page of results.
+     *
+     * @return true if the iterator has more results
+     */
+    private boolean initCurrentPageIterator() {
+        List currentPage;
+        if ( results != null ) {
+            switch ( level ) {
+                case IDS:
+                    currentPage = results.getIds();
+                    break;
+                case REFS:
+                    currentPage = results.getRefs();
+                    break;
+                default:
+                    currentPage = results.getEntities();
+            }
+            if ( currentPage.size() > 0 ) {
+                currentPageIterator = currentPage.iterator();
+            }
+        }
+        else {
+            currentPageIterator = null;
+        }
+        return currentPageIterator != null && currentPageIterator.hasNext();
+    }
+
+
+    /**
+     * attempts to load the next page
+     *
+     * @return true if loaded there are more results
+     */
+    private boolean loadNextPage() {
+        try {
+            results = results.getNextPageResults();
+        }
+        catch ( Exception e ) {
+            throw new RuntimeException( e );
+        }
+        return initCurrentPageIterator();
+    }
+
+
+    @Override
+    public Iterator iterator() {
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c2acbe4/stack/core/src/main/java/org/apache/usergrid/persistence/PathQuery.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/persistence/PathQuery.java b/stack/core/src/main/java/org/apache/usergrid/persistence/PathQuery.java
new file mode 100644
index 0000000..a91aac4
--- /dev/null
+++ b/stack/core/src/main/java/org/apache/usergrid/persistence/PathQuery.java
@@ -0,0 +1,115 @@
+package org.apache.usergrid.persistence;
+
+
+import java.util.Iterator;
+import java.util.UUID;
+
+
+public class PathQuery<E> {
+
+    private PathQuery source;
+    private Query query;
+    private UUID head;
+
+
+    public PathQuery() {
+    }
+
+
+    /**
+     * top level
+     *
+     * @param head the top-level entity
+     */
+    public PathQuery( EntityRef head ) {
+        this.head = head.getUuid();
+        this.query = null;
+    }
+
+
+    /**
+     * top level
+     *
+     * @param head the top-level entity
+     * @param collectionName the query - must have a collection or connectType value set
+     */
+    public PathQuery( EntityRef head, Query query ) {
+        if ( query.getCollection() == null && query.getConnectionType() == null ) {
+            throw new IllegalArgumentException( "Query must have a collection or connectionType value" );
+        }
+        this.head = head.getUuid();
+        this.query = query;
+    }
+
+
+    /**
+     * chained
+     *
+     * @param source the source query we're chaining from
+     * @param collectionName the query - must have a collection or connectType value set
+     */
+    public PathQuery( PathQuery source, Query query ) {
+        if ( query.getCollection() == null && query.getConnectionType() == null ) {
+            throw new IllegalArgumentException( "Query must have a collection or connectionType value" );
+        }
+        this.source = source;
+        this.query = query;
+    }
+
+
+    public PathQuery chain( Query query ) {
+        return new PathQuery( this, query );
+    }
+
+
+    public Iterator<E> iterator( EntityManager em ) {
+        try {
+            if ( head != null ) {
+                return new PagingResultsIterator( getHeadResults( em ), query.getResultsLevel() );
+            }
+            else {
+                return new MultiQueryIterator( em, source.uuidIterator( em ), query );
+            }
+        }
+        catch ( Exception e ) {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    protected Results getHeadResults( EntityManager em ) throws Exception {
+        EntityRef ref = new SimpleEntityRef( head );
+        return ( query.getCollection() != null ) ? em.searchCollection( ref, query.getCollection(), query ) :
+               em.searchConnectedEntities( ref, query );
+    }
+
+
+    protected Iterator uuidIterator( EntityManager em ) throws Exception {
+        if ( head != null ) {
+            return new PagingResultsIterator( getHeadResults( em ), Results.Level.IDS );
+        }
+        else {
+            Query q = query;
+            if ( query.getResultsLevel() != Results.Level.IDS ) { // ensure IDs level
+                q = new Query( q );
+                q.setResultsLevel( Results.Level.IDS );
+            }
+            return new MultiQueryIterator( em, source.uuidIterator( em ), q );
+        }
+    }
+
+
+    public PathQuery getSource() {
+        return source;
+    }
+
+
+    public UUID getHead() {
+        return head;
+    }
+
+
+    public Query getQuery() {
+        return query;
+    }
+}