You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by mr...@apache.org on 2016/06/15 16:24:54 UTC

[01/50] [abbrv] usergrid git commit: Merge branch 'usergrid-1283-service-mgr-init' into usegrid-1283-mgmt-app-init

Repository: usergrid
Updated Branches:
  refs/heads/master 9250a81e7 -> f2126086e


Merge branch 'usergrid-1283-service-mgr-init' into usegrid-1283-mgmt-app-init

Conflicts:
	stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java


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

Branch: refs/heads/master
Commit: de6de6629903f57df4faf5c3f20f5cea63f2bcec
Parents: e0c0c87 5f46341
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 18 09:23:54 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 18 09:23:54 2016 -0400

----------------------------------------------------------------------
 .../corepersistence/CpEntityManagerFactory.java | 66 +++++++++++++++++---
 1 file changed, 59 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/de6de662/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
----------------------------------------------------------------------
diff --cc stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
index b61be01,4028875..e057210
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
@@@ -98,14 -102,15 +98,12 @@@ public class CpEntityManagerFactory imp
  
      private Setup setup = null;
  
+     EntityManager managementAppEntityManager = null;
+ 
      // cache of already instantiated entity managers
-     private LoadingCache<UUID, EntityManager> entityManagers
-         = CacheBuilder.newBuilder().maximumSize(100).build(new CacheLoader<UUID, EntityManager>() {
-             public EntityManager load(UUID appId) { // no checked exception
-                 return _getEntityManager(appId);
-             }
-         });
+     private final String ENTITY_MANAGER_CACHE_SIZE = "entity.manager.cache.size";
+     private final LoadingCache<UUID, EntityManager> entityManagers;
  
 -
 -
 -
      private final ApplicationIdCache applicationIdCache;
      //private final IndexSchemaCache indexSchemaCache;
  
@@@ -148,7 -148,62 +146,61 @@@
          this.applicationIdCache = injector.getInstance(ApplicationIdCacheFactory.class).getInstance(
              getManagementEntityManager() );
  
-         initMgmtAppInternal();
 -
+         int entityManagerCacheSize = 100;
+         try {
+             entityManagerCacheSize = Integer.parseInt(
+                 cassandraService.getProperties().getProperty( ENTITY_MANAGER_CACHE_SIZE, "100" ));
+         } catch ( Exception e ) {
+             logger.error("Error parsing " + ENTITY_MANAGER_CACHE_SIZE + " using " + entityManagerCacheSize, e );
+         }
+ 
+         entityManagers = CacheBuilder.newBuilder()
+             .maximumSize(entityManagerCacheSize)
+             .build(new CacheLoader<UUID, EntityManager>() {
+ 
+             public EntityManager load( UUID appId ) { // no checked exception
+ 
+                 // get entity manager and ensure it can get its own application
+ 
+                 EntityManager entityManager = _getEntityManager( appId );
+                 Application app = null;
+                 Exception exception = null;
+                 try {
+                     app = entityManager.getApplication();
+                 } catch (Exception e) {
+                     exception = e;
+                 }
+ 
+                 // the management app is a special case
+ 
+                 if ( CpNamingUtils.MANAGEMENT_APPLICATION_ID.equals( appId ) ) {
+ 
+                     if ( app != null ) {
+ 
+                         // we successfully fetched up the management app, cache it for a rainy day
+                         managementAppEntityManager = entityManager;
+ 
+                     } else if ( managementAppEntityManager != null ) {
+ 
+                         // failed to fetch management app, use cached one
+                         entityManager = managementAppEntityManager;
+ 
+                     } else {
+ 
+                         // fetch failed and we have nothing cached, we must be bootstrapping
+                         logger.info("managementAppEntityManager is null, bootstrapping in progress");
+                     }
+ 
+                 } else { // not the management app, so blow up if app cannot be fetched
+ 
+                     if (app == null) {
+                         throw new RuntimeException( "Error getting application " + appId, exception );
+                     }
+                 }
+ 
+                 return entityManager;
+             }
+         });
      }
  
  


[17/50] [abbrv] usergrid git commit: Revert all changes to CpEntityManager

Posted by mr...@apache.org.
Revert all changes to CpEntityManager


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

Branch: refs/heads/master
Commit: e299024ff75caaff3111c9e762671fb91166d50c
Parents: 7d2de99
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 25 10:26:27 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 25 10:26:27 2016 -0400

----------------------------------------------------------------------
 .../corepersistence/CpEntityManager.java        | 27 +++++++++++++++-----
 1 file changed, 20 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/e299024f/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
index acdfa0f..13b5d1f 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
@@ -36,7 +36,6 @@ import java.util.TreeSet;
 import java.util.UUID;
 import java.util.stream.Collectors;
 
-import org.apache.usergrid.persistence.*;
 import org.apache.usergrid.persistence.collection.EntitySet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,7 +48,24 @@ import org.apache.usergrid.corepersistence.service.CollectionService;
 import org.apache.usergrid.corepersistence.service.ConnectionService;
 import org.apache.usergrid.corepersistence.util.CpEntityMapUtils;
 import org.apache.usergrid.corepersistence.util.CpNamingUtils;
+import org.apache.usergrid.persistence.AggregateCounter;
+import org.apache.usergrid.persistence.AggregateCounterSet;
+import org.apache.usergrid.persistence.CollectionRef;
+import org.apache.usergrid.persistence.ConnectedEntityRef;
+import org.apache.usergrid.persistence.ConnectionRef;
+import org.apache.usergrid.persistence.Entity;
+import org.apache.usergrid.persistence.EntityFactory;
+import org.apache.usergrid.persistence.EntityManager;
+import org.apache.usergrid.persistence.EntityRef;
+import org.apache.usergrid.persistence.IndexBucketLocator;
+import org.apache.usergrid.persistence.Query;
 import org.apache.usergrid.persistence.Query.Level;
+import org.apache.usergrid.persistence.RelationManager;
+import org.apache.usergrid.persistence.Results;
+import org.apache.usergrid.persistence.Schema;
+import org.apache.usergrid.persistence.SimpleEntityRef;
+import org.apache.usergrid.persistence.SimpleRoleRef;
+import org.apache.usergrid.persistence.TypedEntity;
 import org.apache.usergrid.persistence.cassandra.ApplicationCF;
 import org.apache.usergrid.persistence.cassandra.CassandraPersistenceUtils;
 import org.apache.usergrid.persistence.cassandra.CassandraService;
@@ -214,9 +230,6 @@ public class CpEntityManager implements EntityManager {
 
     private EntityCollectionManager ecm;
 
-    private CpEntityManagerFactory emf;
-
-
     //    /** Short-term cache to keep us from reloading same Entity during single request. */
 //    private LoadingCache<EntityScope, org.apache.usergrid.persistence.model.entity.Entity> entityCache;
 
@@ -229,8 +242,7 @@ public class CpEntityManager implements EntityManager {
      * @param metricsFactory
      * @param applicationId
      */
-    public CpEntityManager(final CpEntityManagerFactory emf,
-                           final CassandraService cass,
+    public CpEntityManager( final CassandraService cass,
                            final CounterUtils counterUtils,
                            final AsyncEventService indexService,
                            final ManagerCache managerCache,
@@ -242,7 +254,6 @@ public class CpEntityManager implements EntityManager {
                            final IndexSchemaCacheFactory indexSchemaCacheFactory,
                            final UUID applicationId ) {
 
-        this.emf = emf;
         this.entityManagerFig = entityManagerFig;
 
         Preconditions.checkNotNull( cass, "cass must not be null" );
@@ -259,6 +270,8 @@ public class CpEntityManager implements EntityManager {
         this.connectionService = connectionService;
         this.collectionService = collectionService;
 
+
+
         this.managerCache = managerCache;
         this.applicationId = applicationId;
         this.indexService = indexService;


[27/50] [abbrv] usergrid git commit: Remove unneeded properties, log when mgmt app lookup fails, minor refactoring

Posted by mr...@apache.org.
Remove unneeded properties, log when mgmt app lookup fails, minor refactoring


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

Branch: refs/heads/master
Commit: 4b8e5460cb93fb65ee54282e93887668bf7d6f8a
Parents: 59c538a
Author: Dave Johnson <sn...@apache.org>
Authored: Fri Jun 3 07:31:46 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri Jun 3 07:31:46 2016 -0400

----------------------------------------------------------------------
 .../src/main/resources/usergrid-default.properties    |  7 -------
 .../corepersistence/CpEntityManagerFactory.java       | 14 +++++++-------
 .../exception/CollectionRuntimeException.java         |  2 +-
 3 files changed, 8 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/4b8e5460/stack/config/src/main/resources/usergrid-default.properties
----------------------------------------------------------------------
diff --git a/stack/config/src/main/resources/usergrid-default.properties b/stack/config/src/main/resources/usergrid-default.properties
index 1e22d6a..0fc31ef 100644
--- a/stack/config/src/main/resources/usergrid-default.properties
+++ b/stack/config/src/main/resources/usergrid-default.properties
@@ -195,13 +195,6 @@ cassandra.lock.writecl=LOCAL_QUORUM
 #
 #cassandra.useSocketKeepalive=false
 
-# Number of times to retry creation of lock keyspace and column family
-cassandra.lock.init.retries = 100;
-
-# Interval between lock keyspace creation attempts (in milliseconds)
-cassandra.lock.init.interval = 1000;
-
-
 ##################### Async Threadpool Settings #####################
 
 # Set the number of threads available in the Rx Async Thread Pool

http://git-wip-us.apache.org/repos/asf/usergrid/blob/4b8e5460/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
index 622944b..18df205 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
@@ -69,7 +69,6 @@ import java.util.*;
 import static java.lang.String.CASE_INSENSITIVE_ORDER;
 import static org.apache.usergrid.persistence.Schema.PROPERTY_NAME;
 import static org.apache.usergrid.persistence.Schema.TYPE_APPLICATION;
-import static org.apache.usergrid.persistence.Schema.initLock;
 
 
 /**
@@ -178,26 +177,27 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
                         } else if ( managementAppEntityManager != null ) {
                             // failed to fetch management app, use cached one
                             entityManager = managementAppEntityManager;
+                            logger.error("Failed to fetch management app");
                         }
                     }
 
                     // missing keyspace means we have not done bootstrap yet
-                    final boolean missingKeyspace;
+                    final boolean isBootstrapping;
                     if ( throwable instanceof CollectionRuntimeException ) {
                         CollectionRuntimeException cre = (CollectionRuntimeException) throwable;
-                        missingKeyspace = cre.isMissingKeyspace();
+                        isBootstrapping = cre.isBootstrapping();
                     } else {
-                        missingKeyspace = false;
+                        isBootstrapping = false;
                     }
 
                     // work around for https://issues.apache.org/jira/browse/USERGRID-1291
-                    // throw exception so that we do not cache 
+                    // throw exception so that we do not cache
                     // TODO: determine how application name can intermittently be null
                     if ( app != null && app.getName() == null ) {
                         throw new RuntimeException( "Name is null for application " + appId, throwable );
                     }
 
-                    if ( app == null && !missingKeyspace ) {
+                    if ( app == null && !isBootstrapping ) {
                         throw new RuntimeException( "Error getting application " + appId, throwable );
 
                     } // else keyspace is missing because setup/bootstrap not done yet
@@ -241,7 +241,7 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
 
                 if ( t instanceof CollectionRuntimeException ) {
                     CollectionRuntimeException cre = (CollectionRuntimeException)t;
-                    if ( cre.isMissingKeyspace() ) {
+                    if ( cre.isBootstrapping() ) {
                         // we're bootstrapping, ignore this and continue
                         bootstrapping = true;
                         break;

http://git-wip-us.apache.org/repos/asf/usergrid/blob/4b8e5460/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java
index f27e2d7..8aa2a7a 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java
@@ -57,7 +57,7 @@ public class CollectionRuntimeException extends RuntimeException {
         this.applicationScope = scope;
     }
 
-    public boolean isMissingKeyspace() {
+    public boolean isBootstrapping() {
         if ( getCause() instanceof BadRequestException ) {
             BadRequestException bre = (BadRequestException)getCause();
             String msg = bre.getMessage();


[35/50] [abbrv] usergrid git commit: better logging

Posted by mr...@apache.org.
better logging


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

Branch: refs/heads/master
Commit: b3e60c93bca7b463121991dca2d48e553c337aba
Parents: 66bb5cd
Author: Dave Johnson <sn...@apache.org>
Authored: Mon Jun 6 12:20:15 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Mon Jun 6 12:20:15 2016 -0400

----------------------------------------------------------------------
 .../org/apache/usergrid/locking/cassandra/AstyanaxLockImpl.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/b3e60c93/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockImpl.java
index 1399d16..d06d579 100644
--- a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockImpl.java
@@ -67,7 +67,7 @@ public class AstyanaxLockImpl implements Lock {
             count.incrementAndGet();
 
         } catch (Exception e) {
-            throw new UGLockException("Unable to acquire lock with id: " + lock.getLockId());
+            throw new UGLockException("Unable to acquire lock with id: " + lock.getLockId(), e);
         }
     }
 


[21/50] [abbrv] usergrid git commit: Make retries and interval configurable

Posted by mr...@apache.org.
Make retries and interval configurable


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

Branch: refs/heads/master
Commit: fcd00e83b4febea1f395e7d8818bab8c38fa8bea
Parents: 910811d
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 25 18:30:27 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 25 18:30:27 2016 -0400

----------------------------------------------------------------------
 .../main/resources/usergrid-default.properties  |  8 ++
 .../corepersistence/CpEntityManagerFactory.java | 94 ++++++++++++--------
 .../cassandra/AstyanaxLockManagerImpl.java      |  5 +-
 .../persistence/core/astyanax/CassandraFig.java | 18 +++-
 4 files changed, 86 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/fcd00e83/stack/config/src/main/resources/usergrid-default.properties
----------------------------------------------------------------------
diff --git a/stack/config/src/main/resources/usergrid-default.properties b/stack/config/src/main/resources/usergrid-default.properties
index 4f57cdd..1e22d6a 100644
--- a/stack/config/src/main/resources/usergrid-default.properties
+++ b/stack/config/src/main/resources/usergrid-default.properties
@@ -195,6 +195,12 @@ cassandra.lock.writecl=LOCAL_QUORUM
 #
 #cassandra.useSocketKeepalive=false
 
+# Number of times to retry creation of lock keyspace and column family
+cassandra.lock.init.retries = 100;
+
+# Interval between lock keyspace creation attempts (in milliseconds)
+cassandra.lock.init.interval = 1000;
+
 
 ##################### Async Threadpool Settings #####################
 
@@ -628,6 +634,8 @@ usergrid.auth.cache.inmemory.size=3000
 # all (= in + out)'
 usergrid.rest.default-connection-param=all
 
+# Number of times to retry attempt to access management app on startup
+management.app.max.retries=100
 
 
 ##############################  Usergrid Testing  #############################

http://git-wip-us.apache.org/repos/asf/usergrid/blob/fcd00e83/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
index 84872aa..b6fbc2a 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
@@ -23,6 +23,8 @@ import com.google.common.cache.LoadingCache;
 import com.google.inject.Injector;
 import com.google.inject.Key;
 import com.google.inject.TypeLiteral;
+import com.netflix.astyanax.connectionpool.exceptions.BadRequestException;
+import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.commons.lang.StringUtils;
 import org.apache.usergrid.corepersistence.asyncevents.AsyncEventService;
 import org.apache.usergrid.corepersistence.index.IndexSchemaCacheFactory;
@@ -124,54 +126,79 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
         this.connectionService = injector.getInstance( ConnectionService.class );
         this.indexSchemaCacheFactory = injector.getInstance( IndexSchemaCacheFactory.class );
 
+        Properties properties = cassandraService.getProperties();
+
+        entityManagers = createEntityManagerCache( properties );
+
+        checkManagementApp( properties );
+
+        // this line always needs to be last due to the temporary circular dependency until spring is removed
+        applicationIdCache = injector.getInstance(ApplicationIdCacheFactory.class)
+            .getInstance( getManagementEntityManager() );
+    }
+
+
+    private LoadingCache<UUID, EntityManager> createEntityManagerCache(Properties properties) {
+
         int entityManagerCacheSize = 100;
         try {
-            entityManagerCacheSize = Integer.parseInt(
-                cassandraService.getProperties().getProperty( ENTITY_MANAGER_CACHE_SIZE, "100" ));
+            entityManagerCacheSize = Integer.parseInt( properties.getProperty( ENTITY_MANAGER_CACHE_SIZE, "100" ));
         } catch ( Exception e ) {
-            logger.error("Error parsing " + ENTITY_MANAGER_CACHE_SIZE + " using " + entityManagerCacheSize, e );
+            logger.error("Error parsing " + ENTITY_MANAGER_CACHE_SIZE + ". Will use " + entityManagerCacheSize, e );
         }
 
-        entityManagers = CacheBuilder.newBuilder()
+        return CacheBuilder.newBuilder()
             .maximumSize(entityManagerCacheSize)
             .build(new CacheLoader<UUID, EntityManager>() {
 
-            public EntityManager load( UUID appId ) { // no checked exception
+                public EntityManager load( UUID appId ) { // no checked exception
 
-                // create new entity manager and pre-fetch its application
-                EntityManager entityManager = _getEntityManager( appId );
-                Application app = null;
-                Exception exception = null;
-                try {
-                    app = entityManager.getApplication();
-                } catch (Exception e) {
-                    exception = e;
-                }
+                    // create new entity manager and pre-fetch its application
+                    EntityManager entityManager = _getEntityManager( appId );
+                    Application app = null;
+                    Throwable throwable = null;
+                    try {
+                        app = entityManager.getApplication();
+                    } catch (Throwable t) {
+                        throwable = t;
+                    }
 
-                // the management app is a special case
+                    // the management app is a special case
 
-                if ( CpNamingUtils.MANAGEMENT_APPLICATION_ID.equals( appId ) ) {
+                    if ( CpNamingUtils.MANAGEMENT_APPLICATION_ID.equals( appId ) ) {
 
-                    if ( app != null ) {
-                        // we successfully fetched up the management app, cache it for a rainy day
-                        managementAppEntityManager = entityManager;
+                        if ( app != null ) {
+                            // we successfully fetched up the management app, cache it for a rainy day
+                            managementAppEntityManager = entityManager;
 
-                    } else if ( managementAppEntityManager != null ) {
-                        // failed to fetch management app, use cached one
-                        entityManager = managementAppEntityManager;
+                        } else if ( managementAppEntityManager != null ) {
+                            // failed to fetch management app, use cached one
+                            entityManager = managementAppEntityManager;
+                        }
+                    }
+
+                    if ( app == null && throwable != null && throwable.getCause() instanceof BadRequestException) {
+                        // probably means schema has not been created yet
+                    } else {
+                        throw new RuntimeException( "Error getting application " + appId, throwable );
                     }
-                }
 
-                if (app == null) {
-                    throw new RuntimeException( "Error getting application " + appId, exception );
+                    return entityManager;
                 }
+            });
+    }
 
-                return entityManager;
-            }
-        });
+
+    private void checkManagementApp(Properties properties) {
+        int maxRetries = 100;
+        try {
+            maxRetries = Integer.parseInt( properties.getProperty( MANAGEMENT_APP_MAX_RETRIES, "100" ));
+
+        } catch ( Exception e ) {
+            logger.error("Error parsing " + MANAGEMENT_APP_MAX_RETRIES + ". Will use " + maxRetries, e );
+        }
 
         // hold up construction until we can access the management app
-        int maxRetries = 1000;
         int retries = 0;
         boolean managementAppFound = false;
         while ( !managementAppFound && retries++ < maxRetries ) {
@@ -186,6 +213,7 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
                 } else {
                     logger.error(msg);
                 }
+                try { Thread.sleep( 1000 ); } catch (InterruptedException ignored) {}
             }
         }
 
@@ -193,10 +221,6 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
             // exception here will prevent WAR from being deployed
             throw new RuntimeException( "Unable to get management app after " + retries + " retries" );
         }
-
-        // this line always needs to be last due to the temporary circular dependency until spring is removed
-        applicationIdCache = injector.getInstance(ApplicationIdCacheFactory.class)
-            .getInstance( getManagementEntityManager() );
     }
 
 
@@ -240,8 +264,8 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
         try {
             return entityManagers.get( applicationId );
         }
-        catch ( Exception ex ) {
-            logger.error("Error getting oldAppInfo manager", ex);
+        catch ( Throwable t ) {
+            logger.error("Error getting entity manager", t);
         }
         return _getEntityManager(applicationId);
     }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/fcd00e83/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
index 49ff52e..9bf6694 100644
--- a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
@@ -52,6 +52,7 @@ public class AstyanaxLockManagerImpl implements LockManager {
     private ColumnFamily columnFamily;
     private static final int MINIMUM_LOCK_EXPIRATION = 60000; // 1 minute
 
+
     @Inject
     public AstyanaxLockManagerImpl(CassandraFig cassandraFig,
                                    CassandraCluster cassandraCluster ) throws ConnectionException {
@@ -59,7 +60,7 @@ public class AstyanaxLockManagerImpl implements LockManager {
         this.cassandraFig = cassandraFig;
 
         // hold up construction until we can create the column family
-        int maxRetries = 1000;
+        int maxRetries = cassandraFig.getLockManagerInitRetries();
         int retries = 0;
         boolean famReady = false;
         while ( !famReady && retries++ < maxRetries ) {
@@ -76,7 +77,7 @@ public class AstyanaxLockManagerImpl implements LockManager {
                 } else {
                     logger.error( msg );
                 }
-                try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
+                try { Thread.sleep( cassandraFig.getLockManagerInitInterval() ); } catch (InterruptedException ignored) {}
             }
         }
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/fcd00e83/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraFig.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraFig.java b/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraFig.java
index b00eca8..d315561 100644
--- a/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraFig.java
+++ b/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraFig.java
@@ -50,8 +50,8 @@ public interface CassandraFig extends GuicyFig {
     String LOCKS_CONNECTIONS = "cassandra.lock.connections";
     String LOCKS_EXPIRATION = "cassandra.lock.expiration.milliseconds";
 
-
-
+    String LOCK_MANAGER_INIT_RETRIES = "cassandra.lock.init.retries";
+    String LOCK_MANAGER_INIT_INTERVAL = "cassandra.lock.init.interval";
 
     // re-usable default values
     String DEFAULT_CONNECTION_POOLSIZE = "15";
@@ -180,4 +180,18 @@ public interface CassandraFig extends GuicyFig {
     @Default(DEFAULT_LOCKS_EXPIRATION)
     int getLocksExpiration();
 
+    /**
+     * How many times to attempt lock keyspace and column family creation
+     */
+    @Key( LOCK_MANAGER_INIT_RETRIES )
+    @Default( "100" )
+    int getLockManagerInitRetries();
+
+    /**
+     * Return the expiration that should be used for expiring a lock if it's not released
+     */
+    @Key( LOCK_MANAGER_INIT_INTERVAL )
+    @Default( "1000" )
+    int getLockManagerInitInterval();
+
 }


[07/50] [abbrv] usergrid git commit: Now that ShiroCache is working well, this test is not thread-safe.

Posted by mr...@apache.org.
Now that ShiroCache is working well, this test is not thread-safe.


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

Branch: refs/heads/master
Commit: ebcc772f99d8a85bd20ebd53ebbf49f900a79ce8
Parents: 7fdca3d
Author: Dave Johnson <sn...@apache.org>
Authored: Fri May 20 12:01:28 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri May 20 12:01:28 2016 -0400

----------------------------------------------------------------------
 .../usergrid/rest/applications/ApplicationResourceIT.java       | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/ebcc772f/stack/rest/src/test/java/org/apache/usergrid/rest/applications/ApplicationResourceIT.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/ApplicationResourceIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/ApplicationResourceIT.java
index 2dd5090..06615df 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/ApplicationResourceIT.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/ApplicationResourceIT.java
@@ -16,19 +16,17 @@
  */
 package org.apache.usergrid.rest.applications;
 
-import com.fasterxml.jackson.databind.JsonNode;
 import junit.framework.Assert;
+import net.jcip.annotations.NotThreadSafe;
 import org.apache.commons.lang.RandomStringUtils;
 import org.apache.shiro.codec.Base64;
 import org.apache.usergrid.cassandra.SpringResource;
 import org.apache.usergrid.management.ManagementService;
 import org.apache.usergrid.rest.test.resource.AbstractRestIT;
-import org.apache.usergrid.rest.test.resource.endpoints.mgmt.OrganizationResource;
 import org.apache.usergrid.rest.test.resource.model.*;
 import org.apache.usergrid.setup.ConcurrentProcessSingleton;
 import org.apache.usergrid.utils.MapUtils;
 import org.glassfish.jersey.client.ClientProperties;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,6 +50,7 @@ import static org.junit.Assert.*;
 /**
  * Invokes methods on ApplicationResource
  */
+@NotThreadSafe
 public class ApplicationResourceIT extends AbstractRestIT {
     private static final Logger logger = LoggerFactory.getLogger(ApplicationResourceIT.class);
 


[19/50] [abbrv] usergrid git commit: Revert all changes to CpEntityManagerFactory

Posted by mr...@apache.org.
Revert all changes to CpEntityManagerFactory


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

Branch: refs/heads/master
Commit: ba10e7f94a4b55bb0c89fc209d14a7a5687760fe
Parents: b0fba68
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 25 10:29:57 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 25 10:29:57 2016 -0400

----------------------------------------------------------------------
 .../corepersistence/CpEntityManagerFactory.java | 84 ++++++--------------
 1 file changed, 25 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/ba10e7f9/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
index f92fc9e..d2417be 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
@@ -16,16 +16,14 @@
 package org.apache.usergrid.corepersistence;
 
 
-import java.util.*;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-
+import com.google.common.base.Optional;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
 import org.apache.commons.lang.StringUtils;
-
 import org.apache.usergrid.corepersistence.asyncevents.AsyncEventService;
 import org.apache.usergrid.corepersistence.index.IndexSchemaCacheFactory;
 import org.apache.usergrid.corepersistence.index.ReIndexRequestBuilder;
@@ -34,15 +32,7 @@ import org.apache.usergrid.corepersistence.service.CollectionService;
 import org.apache.usergrid.corepersistence.service.ConnectionService;
 import org.apache.usergrid.corepersistence.util.CpNamingUtils;
 import org.apache.usergrid.exception.ConflictException;
-import org.apache.usergrid.persistence.AbstractEntity;
-import org.apache.usergrid.persistence.Entity;
-import org.apache.usergrid.persistence.EntityFactory;
-import org.apache.usergrid.persistence.EntityManager;
-import org.apache.usergrid.persistence.EntityManagerFactory;
-import org.apache.usergrid.persistence.EntityRef;
-import org.apache.usergrid.persistence.Query;
-import org.apache.usergrid.persistence.Results;
-import org.apache.usergrid.persistence.SimpleEntityRef;
+import org.apache.usergrid.persistence.*;
 import org.apache.usergrid.persistence.cassandra.CassandraService;
 import org.apache.usergrid.persistence.cassandra.CounterUtils;
 import org.apache.usergrid.persistence.cassandra.Setup;
@@ -57,30 +47,23 @@ import org.apache.usergrid.persistence.entities.Application;
 import org.apache.usergrid.persistence.exceptions.ApplicationAlreadyExistsException;
 import org.apache.usergrid.persistence.exceptions.DuplicateUniquePropertyExistsException;
 import org.apache.usergrid.persistence.exceptions.EntityNotFoundException;
-import org.apache.usergrid.persistence.graph.Edge;
-import org.apache.usergrid.persistence.graph.GraphManager;
-import org.apache.usergrid.persistence.graph.GraphManagerFactory;
-import org.apache.usergrid.persistence.graph.MarkedEdge;
-import org.apache.usergrid.persistence.graph.SearchByEdgeType;
+import org.apache.usergrid.persistence.graph.*;
 import org.apache.usergrid.persistence.graph.impl.SimpleSearchByEdgeType;
 import org.apache.usergrid.persistence.index.EntityIndex;
 import org.apache.usergrid.persistence.model.entity.Id;
 import org.apache.usergrid.persistence.model.entity.SimpleId;
 import org.apache.usergrid.persistence.model.util.UUIDGenerator;
 import org.apache.usergrid.utils.UUIDUtils;
-
-import com.google.common.base.Optional;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import com.google.inject.TypeLiteral;
-
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
 import rx.Observable;
 
-import static java.lang.String.CASE_INSENSITIVE_ORDER;
+import java.util.*;
 
+import static java.lang.String.CASE_INSENSITIVE_ORDER;
 import static org.apache.usergrid.persistence.Schema.PROPERTY_NAME;
 import static org.apache.usergrid.persistence.Schema.TYPE_APPLICATION;
 
@@ -265,19 +248,9 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
 
 
     private EntityManager _getEntityManager( UUID applicationId ) {
-        EntityManager em = new CpEntityManager(
-            this,
-            cassandraService,
-            counterUtils,
-            indexService,
-            managerCache,
-            metricsFactory,
-            entityManagerFig,
-            graphManagerFactory,
-            collectionService,
-            connectionService,
-            indexSchemaCacheFactory,
-            applicationId );
+        EntityManager em = new CpEntityManager(cassandraService, counterUtils, indexService, managerCache,
+            metricsFactory, entityManagerFig, graphManagerFactory,  collectionService, connectionService,indexSchemaCacheFactory, applicationId );
+
         return em;
     }
 
@@ -289,8 +262,7 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
 
     @Override
     public Entity createApplicationV2(
-        String orgName, String name, UUID applicationId, Map<String, Object> properties, boolean forMigration)
-        throws Exception {
+        String orgName, String name, UUID applicationId, Map<String, Object> properties, boolean forMigration) throws Exception {
 
         String appName = buildAppName( orgName, name );
 
@@ -392,9 +364,8 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
 
         // find application_info for application to delete
 
-        migrateAppInfo(
-            applicationId, CpNamingUtils.APPLICATION_INFO, CpNamingUtils.DELETED_APPLICATION_INFOS,
-            CpNamingUtils.DELETED_APPLICATION_INFO).toBlocking().lastOrDefault( null );
+        migrateAppInfo(applicationId, CpNamingUtils.APPLICATION_INFO, CpNamingUtils.DELETED_APPLICATION_INFOS, CpNamingUtils.DELETED_APPLICATION_INFO).toBlocking()
+            .lastOrDefault( null );
     }
 
     //TODO: return status for restore
@@ -436,13 +407,9 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
      * @return
      * @throws Exception
      */
-    private Observable migrateAppInfo(
-        final UUID applicationUUID,  final String deleteTypeName, final String createCollectionName,
-        final String createTypeName ) throws Exception {
-
-        final ApplicationScope managementAppScope =
-            CpNamingUtils.getApplicationScope(CpNamingUtils.MANAGEMENT_APPLICATION_ID);
+    private Observable migrateAppInfo(final UUID applicationUUID,  final String deleteTypeName, final String createCollectionName, final String createTypeName ) throws Exception {
 
+        final ApplicationScope managementAppScope = CpNamingUtils.getApplicationScope(CpNamingUtils.MANAGEMENT_APPLICATION_ID);
         final EntityManager managementEm = getEntityManager(CpNamingUtils.MANAGEMENT_APPLICATION_ID);
 
         //the application id we will be removing
@@ -497,8 +464,7 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
         final Id managementAppId = CpNamingUtils.getManagementApplicationId();
         final EntityIndex aei = getManagementIndex();
         final GraphManager managementGraphManager = managerCache.getGraphManager(managementAppScope);
-        final Edge createEdge =
-            CpNamingUtils.createCollectionEdge(managementAppId, createCollectionName, createApplicationId);
+        final Edge createEdge = CpNamingUtils.createCollectionEdge(managementAppId, createCollectionName, createApplicationId);
 
         final Observable createNodeGraph = managementGraphManager.writeEdge(createEdge);
 


[48/50] [abbrv] usergrid git commit: Add Pivotal Cloud Foundry source for creating Usergrid Tile ( CF deployment + bosh release )

Posted by mr...@apache.org.
http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/apache-usergrid-tile-1.6.yml
----------------------------------------------------------------------
diff --git a/deployment/pcf/apache-usergrid-tile-1.6.yml b/deployment/pcf/apache-usergrid-tile-1.6.yml
new file mode 100644
index 0000000..f45570d
--- /dev/null
+++ b/deployment/pcf/apache-usergrid-tile-1.6.yml
@@ -0,0 +1,510 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: apache-usergrid
+label: Apache Usergrid - Open Source mBaaS
+description: Apache's only mBaaS project
+icon_image: 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

<TRUNCATED>

[44/50] [abbrv] usergrid git commit: USERGRID-1300: localhost superuser setting

Posted by mr...@apache.org.
USERGRID-1300: localhost superuser setting


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

Branch: refs/heads/master
Commit: 7ea48c27885da00a9a1d2251702e02bfe8ddf1ef
Parents: 3df0779
Author: Mike Dunker <md...@apigee.com>
Authored: Tue Jun 14 15:16:39 2016 -0700
Committer: Mike Dunker <md...@apigee.com>
Committed: Tue Jun 14 15:16:39 2016 -0700

----------------------------------------------------------------------
 .../main/resources/usergrid-default.properties  |  4 +++
 .../rest/management/ManagementResource.java     |  4 +--
 .../shiro/filters/BasicAuthSecurityFilter.java  | 19 ++++++++++--
 .../management/AccountCreationProps.java        |  3 +-
 .../usergrid/management/ManagementService.java  |  6 +++-
 .../cassandra/AccountCreationPropsImpl.java     | 17 +++++++++--
 .../cassandra/ManagementServiceImpl.java        | 32 ++++++++++++++++----
 .../apache/usergrid/security/shiro/Realm.java   |  6 ----
 .../shiro/principals/AdminUserPrincipal.java    |  4 +--
 .../usergrid/management/OrganizationIT.java     |  2 +-
 .../cassandra/ManagementServiceIT.java          |  6 ++--
 11 files changed, 77 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/config/src/main/resources/usergrid-default.properties
----------------------------------------------------------------------
diff --git a/stack/config/src/main/resources/usergrid-default.properties b/stack/config/src/main/resources/usergrid-default.properties
index 0fc31ef..d2141cf 100644
--- a/stack/config/src/main/resources/usergrid-default.properties
+++ b/stack/config/src/main/resources/usergrid-default.properties
@@ -535,6 +535,10 @@ usergrid.sysadmin.login.email=super@usergrid.com
 usergrid.sysadmin.login.password=test
 usergrid.sysadmin.login.allowed=true
 
+# if usergrid.sysadmin.login.allowed=true, only allows sysadmin login if request is localhost
+# if usergrid.sysadmin.login.allowed=false, this property has no effect
+usergrid.sysadmin.localhost.only=false
+
 # Set admin notification email properties
 #
 usergrid.sysadmin.email=

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
index 1aa75ee..c4a921c 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/management/ManagementResource.java
@@ -220,7 +220,7 @@ public class ManagementResource extends AbstractContextResource {
                 // do checking for different grant types
                 if ( GrantType.PASSWORD.toString().equals( grant_type ) ) {
                     try {
-                        user = management.verifyAdminUserPasswordCredentials( username, password );
+                        user = management.verifyAdminUserPasswordCredentials( username, password, ui );
 
                         if ( user != null ) {
                             if (logger.isTraceEnabled()) {
@@ -438,7 +438,7 @@ public class ManagementResource extends AbstractContextResource {
 
             UserInfo user = null;
             try {
-                user = management.verifyAdminUserPasswordCredentials( username, password );
+                user = management.verifyAdminUserPasswordCredentials( username, password, ui );
             }
             catch ( Exception e1 ) {
                 // intentionally empty

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/BasicAuthSecurityFilter.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/BasicAuthSecurityFilter.java b/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/BasicAuthSecurityFilter.java
index a5d7272..7d6b40c 100644
--- a/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/BasicAuthSecurityFilter.java
+++ b/stack/rest/src/main/java/org/apache/usergrid/rest/security/shiro/filters/BasicAuthSecurityFilter.java
@@ -25,6 +25,7 @@ import javax.ws.rs.container.ContainerRequestContext;
 import javax.ws.rs.container.PreMatching;
 import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.ext.Provider;
+import java.net.InetAddress;
 import java.security.Principal;
 import java.util.Map;
 
@@ -65,11 +66,25 @@ public class BasicAuthSecurityFilter extends SecurityFilter {
         String sysadmin_login_password = properties.getProperty( "usergrid.sysadmin.login.password" );
         boolean sysadmin_login_allowed =
                 Boolean.parseBoolean( properties.getProperty( "usergrid.sysadmin.login.allowed" ) );
-        if ( name.equals( sysadmin_login_name ) && password.equals( sysadmin_login_password )
-                && sysadmin_login_allowed ) {
+        boolean sysadmin_localhost_only =
+                Boolean.parseBoolean( properties.getProperty( "usergrid.sysadmin.localhost.only", "false" ) );
+
+        boolean is_localhost = false;
+        try {
+            is_localhost = InetAddress.getByName(request.getUriInfo().getBaseUri().getHost()).isLoopbackAddress();
+        }
+        catch (Exception e) {
+            // won't treat as localhost
+        }
+        boolean password_match = password.equals( sysadmin_login_password );
+        if ( name.equals( sysadmin_login_name ) && (password_match || is_localhost)
+                && sysadmin_login_allowed && (is_localhost || !sysadmin_localhost_only)) {
             request.setSecurityContext( new SysAdminRoleAuthenticator() );
             if (logger.isTraceEnabled()) {
                 logger.trace("System administrator access allowed");
+                if (!password_match) {
+                    logger.trace("Allowed sysadmin password mismatch because accessing via localhost");
+                }
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/services/src/main/java/org/apache/usergrid/management/AccountCreationProps.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/AccountCreationProps.java b/stack/services/src/main/java/org/apache/usergrid/management/AccountCreationProps.java
index 17f2c6a..a5a0751 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/AccountCreationProps.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/AccountCreationProps.java
@@ -75,6 +75,7 @@ public interface AccountCreationProps {
     String PROPERTIES_SYSADMIN_LOGIN_EMAIL = "usergrid.sysadmin.login.email";
     String PROPERTIES_SYSADMIN_LOGIN_NAME = "usergrid.sysadmin.login.name";
     String PROPERTIES_SYSADMIN_LOGIN_ALLOWED = "usergrid.sysadmin.login.allowed";
+    String PROPERTIES_SYSADMIN_LOCALHOST_ONLY = "usergrid.sysadmin.localhost.only";
 
     String PROPERTIES_ADMIN_SYSADMIN_EMAIL = "usergrid.admin.sysadmin.email";
     String PROPERTIES_ORG_SYSADMIN_EMAIL = "usergrid.org.sysadmin.email";
@@ -127,7 +128,7 @@ public interface AccountCreationProps {
     SuperUser getSuperUser();
 
     interface SuperUser{
-        boolean isEnabled();
+        boolean isEnabled(String host);
         String getUsername();
         String getEmail();
         String getPassword();

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java b/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
index 1d74ec3..481f272 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/ManagementService.java
@@ -39,6 +39,8 @@ import org.apache.usergrid.services.ServiceResults;
 import com.google.common.collect.BiMap;
 import rx.Observable;
 
+import javax.ws.rs.core.UriInfo;
+
 
 public interface ManagementService {
 
@@ -268,7 +270,9 @@ public interface ManagementService {
 
 	boolean verifyAdminUserPassword( UUID userId, String password ) throws Exception;
 
-	UserInfo verifyAdminUserPasswordCredentials( String name, String password ) throws Exception;
+	UserInfo verifyAdminUserPasswordCredentialsOnly( String name, String password ) throws Exception;
+
+	UserInfo verifyAdminUserPasswordCredentials( String name, String password, UriInfo uriInfo ) throws Exception;
 
 	UserInfo verifyMongoCredentials( String name, String nonce, String key ) throws Exception;
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/services/src/main/java/org/apache/usergrid/management/cassandra/AccountCreationPropsImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/AccountCreationPropsImpl.java b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/AccountCreationPropsImpl.java
index 7c6a091..4077ef9 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/AccountCreationPropsImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/AccountCreationPropsImpl.java
@@ -17,9 +17,11 @@
 package org.apache.usergrid.management.cassandra;
 
 
+import java.net.InetAddress;
 import java.util.Enumeration;
 import java.util.Properties;
 
+import com.amazonaws.util.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.usergrid.management.AccountCreationProps;
@@ -131,17 +133,28 @@ public class AccountCreationPropsImpl implements AccountCreationProps {
         private final String username;
         private final String email;
         private final String password;
+        private final boolean localhostOnly;
 
         public SuperUserImpl(Properties properties) {
             enabled = parseBoolean(properties.getProperty(PROPERTIES_SYSADMIN_LOGIN_ALLOWED));
             username = properties.getProperty(PROPERTIES_SYSADMIN_LOGIN_NAME);
             email = properties.getProperty(PROPERTIES_SYSADMIN_LOGIN_EMAIL);
             password = properties.getProperty(PROPERTIES_SYSADMIN_LOGIN_PASSWORD);
+            localhostOnly = parseBoolean(properties.getProperty(PROPERTIES_SYSADMIN_LOCALHOST_ONLY, "false"));
         }
 
         @Override
-        public boolean isEnabled() {
-            return superuserEnabled();
+        public boolean isEnabled(String host) {
+            boolean isLocalhost = false;
+            // if host not passed in, assume not localhost
+            if (!StringUtils.isNullOrEmpty(host)) {
+                try {
+                    isLocalhost = InetAddress.getByName(host).isLoopbackAddress();
+                } catch (Exception e) {
+                    // will treat as non-localhost
+                }
+            }
+            return superuserEnabled() && (isLocalhost || !localhostOnly);
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
index 73a56c8..bf20c6d 100644
--- a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
+++ b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java
@@ -27,6 +27,7 @@ import com.google.inject.Injector;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.lang.text.StrSubstitutor;
 import org.apache.shiro.UnavailableSecurityManagerException;
+import org.apache.shiro.authc.ExcessiveAttemptsException;
 import org.apache.usergrid.corepersistence.service.AggregationService;
 import org.apache.usergrid.corepersistence.service.AggregationServiceFactory;
 import org.apache.usergrid.corepersistence.service.ApplicationService;
@@ -76,6 +77,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import rx.Observable;
 
+import javax.ws.rs.core.UriInfo;
 import java.nio.ByteBuffer;
 import java.util.*;
 import java.util.Map.Entry;
@@ -357,13 +359,13 @@ public class ManagementServiceImpl implements ManagementService {
             logger.warn( "Test app creation disabled" );
         }
 
-        if ( superuserEnabled() ) {
+        if ( superuserShouldBeProvisioned() ) {
             provisionSuperuser();
         }
     }
 
 
-    public boolean superuserEnabled() {
+    public boolean superuserShouldBeProvisioned() {
         boolean superuser_enabled = getBooleanProperty( PROPERTIES_SYSADMIN_LOGIN_ALLOWED );
         String superuser_username = properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_NAME );
         String superuser_email = properties.getProperty( PROPERTIES_SYSADMIN_LOGIN_EMAIL );
@@ -1347,10 +1349,27 @@ public class ManagementServiceImpl implements ManagementService {
 
 
     @Override
-    public UserInfo verifyAdminUserPasswordCredentials( String name, String password ) throws Exception {
+    public UserInfo verifyAdminUserPasswordCredentials( String name, String password, UriInfo uriInfo ) throws Exception {
+        // uriInfo should not be null
+        Preconditions.checkArgument(uriInfo != null, "uriInfo parameter should not be null");
+
+        return verifyAdminUserPasswordCredentialsInternal(name, password, uriInfo);
+    }
+
+
+    @Override
+    public UserInfo verifyAdminUserPasswordCredentialsOnly( String name, String password ) throws Exception {
+        return verifyAdminUserPasswordCredentialsInternal(name, password, null);
+    }
+
+
+    private UserInfo verifyAdminUserPasswordCredentialsInternal( String name, String password, UriInfo uriInfo)
+            throws Exception {
+
+        // null UriInfo means assume not a localhost request
 
         if(logger.isTraceEnabled()){
-            logger.trace("verifyAdminUserPasswordCredentials for {}", name);
+            logger.trace("verifyAdminUserPasswordCredentialsInternal for {}", name);
         }
 
         User user = findUserEntity( smf.getManagementAppId(), name );
@@ -1361,7 +1380,8 @@ public class ManagementServiceImpl implements ManagementService {
         if ( verify( smf.getManagementAppId(), user.getUuid(), password ) ) {
             UserInfo userInfo = getUserInfo( smf.getManagementAppId(), user );
 
-            boolean userIsSuperAdmin = properties.getSuperUser().isEnabled()
+            boolean userIsSuperAdmin =
+                    properties.getSuperUser().isEnabled(uriInfo != null ? uriInfo.getBaseUri().getHost() : null)
                 && properties.getSuperUser().getEmail().equals(userInfo.getEmail());
 
             boolean testUserEnabled = parseBoolean( properties.getProperty( PROPERTIES_SETUP_TEST_ACCOUNT ) );
@@ -1634,7 +1654,7 @@ public class ManagementServiceImpl implements ManagementService {
         Map<UUID, String> organizations;
 
         AccountCreationProps.SuperUser superUser = properties.getSuperUser();
-        if ( superUser.isEnabled() && superUser.getUsername().equals( user.getUsername() ) ) {
+        if ( superUser.isEnabled(null) && superUser.getUsername().equals( user.getUsername() ) ) {
             int maxOrganizations = this.getAccountCreationProps().getMaxOrganizationsForSuperUserLogin();
             organizations = buildOrgBiMap( getOrganizations( null, maxOrganizations ) );
         }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java b/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java
index 4381f01..c8ca812 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/shiro/Realm.java
@@ -56,12 +56,6 @@ public class Realm extends AuthorizingRealm {
     private TokenService tokens;
 
 
-    @Value( "${" + PROPERTIES_SYSADMIN_LOGIN_ALLOWED + "}" )
-    private boolean superUserEnabled;
-    @Value( "${" + AccountCreationProps.PROPERTIES_SYSADMIN_LOGIN_NAME + ":admin}" )
-    private String superUser;
-
-
     public Realm() {
         setCredentialsMatcher(new AllowAllCredentialsMatcher());
         setPermissionResolver(new CustomPermissionResolver());

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java b/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java
index a594d1e..fd4f0c5 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/shiro/principals/AdminUserPrincipal.java
@@ -66,9 +66,9 @@ public class AdminUserPrincipal extends UserPrincipal {
         ApplicationInfo application = null;
 
         boolean superUserEnabled = false;
-        final String s = management.getProperties().getProperty(
+        final String sysadminLoginAllowedProp = management.getProperties().getProperty(
             AccountCreationProps.PROPERTIES_SYSADMIN_LOGIN_ALLOWED);
-        if ( s != null && "true".equalsIgnoreCase(s.trim())) {
+        if ( sysadminLoginAllowedProp != null && "true".equalsIgnoreCase(sysadminLoginAllowedProp.trim())) {
             superUserEnabled = true;
         }
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/services/src/test/java/org/apache/usergrid/management/OrganizationIT.java
----------------------------------------------------------------------
diff --git a/stack/services/src/test/java/org/apache/usergrid/management/OrganizationIT.java b/stack/services/src/test/java/org/apache/usergrid/management/OrganizationIT.java
index 9d20dcb..44599a6 100644
--- a/stack/services/src/test/java/org/apache/usergrid/management/OrganizationIT.java
+++ b/stack/services/src/test/java/org/apache/usergrid/management/OrganizationIT.java
@@ -103,7 +103,7 @@ public class OrganizationIT {
 
         setup.getEntityIndex().refresh(CpNamingUtils.MANAGEMENT_APPLICATION_ID);
 
-        UserInfo u = setup.getMgmtSvc().verifyAdminUserPasswordCredentials(
+        UserInfo u = setup.getMgmtSvc().verifyAdminUserPasswordCredentialsOnly(
             organization.getOwner().getUuid().toString(), "test" );
         assertNotNull( u );
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7ea48c27/stack/services/src/test/java/org/apache/usergrid/management/cassandra/ManagementServiceIT.java
----------------------------------------------------------------------
diff --git a/stack/services/src/test/java/org/apache/usergrid/management/cassandra/ManagementServiceIT.java b/stack/services/src/test/java/org/apache/usergrid/management/cassandra/ManagementServiceIT.java
index 6179a6d..83ceae9 100644
--- a/stack/services/src/test/java/org/apache/usergrid/management/cassandra/ManagementServiceIT.java
+++ b/stack/services/src/test/java/org/apache/usergrid/management/cassandra/ManagementServiceIT.java
@@ -480,15 +480,15 @@ public class ManagementServiceIT {
         EntityManager em = setup.getEmf().getEntityManager( setup.getSmf().getManagementAppId() );
         setup.getEntityIndex().refresh(applicationId);
 
-        UserInfo authedUser = setup.getMgmtSvc().verifyAdminUserPasswordCredentials( username, password );
+        UserInfo authedUser = setup.getMgmtSvc().verifyAdminUserPasswordCredentialsOnly( username, password );
 
         assertEquals( adminUser.getUuid(), authedUser.getUuid() );
 
-        authedUser = setup.getMgmtSvc().verifyAdminUserPasswordCredentials( adminUser.getEmail(), password );
+        authedUser = setup.getMgmtSvc().verifyAdminUserPasswordCredentialsOnly( adminUser.getEmail(), password );
 
         assertEquals( adminUser.getUuid(), authedUser.getUuid() );
 
-        authedUser = setup.getMgmtSvc().verifyAdminUserPasswordCredentials( adminUser.getUuid().toString(), password );
+        authedUser = setup.getMgmtSvc().verifyAdminUserPasswordCredentialsOnly( adminUser.getUuid().toString(), password );
 
         assertEquals( adminUser.getUuid(), authedUser.getUuid() );
     }


[08/50] [abbrv] usergrid git commit: Merge branch 'release-2.1.1' of https://git-wip-us.apache.org/repos/asf/usergrid into release-2.1.1

Posted by mr...@apache.org.
Merge branch 'release-2.1.1' of https://git-wip-us.apache.org/repos/asf/usergrid into release-2.1.1


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

Branch: refs/heads/master
Commit: aae8fdf817c59a57ef875ab5f8aa9e7a47a945ab
Parents: ebcc772 5107ccf
Author: Dave Johnson <sn...@apache.org>
Authored: Fri May 20 12:02:02 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri May 20 12:02:02 2016 -0400

----------------------------------------------------------------------
 .../usergrid/security/shiro/ShiroCache.java     | 44 +++++++++++++++++++-
 1 file changed, 42 insertions(+), 2 deletions(-)
----------------------------------------------------------------------



[32/50] [abbrv] usergrid git commit: Quick fix for Core tests: ensure lockManager gets initialized.

Posted by mr...@apache.org.
Quick fix for Core tests: ensure lockManager gets initialized.


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

Branch: refs/heads/master
Commit: 17809acdac0c66725dbcd7ad79b0240e4a7290b0
Parents: e6cf6ed
Author: Dave Johnson <sn...@apache.org>
Authored: Fri Jun 3 11:45:13 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri Jun 3 11:45:13 2016 -0400

----------------------------------------------------------------------
 .../org/apache/usergrid/persistence/CoreSchemaManager.java   | 8 +++++++-
 stack/core/src/test/resources/usergrid-test-context.xml      | 1 +
 2 files changed, 8 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/17809acd/stack/core/src/test/java/org/apache/usergrid/persistence/CoreSchemaManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/test/java/org/apache/usergrid/persistence/CoreSchemaManager.java b/stack/core/src/test/java/org/apache/usergrid/persistence/CoreSchemaManager.java
index c6c2d26..28f2c9f 100644
--- a/stack/core/src/test/java/org/apache/usergrid/persistence/CoreSchemaManager.java
+++ b/stack/core/src/test/java/org/apache/usergrid/persistence/CoreSchemaManager.java
@@ -17,6 +17,7 @@
 package org.apache.usergrid.persistence;
 
 
+import org.apache.usergrid.locking.LockManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,11 +38,13 @@ public class CoreSchemaManager implements SchemaManager {
 
     private final Setup setup;
     private final Cluster cluster;
+    private final LockManager lockManager;
 
 
-    public CoreSchemaManager( final Setup setup, final Cluster cluster ) {
+    public CoreSchemaManager( final Setup setup, final Cluster cluster, Injector injector ) {
         this.setup = setup;
         this.cluster = cluster;
+        this.lockManager = injector.getInstance( LockManager.class );
     }
 
 
@@ -49,6 +52,7 @@ public class CoreSchemaManager implements SchemaManager {
     public void create() {
         try {
             setup.initSchema();
+            lockManager.setup();
         }
         catch ( Exception ex ) {
             logger.error( "Could not setup usergrid core schema", ex );
@@ -62,6 +66,8 @@ public class CoreSchemaManager implements SchemaManager {
         try {
 
             setup.initSchema();
+            lockManager.setup();
+
             setup.runDataMigration();
             setup.initMgmtApp();
         }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/17809acd/stack/core/src/test/resources/usergrid-test-context.xml
----------------------------------------------------------------------
diff --git a/stack/core/src/test/resources/usergrid-test-context.xml b/stack/core/src/test/resources/usergrid-test-context.xml
index 6b10a7c..5572619 100644
--- a/stack/core/src/test/resources/usergrid-test-context.xml
+++ b/stack/core/src/test/resources/usergrid-test-context.xml
@@ -55,5 +55,6 @@
     <bean id="coreManager" class="org.apache.usergrid.persistence.CoreSchemaManager">
         <constructor-arg ref="setup"/>
         <constructor-arg ref="cassandraCluster"/>
+        <constructor-arg ref="injector"/>
     </bean>
 </beans>


[13/50] [abbrv] usergrid git commit: Revert "Adding distinctive logging, also: no longer wrap RuntimeException in RuntimeException"

Posted by mr...@apache.org.
Revert "Adding distinctive logging, also: no longer wrap RuntimeException in RuntimeException"

This reverts commit 6b195a07b94858deecdc80156d9ab9ebd6ae4a80.


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

Branch: refs/heads/master
Commit: b03f6a9eaee9cd529ff8ca781030415798f32e7d
Parents: aae8fdf
Author: Dave Johnson <sn...@apache.org>
Authored: Tue May 24 14:36:29 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Tue May 24 14:36:29 2016 -0400

----------------------------------------------------------------------
 .../org/apache/usergrid/services/ServiceManager.java   | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/b03f6a9e/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
index ef1baaf..1ed73d6 100644
--- a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
@@ -128,27 +128,18 @@ public class ServiceManager {
                     if ( application != null ) {
                         appNotFound = false;
                         applicationId = application.getUuid();
-
                     } else {
-                        // Cassandra may be alive but responding very slowly, let's wait and retry
-                        logger.error("STARTUP PROBLEM: Cannot get application by UUID. Will retry in {} seconds #{}",
-                            retryInterval/1000, retryCount);
                         Thread.sleep( retryInterval );
                         retryCount++;
                     }
                 }
 
                 if ( application == null ) {
-                    Exception e = new RuntimeException(
-                        "STARTUP FAILURE: application id {" + em.getApplicationId()
-                            + "} is returning null after " + retryCount + " retries" );
+                    Exception e = new RuntimeException( "application id {" + em.getApplicationId() + "} is returning null" );
+                    logger.error( "Failed to get application", e );
                     throw e;
                 }
 
-            } catch ( RuntimeException re ) {
-                logger.error( "ServiceManager init failure", re );
-                throw re;
-
             } catch ( Exception e ) {
                 logger.error( "ServiceManager init failure", e );
                 throw new RuntimeException( e );


[23/50] [abbrv] usergrid git commit: Move LockManager setup into normal setup regime, don't cache EntityManagers with null application names, and add logging to help debug issue USERGRID-1283.

Posted by mr...@apache.org.
Move LockManager setup into normal setup regime, don't cache EntityManagers with null application names, and add logging to help debug issue USERGRID-1283.


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

Branch: refs/heads/master
Commit: 59c538aa8a6becf90573c815e68347036f1aca44
Parents: 61a35a0
Author: Dave Johnson <sn...@apache.org>
Authored: Tue May 31 09:34:48 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Tue May 31 09:34:48 2016 -0400

----------------------------------------------------------------------
 .../corepersistence/CpEntityManagerFactory.java | 13 +++++-
 .../apache/usergrid/locking/LockManager.java    |  5 +++
 .../cassandra/AstyanaxLockManagerImpl.java      | 42 ++++++--------------
 .../locking/noop/NoOpLockManagerImpl.java       |  5 +++
 .../usergrid/services/ServiceManager.java       |  8 ++++
 .../services/ServiceManagerFactory.java         | 12 ++++++
 6 files changed, 54 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/59c538aa/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
index ee28765..622944b 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
@@ -33,6 +33,7 @@ import org.apache.usergrid.corepersistence.service.CollectionService;
 import org.apache.usergrid.corepersistence.service.ConnectionService;
 import org.apache.usergrid.corepersistence.util.CpNamingUtils;
 import org.apache.usergrid.exception.ConflictException;
+import org.apache.usergrid.locking.LockManager;
 import org.apache.usergrid.persistence.*;
 import org.apache.usergrid.persistence.cassandra.CassandraService;
 import org.apache.usergrid.persistence.cassandra.CounterUtils;
@@ -107,6 +108,7 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
     private final ConnectionService connectionService;
     private final GraphManagerFactory graphManagerFactory;
     private final IndexSchemaCacheFactory indexSchemaCacheFactory;
+    private final LockManager lockManager;
 
     public static final String MANAGEMENT_APP_INIT_MAXRETRIES= "management.app.init.max-retries";
     public static final String MANAGEMENT_APP_INIT_INTERVAL = "management.app.init.interval";
@@ -127,6 +129,7 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
         this.collectionService = injector.getInstance( CollectionService.class );
         this.connectionService = injector.getInstance( ConnectionService.class );
         this.indexSchemaCacheFactory = injector.getInstance( IndexSchemaCacheFactory.class );
+        this.lockManager = injector.getInstance( LockManager.class );
 
         Properties properties = cassandraService.getProperties();
 
@@ -166,7 +169,6 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
                     }
 
                     // the management app is a special case
-
                     if ( CpNamingUtils.MANAGEMENT_APPLICATION_ID.equals( appId ) ) {
 
                         if ( app != null ) {
@@ -179,6 +181,7 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
                         }
                     }
 
+                    // missing keyspace means we have not done bootstrap yet
                     final boolean missingKeyspace;
                     if ( throwable instanceof CollectionRuntimeException ) {
                         CollectionRuntimeException cre = (CollectionRuntimeException) throwable;
@@ -187,6 +190,13 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
                         missingKeyspace = false;
                     }
 
+                    // work around for https://issues.apache.org/jira/browse/USERGRID-1291
+                    // throw exception so that we do not cache 
+                    // TODO: determine how application name can intermittently be null
+                    if ( app != null && app.getName() == null ) {
+                        throw new RuntimeException( "Name is null for application " + appId, throwable );
+                    }
+
                     if ( app == null && !missingKeyspace ) {
                         throw new RuntimeException( "Error getting application " + appId, throwable );
 
@@ -645,6 +655,7 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
     @Override
     public void setup() throws Exception {
         getSetup().initSchema();
+        lockManager.setup();
     }
 
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/59c538aa/stack/core/src/main/java/org/apache/usergrid/locking/LockManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/LockManager.java b/stack/core/src/main/java/org/apache/usergrid/locking/LockManager.java
index a2d37ab..4ed41d8 100644
--- a/stack/core/src/main/java/org/apache/usergrid/locking/LockManager.java
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/LockManager.java
@@ -38,4 +38,9 @@ public interface LockManager {
      * @throws UGLockException if the lock cannot be acquired
      */
     public Lock createLock( final UUID applicationId, final String... path );
+
+    /**
+     * Setup lock persistence mechanism.
+     */
+    public void setup();
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/59c538aa/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
index 6acce47..90b9d57 100644
--- a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
@@ -50,6 +50,7 @@ public class AstyanaxLockManagerImpl implements LockManager {
 
 
     private final CassandraFig cassandraFig;
+    private final CassandraCluster cassandraCluster;
     private Keyspace keyspace;
     private ColumnFamily columnFamily;
     private static final int MINIMUM_LOCK_EXPIRATION = 60000; // 1 minute
@@ -60,38 +61,19 @@ public class AstyanaxLockManagerImpl implements LockManager {
                                    CassandraCluster cassandraCluster ) throws ConnectionException {
 
         this.cassandraFig = cassandraFig;
+        this.cassandraCluster = cassandraCluster;
+    }
 
-        // hold up construction until we can create the column family
-        int maxRetries = cassandraFig.getLockManagerInitRetries();
-        int retries = 0;
-        boolean famReady = false;
-        Set<Class> seenBefore = new HashSet<>(10);
-        while ( !famReady && retries++ < maxRetries ) {
-            try {
-                keyspace = cassandraCluster.getLocksKeyspace();
-                createLocksKeyspace();
-                columnFamily = createLocksColumnFamily();
-                famReady = true;
-
-            } catch ( Throwable t ) {
-                final String msg;
-                if ( t instanceof PoolTimeoutException || t instanceof NoAvailableHostsException) {
-                    msg = retries + ": Cannot connect to Cassandra (" + t.getClass().getSimpleName() + ")";
-                } else {
-                    msg = retries + ": Error (" + t.getClass().getSimpleName() + ") tries=" + retries;
-                }
-                if ( !seenBefore.contains( t.getClass() ) ) {
-                    logger.error( msg, t );
-                } else {
-                    logger.error( msg );
-                }
-                seenBefore.add( t.getClass() );
-                try {
-                    Thread.sleep( cassandraFig.getLockManagerInitInterval() );
-                } catch (InterruptedException ignored) {}
-            }
-        }
 
+    @Override
+    public void setup() {
+        try {
+            keyspace = cassandraCluster.getLocksKeyspace();
+            createLocksKeyspace();
+            columnFamily = createLocksColumnFamily();
+        } catch (ConnectionException e) {
+            throw new RuntimeException( "Error setting up locks keyspace and column family", e );
+        }
     }
 
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/59c538aa/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockManagerImpl.java
index 6174890..ff14031 100644
--- a/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockManagerImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/noop/NoOpLockManagerImpl.java
@@ -38,4 +38,9 @@ public class NoOpLockManagerImpl implements LockManager {
     public Lock createLock( UUID applicationId, String... path ) {
         return new NoOpLockImpl();
     }
+
+    @Override
+    public void setup() {
+        // no op
+    }
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/59c538aa/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
index a9892f5..04e00e0 100644
--- a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
@@ -96,6 +96,14 @@ public class ServiceManager {
         this.qm = qm;
         this.properties = properties;
 
+        // additional logging to help debug https://issues.apache.org/jira/browse/USERGRID-1291
+        if ( em == null ) {
+            logger.error("EntityManager is null");
+        }
+        if ( qm == null ) {
+            logger.error("QueueManager is null");
+        }
+
         if ( em != null ) {
             try {
                 application = em.getApplication();

http://git-wip-us.apache.org/repos/asf/usergrid/blob/59c538aa/stack/services/src/main/java/org/apache/usergrid/services/ServiceManagerFactory.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManagerFactory.java b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManagerFactory.java
index 5274336..2425b95 100644
--- a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManagerFactory.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManagerFactory.java
@@ -23,6 +23,8 @@ import java.util.UUID;
 
 import com.google.inject.Injector;
 import org.apache.usergrid.locking.Lock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
@@ -35,6 +37,7 @@ import org.apache.usergrid.persistence.EntityManagerFactory;
 
 
 public class ServiceManagerFactory implements ApplicationContextAware {
+    private static final Logger logger = LoggerFactory.getLogger( ServiceManagerFactory.class );
 
     private ApplicationContext applicationContext;
 
@@ -59,6 +62,15 @@ public class ServiceManagerFactory implements ApplicationContextAware {
 
 
     public ServiceManager getServiceManager( UUID applicationId ) {
+
+        // additional logging to help debug https://issues.apache.org/jira/browse/USERGRID-1291
+        if ( emf == null ) {
+            logger.error("EntityManagerFactory is null");
+        }
+        if ( qmf == null ) {
+            logger.error("QueueManagerFactory is null");
+        }
+
         EntityManager em = null;
         if ( emf != null ) {
             em = emf.getEntityManager( applicationId );


[38/50] [abbrv] usergrid git commit: Only execute read repair delete batch if there are no rows to delete.

Posted by mr...@apache.org.
Only execute read repair delete batch if there are no rows to delete.


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

Branch: refs/heads/master
Commit: 48780f07d1d94bc7b8a6934dbd5da3446102e8fc
Parents: 7143cba
Author: Michael Russo <mr...@apigee.com>
Authored: Mon Jun 6 10:44:11 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Mon Jun 6 10:44:11 2016 -0700

----------------------------------------------------------------------
 .../impl/EntityCollectionManagerImpl.java       | 22 +++++++++++++-------
 1 file changed, 14 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/48780f07/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
index 70b06ba..fcf1c6b 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
@@ -385,23 +385,29 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager {
                     response.addEntity( expectedUnique.getField(), entity );
                 }
 
-                deleteBatch.execute();
+                if ( deleteBatch.getRowCount() > 0 ) {
 
-                // optionally sleep after read repair as some tasks immediately try to write after the delete
-                if ( serializationFig.getReadRepairDelay() > 0 ){
+                    deleteBatch.execute();
 
-                    try {
+                    // optionally sleep after read repair as some tasks immediately try to write after the delete
+                    if ( serializationFig.getReadRepairDelay() > 0 ){
 
-                        Thread.sleep(Math.min(serializationFig.getReadRepairDelay(), 200L));
+                        try {
 
-                    } catch (InterruptedException e) {
+                            Thread.sleep(Math.min(serializationFig.getReadRepairDelay(), 200L));
+
+                        } catch (InterruptedException e) {
+
+                            // do nothing if sleep fails; log and continue on
+                            logger.warn("Sleep during unique value read repair failed.");
+                        }
 
-                        // do nothing if sleep fails; log and continue on
-                        logger.warn("Sleep during unique value read repair failed.");
                     }
 
                 }
 
+
+
                 return response;
             }
             catch ( ConnectionException e ) {


[37/50] [abbrv] usergrid git commit: Separate create vs. get column family logic.

Posted by mr...@apache.org.
Separate create vs. get column family logic.


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

Branch: refs/heads/master
Commit: cc7a8678481dccda00d867fc363abc0d404f0c37
Parents: fcb347c
Author: Dave Johnson <sn...@apache.org>
Authored: Mon Jun 6 12:23:46 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Mon Jun 6 12:23:46 2016 -0400

----------------------------------------------------------------------
 .../cassandra/AstyanaxLockManagerImpl.java      | 87 ++++++++++++--------
 1 file changed, 53 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/cc7a8678/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
index 90b9d57..e26aed4 100644
--- a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
@@ -62,13 +62,13 @@ public class AstyanaxLockManagerImpl implements LockManager {
 
         this.cassandraFig = cassandraFig;
         this.cassandraCluster = cassandraCluster;
+        this.keyspace = cassandraCluster.getLocksKeyspace();
     }
 
 
     @Override
     public void setup() {
         try {
-            keyspace = cassandraCluster.getLocksKeyspace();
             createLocksKeyspace();
             columnFamily = createLocksColumnFamily();
         } catch (ConnectionException e) {
@@ -78,7 +78,7 @@ public class AstyanaxLockManagerImpl implements LockManager {
 
 
     @Override
-    public Lock createLock(final UUID applicationId, final String... path ){
+    public Lock createLock(final UUID applicationId, final String... path ) {
 
         String lockPath = LockPathBuilder.buildPath( applicationId, path );
 
@@ -114,7 +114,7 @@ public class AstyanaxLockManagerImpl implements LockManager {
 
 
         ColumnPrefixDistributedRowLock<String> lock =
-            new ColumnPrefixDistributedRowLock<>(keyspace, columnFamily, lockPath)
+            new ColumnPrefixDistributedRowLock<>(keyspace, getLocksColumnFamily(), lockPath)
                 .expireLockAfter( lockExpiration, TimeUnit.MILLISECONDS)
                 .withConsistencyLevel(consistencyLevel);
 
@@ -124,56 +124,75 @@ public class AstyanaxLockManagerImpl implements LockManager {
     }
 
 
+    private ColumnFamily getLocksColumnFamily() {
 
-    private ColumnFamily createLocksColumnFamily() throws ConnectionException {
+        if ( columnFamily == null ) {
 
-        ColumnFamily<String, String> CF_LOCKS = ColumnFamily.newColumnFamily(
-            CF_NAME, StringSerializer.get(), StringSerializer.get() );
+            columnFamily = ColumnFamily.newColumnFamily(
+                CF_NAME, StringSerializer.get(), StringSerializer.get() );
 
-        final KeyspaceDefinition keyspaceDefinition = keyspace.describeKeyspace();
-        final ColumnFamilyDefinition existing =
-            keyspaceDefinition.getColumnFamily( CF_LOCKS.getName() );
+            if ( logger.isDebugEnabled() ) {
 
+                try {
+                    final KeyspaceDefinition kd = keyspace.describeKeyspace();
+                    final ColumnFamilyDefinition cfd = kd.getColumnFamily( columnFamily.getName() );
+                    Map<String, Object> options = new HashMap<>( 1 );
+                    options.put( "gc_grace_seconds", cfd.getGcGraceSeconds() );
+                    options.put( "caching", cfd.getCaching() );
+                    options.put( "compaction_strategy", cfd.getCompactionStrategy() );
+                    options.put( "compaction_strategy_options", cfd.getCompactionStrategyOptions() );
+                    logger.debug( "Locks column family {} exists with options: {}", cfd.getName(), options);
+
+                } catch ( ConnectionException ce ) {
+                    logger.warn("Error connecting to Cassandra for debug column family info", ce);
+                }
+            }
+        }
 
-        if ( existing != null ) {
+        return columnFamily;
+    }
 
-            Map<String, Object> existingOptions = new HashMap<>(1);
-            existingOptions.put("gc_grace_seconds", existing.getGcGraceSeconds());
-            existingOptions.put("caching", existing.getCaching());
-            existingOptions.put("compaction_strategy", existing.getCompactionStrategy());
-            existingOptions.put("compaction_strategy_options", existing.getCompactionStrategyOptions());
 
-            logger.info( "Locks column family {} exists with options: {}", existing.getName(),
-                existingOptions.toString() );
+    private ColumnFamily createLocksColumnFamily() throws ConnectionException {
 
-            return CF_LOCKS;
-        }
+        ColumnFamily<String, String> cflocks = ColumnFamily.newColumnFamily(
+            CF_NAME, StringSerializer.get(), StringSerializer.get() );
 
-        MultiTenantColumnFamilyDefinition columnFamilyDefinition = new MultiTenantColumnFamilyDefinition(
-            CF_LOCKS,
-            BytesType.class.getSimpleName(),
-            UTF8Type.class.getSimpleName(),
-            BytesType.class.getSimpleName(),
-            MultiTenantColumnFamilyDefinition.CacheOption.ALL
-        );
+        final KeyspaceDefinition kd = keyspace.describeKeyspace();
+        final ColumnFamilyDefinition cfdef = kd.getColumnFamily( cflocks.getName() );
 
-        Map<String, Object> cfOptions = columnFamilyDefinition.getOptions();
+        if ( cfdef == null ) {
 
-        // Additionally set the gc grace low
-        cfOptions.put("gc_grace_seconds", 60);
+            // create only if does not already exist
 
+            MultiTenantColumnFamilyDefinition mtcfd = new MultiTenantColumnFamilyDefinition(
+                cflocks,
+                BytesType.class.getSimpleName(),
+                UTF8Type.class.getSimpleName(),
+                BytesType.class.getSimpleName(),
+                MultiTenantColumnFamilyDefinition.CacheOption.ALL
+            );
 
-        keyspace.createColumnFamily( columnFamilyDefinition.getColumnFamily() , cfOptions );
+            Map<String, Object> cfOptions = mtcfd.getOptions();
 
-        logger.info( "Created column family {}", columnFamilyDefinition.getOptions() );
+            // Additionally set the gc grace low
+            cfOptions.put( "gc_grace_seconds", 60 );
 
-        return columnFamilyDefinition.getColumnFamily();
-    }
+            keyspace.createColumnFamily( mtcfd.getColumnFamily(), cfOptions );
 
+            logger.info( "Created column family {}", mtcfd.getOptions() );
 
-    private void createLocksKeyspace() throws ConnectionException {
+            cflocks = mtcfd.getColumnFamily();
+
+        } else {
+            return getLocksColumnFamily();
+        }
+
+        return cflocks;
+    }
 
 
+    private void createLocksKeyspace() throws ConnectionException {
 
         ImmutableMap.Builder<String, Object> strategyOptions = getKeySpaceProps();
 


[14/50] [abbrv] usergrid git commit: Revert "Service manager's init() method now retries if unable to get application."

Posted by mr...@apache.org.
Revert "Service manager's init() method now retries if unable to get application."

This reverts commit 223521e4150e520c92560bbea873b6a024e18a0e.


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

Branch: refs/heads/master
Commit: 0970e1dfa1b7f54204b6ad82e4bf01da84b38618
Parents: b03f6a9
Author: Dave Johnson <sn...@apache.org>
Authored: Tue May 24 14:36:44 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Tue May 24 14:36:44 2016 -0400

----------------------------------------------------------------------
 .../main/resources/usergrid-default.properties  |  5 --
 .../usergrid/services/ServiceManager.java       | 52 +++-----------------
 2 files changed, 8 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/0970e1df/stack/config/src/main/resources/usergrid-default.properties
----------------------------------------------------------------------
diff --git a/stack/config/src/main/resources/usergrid-default.properties b/stack/config/src/main/resources/usergrid-default.properties
index 35e12ae..4f57cdd 100644
--- a/stack/config/src/main/resources/usergrid-default.properties
+++ b/stack/config/src/main/resources/usergrid-default.properties
@@ -628,11 +628,6 @@ usergrid.auth.cache.inmemory.size=3000
 # all (= in + out)'
 usergrid.rest.default-connection-param=all
 
-# In a busy cluster the Service Manager's init() may fail (usually a time-out) on the first
-# attempt to communicate with Cassandra or ElasticSearch so we retry on failure, using an
-# interval that is longer than the default (10s) Cassandra connection time-out.
-service.manager.retry.interval=15000
-service.manager.max.retries=5
 
 
 ##############################  Usergrid Testing  #############################

http://git-wip-us.apache.org/repos/asf/usergrid/blob/0970e1df/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
index 1ed73d6..a9892f5 100644
--- a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
@@ -50,6 +50,7 @@ import static org.apache.usergrid.utils.InflectionUtils.pluralize;
 
 public class ServiceManager {
 
+
     private static final Logger logger = LoggerFactory.getLogger( ServiceManager.class );
 
     /** A pointer that signals we couldn't find a class */
@@ -68,10 +69,6 @@ public class ServiceManager {
     public static final String APPLICATION_REQUESTS_PER = APPLICATION_REQUESTS + ".";
     public static final String IMPL = "Impl";
 
-    public static final String SERVICE_MANAGER_RETRY_INTERVAL = "service.manager.retry.interval";
-
-    public static final String SERVICE_MANAGER_MAX_RETRIES= "service.manager.max.retries";
-
     private Application application;
 
     private UUID applicationId;
@@ -99,60 +96,27 @@ public class ServiceManager {
         this.qm = qm;
         this.properties = properties;
 
-        Integer retryInterval;
-        try {
-            Object retryIntervalObject = properties.get( SERVICE_MANAGER_RETRY_INTERVAL ).toString();
-            retryInterval = Integer.parseInt( retryIntervalObject.toString() );
-        } catch ( NumberFormatException nfe ) {
-            retryInterval = 15000;
-        }
-
-        Integer maxRetries;
-        try {
-            Object maxRetriesObject = properties.get( SERVICE_MANAGER_MAX_RETRIES ).toString();
-            maxRetries = Integer.parseInt( maxRetriesObject.toString() );
-        } catch ( NumberFormatException nfe ) {
-            maxRetries = 5;
-        }
-
         if ( em != null ) {
-
             try {
-                int retryCount = 0;
-                boolean appNotFound = true;
-
-                while ( appNotFound && retryCount <= maxRetries ) {
-
-                    application = em.getApplication();
-
-                    if ( application != null ) {
-                        appNotFound = false;
-                        applicationId = application.getUuid();
-                    } else {
-                        Thread.sleep( retryInterval );
-                        retryCount++;
-                    }
-                }
-
-                if ( application == null ) {
-                    Exception e = new RuntimeException( "application id {" + em.getApplicationId() + "} is returning null" );
-                    logger.error( "Failed to get application", e );
+                application = em.getApplication();
+                if(application == null){
+                    Exception e = new RuntimeException("application id {"+em.getApplicationId()+"} is returning null");
+                    logger.error("Failed to get application",e);
                     throw e;
                 }
-
-            } catch ( Exception e ) {
+                applicationId = application.getUuid();
+            }
+            catch ( Exception e ) {
                 logger.error( "ServiceManager init failure", e );
                 throw new RuntimeException( e );
             }
         }
-
         if ( properties != null ) {
             String packages = properties.getProperty( SERVICE_PACKAGE_PREFIXES );
             if ( !StringUtils.isEmpty( packages ) ) {
                 setServicePackagePrefixes( packages );
             }
         }
-
         return this;
     }
 


[33/50] [abbrv] usergrid git commit: Quick fix for Service tests: ensure lockManager gets initialized.

Posted by mr...@apache.org.
Quick fix for Service tests: ensure lockManager gets initialized.


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

Branch: refs/heads/master
Commit: 66bb5cd4911e10c308dae05d046033ba4d89acdc
Parents: 17809ac
Author: Dave Johnson <sn...@apache.org>
Authored: Fri Jun 3 12:08:31 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri Jun 3 12:08:31 2016 -0400

----------------------------------------------------------------------
 stack/services/src/test/resources/usergrid-test-context.xml | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/66bb5cd4/stack/services/src/test/resources/usergrid-test-context.xml
----------------------------------------------------------------------
diff --git a/stack/services/src/test/resources/usergrid-test-context.xml b/stack/services/src/test/resources/usergrid-test-context.xml
index ec1e2d2..8b31421 100644
--- a/stack/services/src/test/resources/usergrid-test-context.xml
+++ b/stack/services/src/test/resources/usergrid-test-context.xml
@@ -49,6 +49,7 @@
     <bean id="coreManager" class="org.apache.usergrid.persistence.CoreSchemaManager">
         <constructor-arg ref="setup"/>
         <constructor-arg ref="cassandraCluster"/>
+        <constructor-arg ref="injector"/>
     </bean>
 
     <bean id="localFileBinaryStore" class="org.apache.usergrid.services.assets.data.LocalFileBinaryStore">


[18/50] [abbrv] usergrid git commit: Revert all changes to CpEntityManager

Posted by mr...@apache.org.
Revert all changes to CpEntityManager


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

Branch: refs/heads/master
Commit: b0fba682d652195f56f6e49b09b488ca677780a6
Parents: e299024
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 25 10:28:05 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 25 10:28:05 2016 -0400

----------------------------------------------------------------------
 .../corepersistence/CpEntityManager.java        | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/b0fba682/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
index 13b5d1f..68f5d71 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
@@ -243,16 +243,16 @@ public class CpEntityManager implements EntityManager {
      * @param applicationId
      */
     public CpEntityManager( final CassandraService cass,
-                           final CounterUtils counterUtils,
-                           final AsyncEventService indexService,
-                           final ManagerCache managerCache,
-                           final MetricsFactory metricsFactory,
-                           final EntityManagerFig entityManagerFig,
-                           final GraphManagerFactory graphManagerFactory,
-                           final CollectionService collectionService,
-                           final ConnectionService connectionService,
-                           final IndexSchemaCacheFactory indexSchemaCacheFactory,
-                           final UUID applicationId ) {
+                            final CounterUtils counterUtils,
+                            final AsyncEventService indexService,
+                            final ManagerCache managerCache,
+                            final MetricsFactory metricsFactory,
+                            final EntityManagerFig entityManagerFig,
+                            final GraphManagerFactory graphManagerFactory,
+                            final CollectionService collectionService,
+                            final ConnectionService connectionService,
+                            final IndexSchemaCacheFactory indexSchemaCacheFactory,
+                            final UUID applicationId ) {
 
         this.entityManagerFig = entityManagerFig;
 


[09/50] [abbrv] usergrid git commit: Revert changes to initMgmtApp() and add null-pointer check.

Posted by mr...@apache.org.
Revert changes to initMgmtApp() and add null-pointer check.


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

Branch: refs/heads/master
Commit: 12743f3e221f80df7eab89fda08325e9775f7ae9
Parents: de6de66
Author: Dave Johnson <sn...@apache.org>
Authored: Fri May 20 14:03:53 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri May 20 14:03:53 2016 -0400

----------------------------------------------------------------------
 .../corepersistence/CpEntityManagerFactory.java | 49 +++++---------------
 1 file changed, 12 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/12743f3e/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
index e057210..924dd10 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
@@ -175,12 +175,12 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
 
                 if ( CpNamingUtils.MANAGEMENT_APPLICATION_ID.equals( appId ) ) {
 
-                    if ( app != null ) {
+                    if ( app != null && entityManager != null ) {
 
                         // we successfully fetched up the management app, cache it for a rainy day
                         managementAppEntityManager = entityManager;
 
-                    } else if ( managementAppEntityManager != null ) {
+                    } else if ( entityManager == null && managementAppEntityManager != null ) {
 
                         // failed to fetch management app, use cached one
                         entityManager = managementAppEntityManager;
@@ -214,47 +214,22 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
     }
 
 
-
     private void initMgmtAppInternal() {
 
-        Properties properties = cassandraService.getProperties();
-
-        Integer maxRetries;
-        try {
-            Object maxRetriesObject = properties.get( MANAGEMENT_APP_MAX_RETRIES ).toString();
-            maxRetries = Integer.parseInt( maxRetriesObject.toString() );
-        } catch ( NumberFormatException nfe ) {
-            maxRetries = 20;
-        }
-
         EntityManager em = getEntityManager(getManagementAppId());
+        indexService.queueInitializeApplicationIndex(CpNamingUtils.getApplicationScope(getManagementAppId()));
 
-        int retryCount = 0;
-
-        while ( managementApp != null && retryCount++ <= maxRetries ) {
-
-            try {
-                managementApp = em.getApplication();
-
-                if ( managementApp == null ) {
-
-                    logger.warn( "Management application not found, attempting creation" );
-
-                    Map mgmtAppProps = new HashMap<String, Object>();
-                    mgmtAppProps.put( PROPERTY_NAME, CassandraService.MANAGEMENT_APPLICATION );
-                    em.create( getManagementAppId(), TYPE_APPLICATION, mgmtAppProps );
-                    managementApp = em.getApplication();
-                }
-
-            } catch ( Throwable t ) {
-                logger.warn("Error getting or creating management application after " + retryCount + " retries", t);
+        try {
+            if ( em.getApplication() == null ) {
+                logger.info("Creating management application");
+                Map mgmtAppProps = new HashMap<String, Object>();
+                mgmtAppProps.put(PROPERTY_NAME, CassandraService.MANAGEMENT_APPLICATION);
+                em.create( getManagementAppId(), TYPE_APPLICATION, mgmtAppProps);
+                em.getApplication();
             }
-        }
-
-        indexService.queueInitializeApplicationIndex(CpNamingUtils.getApplicationScope(getManagementAppId()));
 
-        if ( managementApp == null ) {
-            throw new RuntimeException("FATAL ERROR: Failed to get or create management app");
+        } catch (Exception ex) {
+            throw new RuntimeException("Fatal error creating management application", ex);
         }
     }
 


[15/50] [abbrv] usergrid git commit: Merge branch 'release-2.1.1' into usergrid-1283-mgmt-app-init

Posted by mr...@apache.org.
Merge branch 'release-2.1.1' into usergrid-1283-mgmt-app-init

Conflicts:
	stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java


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

Branch: refs/heads/master
Commit: 6daba1d7d3dd9ce65644229af87f0440cee53117
Parents: 8ebc28d 0970e1d
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 25 10:08:06 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 25 10:08:06 2016 -0400

----------------------------------------------------------------------
 .../main/resources/usergrid-default.properties  |  5 --
 .../corepersistence/CpEntityManager.java        |  3 -
 .../corepersistence/CpEntityManagerFactory.java | 72 +++++++++-----------
 .../usergrid/services/ServiceManager.java       | 27 ++++----
 4 files changed, 46 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/6daba1d7/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/usergrid/blob/6daba1d7/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
----------------------------------------------------------------------
diff --cc stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
index 924dd10,91a936d..f92fc9e
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
@@@ -141,66 -142,12 +141,79 @@@ public class CpEntityManagerFactory imp
          this.connectionService = injector.getInstance( ConnectionService.class );
          this.indexSchemaCacheFactory = injector.getInstance( IndexSchemaCacheFactory.class );
  
-         // this line always needs to be last due to the temporary circular dependency until spring is removed
- 
-         this.applicationIdCache = injector.getInstance(ApplicationIdCacheFactory.class).getInstance(
-             getManagementEntityManager() );
- 
 -        //this line always needs to be last due to the temporary cicular dependency until spring is removed
 +        int entityManagerCacheSize = 100;
 +        try {
 +            entityManagerCacheSize = Integer.parseInt(
 +                cassandraService.getProperties().getProperty( ENTITY_MANAGER_CACHE_SIZE, "100" ));
 +        } catch ( Exception e ) {
 +            logger.error("Error parsing " + ENTITY_MANAGER_CACHE_SIZE + " using " + entityManagerCacheSize, e );
 +        }
  
 -        this.applicationIdCache = injector.getInstance(ApplicationIdCacheFactory.class).getInstance(
 -            getManagementEntityManager() );
 +        entityManagers = CacheBuilder.newBuilder()
 +            .maximumSize(entityManagerCacheSize)
 +            .build(new CacheLoader<UUID, EntityManager>() {
  
 +            public EntityManager load( UUID appId ) { // no checked exception
 +
-                 // get entity manager and ensure it can get its own application
- 
++                // create new entity manager and pre-fetch its application
 +                EntityManager entityManager = _getEntityManager( appId );
 +                Application app = null;
 +                Exception exception = null;
 +                try {
 +                    app = entityManager.getApplication();
 +                } catch (Exception e) {
 +                    exception = e;
 +                }
 +
 +                // the management app is a special case
 +
 +                if ( CpNamingUtils.MANAGEMENT_APPLICATION_ID.equals( appId ) ) {
 +
-                     if ( app != null && entityManager != null ) {
- 
++                    if ( app != null ) {
 +                        // we successfully fetched up the management app, cache it for a rainy day
 +                        managementAppEntityManager = entityManager;
 +
-                     } else if ( entityManager == null && managementAppEntityManager != null ) {
- 
++                    } else if ( managementAppEntityManager != null ) {
 +                        // failed to fetch management app, use cached one
 +                        entityManager = managementAppEntityManager;
- 
-                     } else {
- 
-                         // fetch failed and we have nothing cached, we must be bootstrapping
-                         logger.info("managementAppEntityManager is null, bootstrapping in progress");
 +                    }
++                }
  
-                 } else { // not the management app, so blow up if app cannot be fetched
- 
-                     if (app == null) {
-                         throw new RuntimeException( "Error getting application " + appId, exception );
-                     }
++                if (app == null) {
++                    throw new RuntimeException( "Error getting application " + appId, exception );
 +                }
 +
 +                return entityManager;
 +            }
 +        });
++
++        // hold up construction until we can access the management app
++        int maxRetries = 1000;
++        int retries = 0;
++        boolean managementAppFound = false;
++        Set<Class> seenBefore = new HashSet<>(100);
++        while ( !managementAppFound && retries++ < maxRetries ) {
++            try {
++                getEntityManager( getManagementAppId() ).getApplication();
++                managementAppFound = true;
++
++            } catch ( Throwable t ) {
++                if ( seenBefore.contains( t.getClass() )) { // don't log full stack trace if we've seen same before
++                    logger.error("Error {} getting management app on try {}", t.getClass().getSimpleName(), retries);
++                } else {
++                    logger.error("Error getting management app on try {}", t.getClass().getSimpleName(), t);
++                }
++            }
++        }
++
++        if ( !managementAppFound ) {
++            // exception here will prevent WAR from being deployed
++            throw new RuntimeException( "Unable to get management app after " + retries + " retries" );
++        }
++
++        // this line always needs to be last due to the temporary circular dependency until spring is removed
++        applicationIdCache = injector.getInstance(ApplicationIdCacheFactory.class)
++            .getInstance( getManagementEntityManager() );
      }
  
  
@@@ -255,7 -187,7 +252,6 @@@
      }
  
  
--
      @Override
      public EntityManager getEntityManager(UUID applicationId) {
          try {

http://git-wip-us.apache.org/repos/asf/usergrid/blob/6daba1d7/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
----------------------------------------------------------------------
diff --cc stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
index 993bf35,a9892f5..e5ef407
--- a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
@@@ -17,32 -17,32 +17,29 @@@
  package org.apache.usergrid.services;
  
  
--import java.lang.reflect.Modifier;
--import java.util.*;
--import java.util.concurrent.ExecutionException;
--import java.util.concurrent.TimeUnit;
--
--import org.slf4j.Logger;
--import org.slf4j.LoggerFactory;
--import org.springframework.context.ApplicationContext;
++import com.google.common.cache.CacheBuilder;
++import com.google.common.cache.CacheLoader;
++import com.google.common.cache.LoadingCache;
++import org.apache.commons.lang.StringUtils;
  import org.apache.usergrid.batch.service.SchedulerService;
  import org.apache.usergrid.locking.LockManager;
  import org.apache.usergrid.mq.QueueManager;
  import org.apache.usergrid.persistence.Entity;
  import org.apache.usergrid.persistence.EntityManager;
  import org.apache.usergrid.persistence.EntityRef;
--import org.apache.usergrid.persistence.cassandra.CassandraService;
  import org.apache.usergrid.persistence.entities.Application;
  import org.apache.usergrid.services.ServiceParameter.IdParameter;
  import org.apache.usergrid.services.applications.ApplicationsService;
  import org.apache.usergrid.services.exceptions.UndefinedServiceEntityTypeException;
  import org.apache.usergrid.utils.ListUtils;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++import org.springframework.context.ApplicationContext;
  
--import org.apache.commons.lang.StringUtils;
--
--import com.google.common.cache.CacheBuilder;
--import com.google.common.cache.CacheLoader;
--import com.google.common.cache.LoadingCache;
++import java.lang.reflect.Modifier;
++import java.util.*;
++import java.util.concurrent.ExecutionException;
++import java.util.concurrent.TimeUnit;
  
  import static org.apache.usergrid.persistence.SimpleEntityRef.ref;
  import static org.apache.usergrid.utils.InflectionUtils.pluralize;


[24/50] [abbrv] usergrid git commit: Merge branch 'release-2.1.1' into select-mappings-nested

Posted by mr...@apache.org.
Merge branch 'release-2.1.1' into select-mappings-nested


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

Branch: refs/heads/master
Commit: 151abf78f92cebd2ac8701d18b9754f65b88cfdc
Parents: e9e7c39 0970e1d
Author: Dave Johnson <sn...@apache.org>
Authored: Tue May 31 13:32:42 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Tue May 31 13:32:42 2016 -0400

----------------------------------------------------------------------
 .../main/resources/usergrid-default.properties  |  5 --
 .../applications/ApplicationResourceIT.java     |  5 +-
 .../usergrid/security/shiro/ShiroCache.java     | 44 +++++++++++++-
 .../usergrid/services/ServiceManager.java       | 61 +++-----------------
 4 files changed, 52 insertions(+), 63 deletions(-)
----------------------------------------------------------------------



[45/50] [abbrv] usergrid git commit: Merge commit 'refs/pull/537/head' of github.com:apache/usergrid into release-2.1.1

Posted by mr...@apache.org.
Merge commit 'refs/pull/537/head' of github.com:apache/usergrid into release-2.1.1


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

Branch: refs/heads/master
Commit: 4bf7761bec6076a5d1acb0bce71ad0ffcf016dae
Parents: 7af4f84 7ea48c2
Author: Michael Russo <mr...@apigee.com>
Authored: Tue Jun 14 18:32:25 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Tue Jun 14 18:32:25 2016 -0700

----------------------------------------------------------------------
 .../main/resources/usergrid-default.properties  |  4 +++
 .../rest/management/ManagementResource.java     |  4 +--
 .../shiro/filters/BasicAuthSecurityFilter.java  | 19 ++++++++++--
 .../management/AccountCreationProps.java        |  3 +-
 .../usergrid/management/ManagementService.java  |  6 +++-
 .../cassandra/AccountCreationPropsImpl.java     | 17 +++++++++--
 .../cassandra/ManagementServiceImpl.java        | 32 ++++++++++++++++----
 .../apache/usergrid/security/shiro/Realm.java   |  6 ----
 .../shiro/principals/AdminUserPrincipal.java    |  4 +--
 .../usergrid/management/OrganizationIT.java     |  2 +-
 .../cassandra/ManagementServiceIT.java          |  6 ++--
 11 files changed, 77 insertions(+), 26 deletions(-)
----------------------------------------------------------------------



[50/50] [abbrv] usergrid git commit: Merge branch 'release-2.1.1'

Posted by mr...@apache.org.
Merge branch 'release-2.1.1'


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

Branch: refs/heads/master
Commit: f2126086efb4a249728e074571c2f083f409ed26
Parents: 9250a81 29c287b
Author: Michael Russo <mr...@apigee.com>
Authored: Wed Jun 15 09:24:31 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Wed Jun 15 09:24:31 2016 -0700

----------------------------------------------------------------------
 deployment/pcf/LICENSE                          | 201 ++++++++
 deployment/pcf/README.md                        |  47 +-
 deployment/pcf/addBlobs.sh                      |  25 +
 deployment/pcf/apache-usergrid-tile-1.6.yml     | 510 +++++++++++++++++++
 deployment/pcf/config/blobs.yml                 |  19 +
 deployment/pcf/config/final.yml                 |  24 +
 deployment/pcf/content_migrations.yml           |  53 ++
 deployment/pcf/createRelease.sh                 |  24 +
 deployment/pcf/createTile.sh                    |  32 ++
 deployment/pcf/jobs/delete-all/monit            |  17 +
 deployment/pcf/jobs/delete-all/spec             |  44 ++
 .../jobs/delete-all/templates/delete-all.sh.erb | 131 +++++
 deployment/pcf/jobs/deploy-all/monit            |  18 +
 deployment/pcf/jobs/deploy-all/spec             | 145 ++++++
 .../jobs/deploy-all/templates/deploy-all.sh.erb | 384 ++++++++++++++
 .../pcf/jobs/docker-bosh-cassandra_docker/monit |  23 +
 .../pcf/jobs/docker-bosh-cassandra_docker/spec  |  26 +
 .../docker-bosh-cassandra_docker.sh.erb         |  69 +++
 .../jobs/docker-bosh-elasticsearch_docker/monit |  23 +
 .../jobs/docker-bosh-elasticsearch_docker/spec  |  26 +
 .../docker-bosh-elasticsearch_docker.sh.erb     |  69 +++
 .../pcf/packages/cassandra_docker/packaging     |  26 +
 deployment/pcf/packages/cassandra_docker/spec   |  26 +
 deployment/pcf/packages/cf_cli/packaging        |  26 +
 deployment/pcf/packages/cf_cli/spec             |  25 +
 deployment/pcf/packages/common/packaging        |  23 +
 deployment/pcf/packages/common/spec             |  25 +
 .../pcf/packages/elasticsearch_docker/packaging |  26 +
 .../pcf/packages/elasticsearch_docker/spec      |  26 +
 deployment/pcf/packages/usergrid_app/packaging  |  27 +
 deployment/pcf/packages/usergrid_app/spec       |  27 +
 deployment/pcf/run.sh                           |  25 +
 deployment/pcf/src/common/utils.sh              | 107 ++++
 deployment/pcf/src/templates/all_open.json      |   6 +
 deployment/pcf/src/usergrid_app/manifest.yml    |  22 +
 .../main/resources/usergrid-default.properties  |   7 +-
 .../corepersistence/CpEntityManager.java        |   2 +-
 .../corepersistence/CpEntityManagerFactory.java | 249 ++++++---
 .../corepersistence/EntityManagerFig.java       |   2 +-
 .../asyncevents/AsyncEventService.java          |   6 +-
 .../asyncevents/AsyncEventServiceImpl.java      |  45 +-
 .../asyncevents/EventBuilder.java               |   6 +-
 .../asyncevents/EventBuilderImpl.java           |  46 +-
 .../model/DeIndexOldVersionsEvent.java          |  12 +-
 .../corepersistence/index/IndexService.java     |  23 +-
 .../corepersistence/index/IndexServiceImpl.java |  86 ++--
 .../pipeline/cursor/CursorSerializerUtil.java   |   9 -
 .../pipeline/cursor/RequestCursor.java          |  29 +-
 .../read/search/CandidateEntityFilter.java      |  94 +++-
 .../apache/usergrid/locking/LockManager.java    |   5 +
 .../locking/cassandra/AstyanaxLockImpl.java     |   2 +-
 .../cassandra/AstyanaxLockManagerImpl.java      | 113 ++--
 .../locking/noop/NoOpLockManagerImpl.java       |   5 +
 .../persistence/entities/Notification.java      |  38 +-
 .../usergrid/persistence/CoreSchemaManager.java |   8 +-
 .../apache/usergrid/persistence/IndexIT.java    |  98 ++++
 .../test/resources/usergrid-test-context.xml    |   1 +
 .../collection/EntityCollectionManager.java     |  10 +-
 .../exception/CollectionRuntimeException.java   |  11 +
 .../impl/EntityCollectionManagerImpl.java       |  40 +-
 .../mvcc/stage/write/WriteUniqueVerify.java     |  13 +-
 .../serialization/SerializationFig.java         |   5 +
 .../serialization/impl/LogEntryIterator.java    | 128 +++++
 .../core/astyanax/CassandraCluster.java         |  24 +-
 .../persistence/core/astyanax/CassandraFig.java |  18 +-
 .../model/field/value/EntityObject.java         |  15 +-
 .../usergrid/persistence/index/EntityIndex.java |   5 +-
 .../usergrid/persistence/index/IndexFig.java    |   2 +-
 .../index/impl/EsEntityIndexImpl.java           |  64 +--
 .../persistence/index/impl/EntityIndexTest.java |  41 --
 .../rest/applications/users/UserResource.java   |   9 +
 .../rest/applications/users/UsersResource.java  |   9 +
 .../rest/management/ManagementResource.java     |   6 +-
 .../organizations/OrganizationsResource.java    |  18 +-
 .../rest/management/users/UserResource.java     |  25 +-
 .../rest/management/users/UsersResource.java    |  10 +-
 .../security/SecuredResourceFilterFactory.java  |  14 +-
 .../shiro/filters/BasicAuthSecurityFilter.java  |  19 +-
 .../applications/ApplicationResourceIT.java     |   5 +-
 .../usergrid/rest/applications/SecurityIT.java  |   1 -
 .../collection/CollectionsResourceIT.java       |  87 +++-
 .../collection/users/PermissionsResourceIT.java | 125 ++++-
 .../queries/SelectMappingsQueryTest.java        | 168 ++++++
 .../rest/management/ManagementResourceIT.java   |   2 +-
 .../resource/endpoints/CollectionEndpoint.java  |  24 +-
 .../test/resource/endpoints/NamedResource.java  |   8 +-
 .../test/resources/usergrid-test-context.xml    |   2 +-
 .../management/AccountCreationProps.java        |   3 +-
 .../usergrid/management/ManagementService.java  |   6 +-
 .../cassandra/AccountCreationPropsImpl.java     |  17 +-
 .../cassandra/ManagementServiceImpl.java        |  32 +-
 .../apache/usergrid/security/shiro/Realm.java   |   6 -
 .../usergrid/security/shiro/ShiroCache.java     |  70 ++-
 .../shiro/principals/AdminUserPrincipal.java    |   4 +-
 .../principals/ApplicationUserPrincipal.java    |  13 +-
 .../security/shiro/utils/LocalShiroCache.java   |   2 +-
 .../usergrid/services/ServiceManager.java       |   8 +
 .../services/ServiceManagerFactory.java         |  12 +
 .../ApplicationQueueManagerCache.java           |   2 +-
 .../impl/ApplicationQueueManagerImpl.java       |  52 +-
 .../usergrid/management/OrganizationIT.java     |   2 +-
 .../cassandra/ManagementServiceIT.java          |   6 +-
 .../AbstractServiceNotificationIT.java          |  26 +-
 .../test/resources/usergrid-test-context.xml    |   1 +
 .../java/org/apache/usergrid/tools/Cli.java     |   2 +-
 .../org/apache/usergrid/tools/EntityUpdate.java |   3 +-
 .../org/apache/usergrid/tools/ExportApp.java    |   2 +-
 .../java/org/apache/usergrid/tools/Import.java  |  10 +-
 .../org/apache/usergrid/tools/ToolBase.java     |  55 +-
 109 files changed, 3941 insertions(+), 514 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/f2126086/deployment/pcf/README.md
----------------------------------------------------------------------
diff --cc deployment/pcf/README.md
index 47bc408,0a002ed..330d4b8
--- a/deployment/pcf/README.md
+++ b/deployment/pcf/README.md
@@@ -1,2 -1,44 +1,45 @@@
- pcf
- ====
+ # Bosh Release + PCF Tile for Apache Usergrid
+ 
+ This is a bosh release for the apache usergrid. The scripts provided can help create the bosh release and tile for Apache Usergrid.
+ A version of the tile is available here: https://s3.amazonaws.com/usergrid-v2-public/usergrid_v2.pivotal
+ 
+ # Components Dependency
+ * Apache usergrid warfile
+   Grab the code from: https://github.com/apache/usergrid
+   Build the war file and save it as ROOT.war 
+ * CF CLI Linux binary
+   Download the CF CLI linux binary (64 bit) from: https://github.com/cloudfoundry/cli/releases
+ * ElasticSearch and Cassandra. 
+   Apache Usergrid requires ElasticSearch and Cassandra to search and manage data.
+   The Bosh release uses dockerized images to run both ElasticSearch and Cassandra.
+   Create docker images for both elastic search (v1.7) and cassandra (v2.1) and save them locally as tarballs
+ * Docker Bosh Release
+   To run docker images within Bosh, we need the docker bosh release.
+   Download v23 from: http://bosh.io/releases/github.com/cf-platform-eng/docker-boshrelease?all=1
+ 
+ # Building Bosh release
+ * Ensure following files are available at the root of the apache-usergrid-release directory
+ ```
+ cf-linux-amd64.tgz          # downloaded from CF cli github repo
+ ROOT.war                    # built from usergrid repo
+ cassandra-2.1.tgz           # Saved Cassandra 2.1 docker image 
+ elasticsearch-1.7.tgz       # Saved ElasticSearch 1.7 docker image 
+ docker-boshrelease-23.tgz   # Docker Bosh release v23
+ ```
+ * Run addBlobs.sh
+   Important to ensure the above blobs filenames match the entries inside the addBlobs.sh (& each of the packages/*/packaging file)
+ * Run ./createRelease.sh
+   Edit the version as required inside the script
+ # Building Tile
+ * Edit the apache-usergrid-tile-1.6.yml to refer to the correct version of release tarball (for docker bosh release and usergrid)
+ * Run ./createTile.sh
+   Edit the file names or versions as needed.
+   The docker-boshrelease-23.tgz file should be present in the directory to create a valid working tile
+   The script should create the usergrid.pivotal tile file.
+ 
+ # Notes
+ * Ensure the usergrid war file is named ROOT.war (or rename all references of ROOT.war with different file name) before running addBlobs.sh
+ * If newer versions are being used, please check and replace the associated versions inside packages/<package-name>/spec & packages/<packagge-name>/packaging file to deal with correct files.
+ * Update the tile metadata file if newer release versions are used
+ * Update the content_migrations.yml if new tile version is being published
++

http://git-wip-us.apache.org/repos/asf/usergrid/blob/f2126086/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java
----------------------------------------------------------------------


[02/50] [abbrv] usergrid git commit: Initial support for select mappings with entity object fields (i.e. nested fields)

Posted by mr...@apache.org.
Initial support for select mappings with entity object fields (i.e. nested fields)


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

Branch: refs/heads/master
Commit: 596e0fc5cef2eb1ae4aba40343bf27e73aee86d6
Parents: 7fdca3d
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 18 17:24:25 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 18 17:24:25 2016 -0400

----------------------------------------------------------------------
 .../read/search/CandidateEntityFilter.java      | 59 ++++++++++++++-
 .../apache/usergrid/persistence/IndexIT.java    | 80 ++++++++++++++++++++
 2 files changed, 135 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/596e0fc5/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
index d47e96c..261259b 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
@@ -27,7 +27,9 @@ import org.apache.usergrid.persistence.index.*;
 import org.apache.usergrid.persistence.index.impl.IndexProducer;
 import org.apache.usergrid.persistence.model.field.DistanceField;
 import org.apache.usergrid.persistence.model.field.DoubleField;
+import org.apache.usergrid.persistence.model.field.EntityObjectField;
 import org.apache.usergrid.persistence.model.field.Field;
+import org.apache.usergrid.persistence.model.field.value.EntityObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -123,12 +125,26 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate
                                 if (mappings.size() > 0) {
                                     Map<String,Field> fieldMap = new HashMap<String, Field>(mappings.size());
                                     rx.Observable.from(mappings)
-                                        .filter(mapping -> entity.getFieldMap().containsKey(mapping.getSourceFieldName()))
+
+                                        .filter(mapping -> {
+                                            if ( entity.getFieldMap().containsKey(mapping.getSourceFieldName())) {
+                                                return true;
+                                            }
+                                            String[] parts = mapping.getSourceFieldName().split("\\.");
+                                            return nestedFieldCheck( parts, entity.getFieldMap() );
+                                        })
+
                                         .doOnNext(mapping -> {
                                             Field field = entity.getField(mapping.getSourceFieldName());
-                                            field.setName(mapping.getTargetFieldName());
-                                            fieldMap.put(mapping.getTargetFieldName(),field);
-                                        }).toBlocking().last();
+                                            if ( field != null ) {
+                                                field.setName( mapping.getTargetFieldName() );
+                                                fieldMap.put( mapping.getTargetFieldName(), field );
+                                            } else {
+                                                String[] parts = mapping.getSourceFieldName().split("\\.");
+                                                nestedFieldSet( fieldMap, parts, entity.getFieldMap() );
+                                            }
+                                        }).toBlocking().lastOrDefault(null);
+
                                     entity.setFieldMap(fieldMap);
                                 }
                                 return entityFilterResult;
@@ -144,6 +160,41 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate
     }
 
 
+    private void nestedFieldSet( Map<String, Field> result, String[] parts, Map<String, Field> fieldMap) {
+        if ( parts.length > 0 ) {
+            if ( fieldMap.containsKey( parts[0] )) {
+                Field field = fieldMap.get( parts[0] );
+                if ( field instanceof EntityObjectField ) {
+                    EntityObjectField eof = (EntityObjectField)field;
+                    if ( result.get( parts[0] ) == null ) {
+                        result.put( parts[0], new EntityObjectField( parts[0], new EntityObject() ) );
+                    }
+                    nestedFieldSet(
+                        ((EntityObjectField)result.get( parts[0] )).getValue().getFieldMap(),
+                        Arrays.copyOfRange(parts, 1, parts.length),
+                        eof.getValue().getFieldMap());
+                } else {
+                    result.put( parts[0], field );
+                }
+            }
+        }
+    }
+
+
+    private boolean nestedFieldCheck( String[] parts, Map<String, Field> fieldMap) {
+        if ( parts.length > 0 ) {
+            if ( fieldMap.containsKey( parts[0] )) {
+                Field field = fieldMap.get( parts[0] );
+                if ( field instanceof EntityObjectField ) {
+                    EntityObjectField eof = (EntityObjectField)field;
+                    return nestedFieldCheck( Arrays.copyOfRange(parts, 1, parts.length), eof.getValue().getFieldMap());
+                } else {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 
 
     /**

http://git-wip-us.apache.org/repos/asf/usergrid/blob/596e0fc5/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
----------------------------------------------------------------------
diff --git a/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java b/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
index f4aa204..7e38f17 100644
--- a/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
+++ b/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
@@ -17,6 +17,7 @@
 package org.apache.usergrid.persistence;
 
 
+import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.UUID;
@@ -461,4 +462,83 @@ public class IndexIT extends AbstractCoreIT {
 
 
     }
+
+    @Test
+    public void testSelectMappings() throws Exception {
+
+        UUID applicationId = app.getId();
+
+        EntityManager em = setup.getEmf().getEntityManager(applicationId);
+
+        Map<String, Object> entity1 = new HashMap<String, Object>() {{
+            put("name","name_1");
+            put("status", "pickled");
+            put("data", new HashMap() {{
+                put("xfactor", 5.1);
+                put("rando", "bar");
+            }});
+        }};
+        em.create("names", entity1);
+
+        Map<String, Object> entity2 = new HashMap<String, Object>() {{
+            put("name","name_2");
+            put("status", "pickled");
+            put("data", new HashMap() {{
+                put("xfactor", 5.1);
+                put("rando", "bar");
+            }});
+        }};
+        em.create("names", entity2);
+
+        app.refreshIndex();
+
+        {
+            Query query = Query.fromQL("select status where status = 'pickled'");
+            Results r = em.searchCollection( em.getApplicationRef(), "names", query );
+            assertTrue(r.getEntities() != null && r.getEntities().size() == 2);
+            Entity first =  r.getEntities().get(0);
+            assertTrue(first.getDynamicProperties().size() == 2);
+        }
+
+        {
+            Query query = Query.fromQL( "select status, data.rando where data.rando = 'bar'" );
+            Results r = em.searchCollection( em.getApplicationRef(), "names", query );
+            assertTrue( r.getEntities() != null && r.getEntities().size() == 2 );
+
+            Entity first = r.getEntities().get( 0 );
+
+            assertNotNull( first.getProperty("status") );
+            assertEquals( first.getProperty("status"), "pickled" );
+
+            assertNotNull( first.getProperty("data") );
+            assertEquals( ((Map<String, Object>)first.getProperty("data")).get("rando"), "bar" );
+
+            assertTrue( first.getDynamicProperties().size() == 3 );
+        }
+
+        {
+            //  query for only one bogus field name should return empty entities
+            Query query = Query.fromQL( "select data.rando where status = 'pickled'" );
+            Results r = em.searchCollection( em.getApplicationRef(), "names", query );
+            assertTrue( r.getEntities() != null && r.getEntities().size() == 2 );
+
+            Entity first = r.getEntities().get( 0 );
+
+            assertNotNull( first.getProperty("data") );
+            assertEquals( ((Map<String, Object>)first.getProperty("data")).get("rando"), "bar" );
+
+            assertTrue( first.getDynamicProperties().size() == 2 );
+        }
+
+        {
+            //  query for only one bogus field name should return empty entities
+            Query query = Query.fromQL( "select data.bogusfieldname where status = 'pickled'" );
+            Results r = em.searchCollection( em.getApplicationRef(), "names", query );
+            assertTrue( r.getEntities() != null && r.getEntities().size() == 2 );
+            Entity first = r.getEntities().get( 0 );
+            assertTrue( first.getDynamicProperties().size() == 1 );
+        }
+
+    }
+
 }


[46/50] [abbrv] usergrid git commit: Fix logging statement.

Posted by mr...@apache.org.
Fix logging statement.


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

Branch: refs/heads/master
Commit: 8814a144b66054048be96a1c892fd750ee327327
Parents: 4bf7761
Author: Michael Russo <mr...@apigee.com>
Authored: Tue Jun 14 21:59:24 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Tue Jun 14 21:59:24 2016 -0700

----------------------------------------------------------------------
 .../corepersistence/asyncevents/AsyncEventServiceImpl.java  | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/8814a144/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
index 8d050fe..0bff887 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
@@ -355,9 +355,12 @@ public class AsyncEventServiceImpl implements AsyncEventService {
                     throw new Exception("Unknown EventType for message: "+ message.getStringBody().trim());
                 }
 
-                if( single.isEmpty() ){
-                    logger.warn("No index operation messages came back from event processing for msg {} ",
-                        message.getStringBody().trim());
+
+                if( !(event instanceof ElasticsearchIndexEvent)
+                    && !(event instanceof InitializeApplicationIndexEvent)
+                      && single.isEmpty() ){
+                        logger.warn("No index operation messages came back from event processing for msg: {} ",
+                            message.getStringBody().trim());
                 }
 
 


[41/50] [abbrv] usergrid git commit: Merge commit 'refs/pull/517/head' of github.com:apache/usergrid into release-2.1.1

Posted by mr...@apache.org.
Merge commit 'refs/pull/517/head' of github.com:apache/usergrid into release-2.1.1


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

Branch: refs/heads/master
Commit: 72c9df14a4185a9dafe55255b9d2cda73ad27882
Parents: 0eaea98 9edfda6
Author: Michael Russo <mr...@apigee.com>
Authored: Tue Jun 7 09:15:25 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Tue Jun 7 09:15:25 2016 -0700

----------------------------------------------------------------------
 .../persistence/entities/Notification.java      | 38 ++++++---
 .../collection/CollectionsResourceIT.java       | 87 ++++++++++++++++----
 .../resource/endpoints/CollectionEndpoint.java  | 24 +++---
 .../impl/ApplicationQueueManagerImpl.java       | 52 +++++++++---
 .../AbstractServiceNotificationIT.java          | 26 +++---
 5 files changed, 158 insertions(+), 69 deletions(-)
----------------------------------------------------------------------



[36/50] [abbrv] usergrid git commit: core schema manager needs injector now

Posted by mr...@apache.org.
core schema manager needs injector now


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

Branch: refs/heads/master
Commit: fcb347c763b1a9027e8261cb54671f6d92f61da3
Parents: b3e60c9
Author: Dave Johnson <sn...@apache.org>
Authored: Mon Jun 6 12:20:36 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Mon Jun 6 12:20:36 2016 -0400

----------------------------------------------------------------------
 stack/rest/src/test/resources/usergrid-test-context.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/fcb347c7/stack/rest/src/test/resources/usergrid-test-context.xml
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/resources/usergrid-test-context.xml b/stack/rest/src/test/resources/usergrid-test-context.xml
index a9fc5a5..76b9775 100644
--- a/stack/rest/src/test/resources/usergrid-test-context.xml
+++ b/stack/rest/src/test/resources/usergrid-test-context.xml
@@ -45,7 +45,6 @@
     </bean>
 
     <bean id="setup" class="org.apache.usergrid.corepersistence.CpSetup">
-
         <constructor-arg ref="entityManagerFactory"/>
         <constructor-arg ref="cassandraService"/>
         <constructor-arg ref="injector"/>
@@ -55,6 +54,7 @@
     <bean id="coreManager" class="org.apache.usergrid.persistence.CoreSchemaManager">
         <constructor-arg ref="setup"/>
         <constructor-arg ref="cassandraCluster"/>
+        <constructor-arg ref="injector"/>
     </bean>
 
 </beans>


[47/50] [abbrv] usergrid git commit: Add Pivotal Cloud Foundry source for creating Usergrid Tile ( CF deployment + bosh release )

Posted by mr...@apache.org.
http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/config/blobs.yml
----------------------------------------------------------------------
diff --git a/deployment/pcf/config/blobs.yml b/deployment/pcf/config/blobs.yml
new file mode 100644
index 0000000..b05a48d
--- /dev/null
+++ b/deployment/pcf/config/blobs.yml
@@ -0,0 +1,19 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+--- {}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/config/final.yml
----------------------------------------------------------------------
diff --git a/deployment/pcf/config/final.yml b/deployment/pcf/config/final.yml
new file mode 100644
index 0000000..784703c
--- /dev/null
+++ b/deployment/pcf/config/final.yml
@@ -0,0 +1,24 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+blobstore:
+  provider: local
+  options:
+    blobstore_path: /tmp/usergrid-blobs
+final_name: usergrid_blobstore

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/content_migrations.yml
----------------------------------------------------------------------
diff --git a/deployment/pcf/content_migrations.yml b/deployment/pcf/content_migrations.yml
new file mode 100644
index 0000000..80035ff
--- /dev/null
+++ b/deployment/pcf/content_migrations.yml
@@ -0,0 +1,53 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+product: apache-usergrid
+installation_version: '1.5'
+to_version: 0.1.1
+migrations:
+- from_version: 0.0.1
+  rules:
+  - type: update
+    selector: product_version
+    to: 0.1.1
+- from_version: 0.0.2
+  rules:
+  - type: update
+    selector: product_version
+    to: 0.1.1
+- from_version: 0.0.3
+  rules:
+  - type: update
+    selector: product_version
+    to: 0.1.1
+- from_version: 0.0.4
+  rules:
+  - type: update
+    selector: product_version
+    to: 0.1.1
+- from_version: 0.0.5
+  rules:
+  - type: update
+    selector: product_version
+    to: 0.1.1
+- from_version: 0.1.0
+  rules:
+  - type: update
+    selector: product_version
+    to: 0.1.1

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/createRelease.sh
----------------------------------------------------------------------
diff --git a/deployment/pcf/createRelease.sh b/deployment/pcf/createRelease.sh
new file mode 100755
index 0000000..e2c58bf
--- /dev/null
+++ b/deployment/pcf/createRelease.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+RELEASE_VERSION=2.1.0
+
+rm -rf dev_releases .dev_builds
+bosh create release --with-tarball --version $RELEASE_VERSION

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/createTile.sh
----------------------------------------------------------------------
diff --git a/deployment/pcf/createTile.sh b/deployment/pcf/createTile.sh
new file mode 100755
index 0000000..91db8f1
--- /dev/null
+++ b/deployment/pcf/createTile.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+TILE_METADATA_VERSION=1.6
+
+# Make sure docker-boshrelease-23.tgz tar ball is available
+
+mkdir -p product/metadata product/releases product/content_migrations # product/javascript-migrations
+cp dev_releases/apache*/apache*tgz product/releases
+cp docker-boshrelease-23.tgz product/releases
+cp apache-usergrid-tile-${TILE_METADATA_VERSION}.yml product/metadata/apache-usergrid.yml
+cp content_migrations.yml product/content_migrations
+cd product
+zip -r ../usergrid.pivotal *
+cd ..

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/delete-all/monit
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/delete-all/monit b/deployment/pcf/jobs/delete-all/monit
new file mode 100644
index 0000000..bba851e
--- /dev/null
+++ b/deployment/pcf/jobs/delete-all/monit
@@ -0,0 +1,17 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/delete-all/spec
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/delete-all/spec b/deployment/pcf/jobs/delete-all/spec
new file mode 100644
index 0000000..3165c6d
--- /dev/null
+++ b/deployment/pcf/jobs/delete-all/spec
@@ -0,0 +1,44 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: delete-all
+templates:
+  delete-all.sh.erb: bin/run
+packages:
+- cf_cli
+- elasticsearch_docker
+- cassandra_docker
+- usergrid_app
+properties:
+  domain:
+    description: 'CloudFoundry system domain'
+  app_domains:
+    description: 'CloudFoundry application domains'
+  org:
+    description: 'Org for the Application'
+    default: ''
+  space:
+    description: 'Space for the Application'
+    default: ''
+  ssl.skip_cert_verify:
+    description: 'Whether to verify SSL certs when making web requests'
+  cf.admin_user:
+    description: 'Username of the CF admin user'
+  cf.admin_password:
+    description: 'Password of the CF admin user'

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/delete-all/templates/delete-all.sh.erb
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/delete-all/templates/delete-all.sh.erb b/deployment/pcf/jobs/delete-all/templates/delete-all.sh.erb
new file mode 100644
index 0000000..9bd29ed
--- /dev/null
+++ b/deployment/pcf/jobs/delete-all/templates/delete-all.sh.erb
@@ -0,0 +1,131 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+export PATH="/var/vcap/packages/cf_cli/bin:$PATH"
+export CF=`which cf`
+
+function cf() {
+	echo cf "$@"
+	output=$($CF "$@" 2>&1)
+	result="$?"
+	if [ "$result" -ne "0" ]; then
+		echo "$output"
+		# No exit here - best effort continuation on failure for the delete script
+	fi
+}
+
+function is_true() {
+	equals_ignore_case "$1" "true"
+}
+
+function equals_ignore_case() {
+	echo "$1" | grep -i "^$2\$" >/dev/null
+}
+
+function import_opsmgr_variables() {
+	export SCHEME=https
+	export ADMIN_USER=<%= properties.cf.admin_user %>
+	export ADMIN_PASSWORD=<%= properties.cf.admin_password %>
+	export DOMAIN=<%= properties.domain %>
+	export APP_DOMAIN=<%= properties.app_domains[0] %>
+	export CF_ORG=<%= properties.org %>
+	export CF_SPACE=<%= properties.space %>
+	export CF_TARGET=$SCHEME://api.${DOMAIN}
+	export CF_SKIP_SSL=<%= properties.ssl.skip_cert_verify %>
+}
+
+function prepare_cf_cli {
+	export PATH="/var/vcap/packages/cf_cli/bin:$PATH"
+	export CF_HOME=`pwd`/home/cf
+	mkdir -p $CF_HOME
+}
+
+function authenticate() {
+	$CF --version
+	if is_true "$CF_SKIP_SSL"; then
+		cf api $CF_TARGET --skip-ssl-validation
+	else
+		cf api $CF_TARGET
+	fi
+	cf auth $ADMIN_USER $ADMIN_PASSWORD
+}
+
+function target_org() {
+	if [ -z "$CF_ORG" ]; then
+		CF_ORG=apache-usergrid-org
+	fi
+	cf target -o $CF_ORG >/dev/null
+}
+
+function target_space() {
+	if [ -z "$CF_SPACE" ]; then
+		CF_SPACE=apache-usergrid-space
+	fi
+	cf target -s $CF_SPACE >/dev/null
+}
+
+function delete_empty_space() {
+	output=`$CF apps | tail -1`
+	if [ "$output" == "No apps found" ]; then
+		cf delete-space -f $CF_SPACE
+	fi
+}
+
+function delete_empty_org() {
+	output=`$CF spaces | tail -1`
+	if [ "$output" == "No spaces found" ]; then
+		cf delete-org -f $CF_ORG
+	fi
+}
+
+function delete_all_versions() {
+	$CF apps | grep "$1-" | while read app rest; do
+		cf delete -f $app
+	done
+}
+
+function delete_service_broker() {
+    services=`$CF service-access | awk "/broker: $1/{flag=1;next}/broker: /{flag=0}flag" | egrep -v "access *orgs" | grep "."  | awk '{print $1}' | uniq`
+    for service in $services; do
+      cf purge-service-offering -f "$service"
+    done
+    cf delete-service-broker -f $1
+}
+
+import_opsmgr_variables
+prepare_cf_cli
+authenticate
+if target_org; then
+	if target_space; then
+
+		# Delete package usergrid_app
+		#
+		delete_all_versions usergrid_app
+
+		# Delete package cassandra_docker
+		#
+
+		# Delete package elasticsearch_docker
+		#
+
+		delete_empty_space
+	fi
+	delete_empty_org
+fi
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/deploy-all/monit
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/deploy-all/monit b/deployment/pcf/jobs/deploy-all/monit
new file mode 100644
index 0000000..1c19c35
--- /dev/null
+++ b/deployment/pcf/jobs/deploy-all/monit
@@ -0,0 +1,18 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/deploy-all/spec
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/deploy-all/spec b/deployment/pcf/jobs/deploy-all/spec
new file mode 100644
index 0000000..96bd3e7
--- /dev/null
+++ b/deployment/pcf/jobs/deploy-all/spec
@@ -0,0 +1,145 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: deploy-all
+templates:
+  deploy-all.sh.erb: bin/run
+packages:
+  - cf_cli
+  - elasticsearch_docker
+  - cassandra_docker
+  - usergrid_app
+properties:
+  domain:
+    description: 'CloudFoundry system domain'
+  app_domains:
+    description: 'CloudFoundry application domains'
+  org:
+    description: 'Org for the Application'
+    default: ''
+  space:
+    description: 'Space for the Application'
+    default: ''
+  ssl.skip_cert_verify:
+    description: 'Whether to verify SSL certs when making web requests'
+  cf.admin_user:
+    description: 'Username of the CF admin user'
+  cf.admin_password:
+    description: 'Password of the CF admin user'
+  org_quota:
+    description: 'Org Memory Quota for the Application'
+    default: 1024
+  apply_open_security_group:
+    description: 'Open security group for the app to access outside'
+    default: true
+  security.user:
+    description: 'Basic auth user'
+  security.password:
+    description: 'Basic auth password'
+
+  elasticsearch.client.type:
+    description: 'The NODE or TRANSPORT type of client for connecting to ES'
+    default: 'TRANSPORT'
+
+  elasticsearch.hosts:
+    description: 'test'
+
+  cassandra.hosts:
+    description: 'test'
+
+  usergrid_app.name:
+    description: 'Name of package'
+
+  usergrid.cluster_name:
+    description: 'test'
+    default: 'usergrid'
+
+  usergrid.tomcat_instances:
+    description: number of instances
+    default: 1
+
+  usergrid.sysadmin.approve.users:
+    description: 'test'
+    default: false
+
+  usergrid.sysadmin.approve.organizations:
+    description: 'test'
+    default: false
+
+  usergrid.sysadmin.login.name:
+    description: 'test'
+
+  usergrid.sysadmin.login.email:
+    description: 'test'
+    default: 'superuser@usergrid.com'
+
+  usergrid.sysadmin.login.password:
+    description: 'test'
+
+  usergrid.sysadmin.login.allowed:
+    description: 'true'
+    default: true
+
+  usergrid.setup_test_account:
+    description: 'test'
+    default: true
+
+  usergrid.test_account.app:
+    description: 'test'
+    default: test-app
+
+  usergrid.test_account.organization:
+    description: 'test'
+    default: test-organization
+
+  usergrid.test_account.admin_user.username:
+    description: 'test'
+    default: 'test'
+
+  usergrid.test_account.admin_user.name:
+    description: 'test'
+    default: 'Test User'
+
+  usergrid.test_account.admin_user.email:
+    description: 'test'
+    default: 'user@usergrid.com'
+
+  usergrid.test_account.admin_user.password:
+    description: 'test'
+    default: 'test'
+
+  mail.smtps.host:
+    description: 'test'
+    default: 'test'
+
+  mail.smtps.port:
+    description: 'test'
+    default: 'test'
+
+  mail.smtps.auth:
+    description: 'test'
+    default: false
+
+  mail.smtps.username:
+    description: 'test'
+    default: 'test'
+
+  mail.smtps.password:
+    description: 'test'
+    default: 'test'
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/deploy-all/templates/deploy-all.sh.erb
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/deploy-all/templates/deploy-all.sh.erb b/deployment/pcf/jobs/deploy-all/templates/deploy-all.sh.erb
new file mode 100644
index 0000000..b4208f3
--- /dev/null
+++ b/deployment/pcf/jobs/deploy-all/templates/deploy-all.sh.erb
@@ -0,0 +1,384 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+export PATH="/var/vcap/packages/cf_cli/bin:$PATH"
+export CF=`which cf`
+
+function cf() {
+	echo cf "$@"
+	output=$($CF "$@" 2>&1)
+	result="$?"
+	if [ "$result" -ne "0" ]; then
+		echo "$output"
+		exit $result
+	fi
+}
+
+function is_true() {
+	equals_ignore_case "$1" "true"
+}
+
+function equals_ignore_case() {
+	echo "$1" | grep -i "^$2\$" >/dev/null
+}
+
+function import_opsmgr_variables() {
+	export SCHEME=https
+	export ADMIN_USER=<%= properties.cf.admin_user %>
+	export ADMIN_PASSWORD=<%= properties.cf.admin_password %>
+	export DOMAIN=<%= properties.domain %>
+	export APP_DOMAIN=<%= properties.app_domains[0] %>
+	export CF_ORG=<%= properties.org %>
+	export CF_ORG_QUOTA=<%= properties.org_quota %>
+	export CF_SPACE=<%= properties.space %>
+	export CF_TARGET=$SCHEME://api.${DOMAIN}
+	export CF_SKIP_SSL=<%= properties.ssl.skip_cert_verify %>
+	export SECURITY_USER_NAME=<%= properties.security.user %>
+	export SECURITY_USER_PASSWORD=<%= properties.security.password %>
+	export APPLY_OPEN_SECURITY_GROUP=<%= properties.apply_open_security_group %>
+}
+
+function prepare_cf_cli {
+	export PATH="/var/vcap/packages/cf_cli/bin:$PATH"
+	export CF_HOME=`pwd`/home/cf
+	mkdir -p $CF_HOME
+}
+
+function authenticate() {
+	$CF --version
+	if is_true "$CF_SKIP_SSL"; then
+		cf api $CF_TARGET --skip-ssl-validation
+	else
+		cf api $CF_TARGET
+	fi
+	cf auth $ADMIN_USER $ADMIN_PASSWORD
+}
+
+function setup_target_org() {
+	if [ -z "$CF_ORG" ]; then
+		CF_ORG=apache-usergrid-org
+	fi
+	if ! $CF org $CF_ORG >/dev/null; then
+		cf create-org $CF_ORG
+	fi
+	cf target -o $CF_ORG
+}
+
+function setup_org_quota() {
+	if [ -n "$CF_ORG_QUOTA" ]; then
+		export CF_QUOTA=${CF_ORG}-quota
+		if ! $CF quota $CF_QUOTA >/dev/null; then
+			cf create-quota $CF_QUOTA -m ${CF_ORG_QUOTA}m -r 10 -s 10
+		fi
+		cf update-quota $CF_QUOTA -m ${CF_ORG_QUOTA}m -r 10 -s 10 --disallow-paid-service-plans
+		cf set-quota $CF_ORG $CF_QUOTA
+	fi
+}
+
+function setup_target_space() {
+	if [ -z "$CF_SPACE" ]; then
+		CF_SPACE=apache-usergrid-space
+	fi
+	if ! $CF space $CF_SPACE >/dev/null; then
+		cf create-space $CF_SPACE
+	fi
+	cf target -s $CF_SPACE
+}
+
+function add_target_org_to_admin() {
+
+  SYSTEM_ORG_GUID=`$CF org system --guid`
+  NEW_ORG_GUID=`$CF org $CF_ORG --guid`
+
+  ADMIN_GUID=`$CF curl /v2/organizations/$SYSTEM_ORG_GUID/users | grep -A 2 "username\": \"admin" | awk '{print $2}' | grep organizations | awk -F '/' '{print $4 }' `
+
+  $CF curl /v2/users/$ADMIN_GUID/organizations/$NEW_ORG_GUID -X PUT >/dev/null
+  $CF curl /v2/users/$ADMIN_GUID/managed_organizations/$NEW_ORG_GUID -X PUT >/dev/null
+}
+
+function setup_package_path() {
+	if [ -z "$PACKAGE_PATH" ]; then
+		export PACKAGE_PATH=/var/vcap/packages
+	fi
+}
+
+function apply_open_security_group() {
+	if ! is_true "$1"; then
+		return
+	fi
+	if ! $CF security-group all_open >/dev/null; then
+		cf create-security-group all_open $PACKAGE_PATH/templates/all_open.json
+	fi
+	cf bind-running-security-group all_open
+}
+
+function add_env_vars() {
+	cf set-env $1 UAA_HOST "$SCHEME://uaa.$DOMAIN"
+	cf set-env $1 CC_HOST "$CF_TARGET"
+	cf set-env $1 LOGIN_HOST "$SCHEME://login.$DOMAIN"
+	cf set-env $1 ROOT "\$HOME"
+	cf set-env $1 SCHEME "$SCHEME"
+	cf set-env $1 VERIFY_SSL "$CF_SKIP_SSL"
+
+	# Adding additional properties that most spring based apps or internal apps seem to be expecting
+	cf set-env $1 CF_ORG "$CF_ORG"
+	cf set-env $1 CF_SPACE "$CF_SPACE"
+	cf set-env $1 CF_TARGET "$CF_TARGET"
+	cf set-env $1 SECURITY_USER_NAME "$SECURITY_USER_NAME"
+	cf set-env $1 SECURITY_USER_PASSWORD "$SECURITY_USER_PASSWORD"
+  cf set-env $1 JBP_CONFIG_TOMCAT "{ tomcat: { version: 7.0.62 }}"
+
+	es_hosts_json="<%= properties.elasticsearch.hosts %>"
+	ca_hosts_json="<%= properties.cassandra.hosts%>"
+
+  export ES_HOSTS=`echo $es_hosts_json | sed -e 's#\[##;s#\]##'`
+  export CA_HOSTS=`echo $ca_hosts_json | sed -e 's#\[##;s#\]##'`
+
+	cf set-env $1 elasticsearch.hosts "$ES_HOSTS"
+	cf set-env $1 cassandra.url "$CA_HOSTS"
+
+  export elasticsearch_client_type="<%= properties.elasticsearch.client.type%>"
+  export cluster_name="<%= properties.usergrid.cluster_name%>"
+  export approve_users="<%= properties.usergrid.sysadmin.approve.users%>"
+  export approve_organizations="<%= properties.usergrid.sysadmin.approve.organizations%>"
+  export login_name="<%= properties.usergrid.sysadmin.login.name%>"
+  export login_email="<%= properties.usergrid.sysadmin.login.email%>"
+  export login_password="<%= properties.usergrid.sysadmin.login.password%>"
+  export login_allowed="<%= properties.usergrid.sysadmin.login.allowed%>"
+  export setup_test_account="<%= properties.usergrid.setup_test_account%>"
+  export test_account_app="<%= properties.usergrid.test_account.app%>"
+  export test_account_organization="<%= properties.usergrid.test_account.organization%>"
+  export test_account_admin_user_username="<%= properties.usergrid.test_account.admin_user.username%>"
+  export test_account_admin_user_name="<%= properties.usergrid.test_account.admin_user.name%>"
+  export test_account_admin_user_email="<%= properties.usergrid.test_account.admin_user.email%>"
+  export test_account_admin_user_password="<%= properties.usergrid.test_account.admin_user.password%>"
+  export smtps_host="<%= properties.mail.smtps.host%>"
+  export smtps_port="<%= properties.mail.smtps.port%>"
+  export smtps_auth="<%= properties.mail.smtps.auth%>"
+  export smtps_username="<%= properties.mail.smtps.username%>"
+  export smtps_password="<%= properties.mail.smtps.password%>"
+
+  cf set-env $1 JAVA_OPTS " -Dcassandra.url=$CA_HOSTS -Delasticsearch.hosts=$ES_HOSTS \
+    -Delasticsearch.client.type=$elasticsearch_client_type -Dusergrid.cluster_name=$cluster_name \
+    -Dmail.smtps.auth=$smtps_auth -Dmail.smtps.host=$smtps_host -Dmail.smtps.password=$smtps_password \
+    -Dmail.smtps.port=$smtps_port -Dmail.smtps.username=$smtps_username \
+    -Dusergrid.setup-test-account=$setup_test_account -Dusergrid.sysadmin.approve.organizations=$approve_organizations \
+    -Dusergrid.sysadmin.approve.users=approve_users -Dusergrid.sysadmin.login.allowed=true \
+    -Dusergrid.sysadmin.login.email=$login_email -Dusergrid.sysadmin.login.name=$login_name \
+    -Dusergrid.sysadmin.login.password=$login_password -Dusergrid.test-account.admin-user.email=baasadmins+pcf@apigee.com \
+    -Dusergrid.test-account.admin-user.name=\"$test_account_admin_user_name\" -Dusergrid.test-account.admin-user.password=test \
+    -Dusergrid.test-account.admin-user.username=$test_account_admin_user_username -Dusergrid.test-account.app=$test_account_app \
+    -Dusergrid.test-account.organization=$test_account_organization"
+
+	# Dynamic plans (if defined)
+
+	# Custom variables from tile.yml
+}
+
+function add_cf_credentials() {
+	cf set-env $1 CF_ADMIN_USER "$ADMIN_USER"
+	cf set-env $1 CF_ADMIN_USERNAME "$ADMIN_USER"
+	cf set-env $1 CF_ADMIN_PASSWORD "$ADMIN_PASSWORD"
+}
+
+function delete_older_versions() {
+	PKG_NAME="$1"
+	APP_NAME="$2"
+	$CF apps | grep "$PKG_NAME" | grep -v "$APP_NAME" | while read app rest; do
+		cf delete -f $app
+	done
+}
+
+function wait_till_running() {
+
+	for i in `seq 1  15`; do
+		CF_TRACE=true $CF app "$1" | grep RUNNING | grep "$1" >/dev/null
+		if [ "$?" -ne "0" ]; then
+			sleep 30
+			echo "cf app $1   # waiting for running state"
+		else
+			break
+		fi
+	done
+}
+
+function bootstrap_usergrid() {
+
+  echo "App is running, attempting Usergrid /system/database/setup"
+  echo " These calls do the following"
+  echo "1) Create the cassandra keyspace"
+  echo "2) Initialize the ElasticSearch indexes"
+  echo "3) Check the status"
+  echo ""
+
+  ug_db_setup=`curl -k -X PUT https://${APP_HOST}.${APP_DOMAIN}/system/database/setup -u ${login_name}:${login_password}`
+  echo "setup output: $ug_db_setup"
+
+  echo "App is running, Usergrid /system/database/setup finished, attempting Usergrid /system/database/bootstrap"
+  ug_db_bootstrap=`curl -k -X PUT https://${APP_HOST}.${APP_DOMAIN}/system/database/bootstrap -u ${login_name}:${login_password}`
+  echo "boostrap output: $ug_db_bootstrap"
+
+  ug_db_status=`curl -k https://${APP_HOST}.${APP_DOMAIN}/status -u ${login_name}:${login_password}`
+  echo "Status: $ug_db_status"
+  echo "Usergrid Bootstrap complete!!"
+  echo ""
+}
+
+function deploy_app() {
+	PKG_NAME="$1"
+	APP_NAME="$2"
+	APP_HOST="$3"
+	DOCKER_IMAGE="$4"
+	NEEDS_CF_CREDS="$5"
+	HEALTH_CHECK="$6"
+	AUTO_SERVICES="$7"
+
+  TOMCAT_INSTANCES="<%= properties.usergrid.tomcat_instances%>"
+
+	cf push ${APP_NAME} -n ${APP_HOST} -d ${APP_DOMAIN} \
+		${DOCKER_IMAGE} -f $PACKAGE_PATH/${PKG_NAME}/manifest.yml -b https://github.com/cloudfoundry/java-buildpack \
+		-i $TOMCAT_INSTANCES --no-start
+
+	add_env_vars ${APP_NAME}
+	if is_true "$NEEDS_CF_CREDS"; then
+		add_cf_credentials ${APP_NAME}
+	fi
+	if [ -n "$HEALTH_CHECK" ]; then
+		cf set-health-check ${APP_NAME} "$HEALTH_CHECK"
+	fi
+	provision_auto_services ${PKG_NAME} ${APP_NAME} ${AUTO_SERVICES}
+	cf start ${APP_NAME}
+	wait_till_running ${APP_NAME}
+	bootstrap_usergrid
+	delete_older_versions ${PKG_NAME} ${APP_NAME}
+}
+
+function provision_auto_services() {
+	PKG_NAME="$1"
+	APP_NAME="$2"
+	shift; shift
+	for service in $*; do
+		if equals_ignore_case "$service" "none"; then
+			continue
+		fi
+		$CF services | grep ${PKG_NAME}-$service >/dev/null
+		if [ "$?" -ne "0" ]; then
+			plan=`$CF marketplace | grep $service | awk '{ print $2 }' | sed 's/,//g'`
+			if [ -n "$plan" ]; then
+				cf create-service $service $plan ${PKG_NAME}-$service
+			else
+				echo "no service matching" $service "in marketplace"
+				exit 1
+			fi
+		fi
+		cf bind-service ${APP_NAME} ${PKG_NAME}-$service
+	done
+}
+
+function register_broker() {
+	BROKER_NAME="$1"
+	BROKER_USER="$2"
+	BROKER_PASS="$3"
+	BROKER_URL="$4"
+	GLOBAL_ACCESS="$5"
+	BROKER_SERVICES="$6"
+	$CF service-brokers | grep $BROKER_NAME >/dev/null
+	if [ "$?" -ne "0" ]; then
+		cf create-service-broker "$BROKER_NAME" "$BROKER_USER" "$BROKER_PASS" "$BROKER_URL"
+	else
+		cf update-service-broker "$BROKER_NAME" "$BROKER_USER" "$BROKER_PASS" "$BROKER_URL"
+	fi
+	if is_true "$GLOBAL_ACCESS"; then
+		publicize_services "$BROKER_NAME" "$BROKER_SERVICES"
+	fi
+}
+
+function publicize_services() {
+	BROKER_NAME="$1"
+	BROKER_SERVICES="$2"
+	services_url=`$CF curl /v2/services?q=label:$BROKER_NAME | grep service_plans_url | awk '{ print $2 }' | sed 's/[",]//g'`
+	if [ -n "$services_url" ]; then
+		services=`$CF curl $services_url | grep "\"url\"" | awk '{ print $2 }' | sed 's/[",]//g'`
+		for service in $services; do
+			cf curl $service -X PUT -d '{"public": true}'
+		done
+	elif [ -n "$BROKER_SERVICES" ] && [ "$BROKER_SERVICES" != "INTERNAL_SERVICE_NAME" ]; then
+		# Rely on the internal plan names if we cannot get it from the /v2/services on the broker
+		for service_name in `echo "$BROKER_SERVICES" | sed -e 's/,/ /g;s/;/ /g'`
+		do
+			cf enable-service-access $service_name
+		done
+	else
+		services=`$CF service-access | awk "/broker: ${BROKER_NAME}/{flag=1;next}/broker: /{flag=0}flag" | egrep -v "access *orgs" | grep "."  | awk '{print $1}' | uniq `
+		for service_name in $services; do
+			cf enable-service-access $service_name
+		done
+	fi
+}
+
+function push_buildpack() {
+	BUILDPACK_NAME="$1"
+	BUILDPACK_ORDER="$2"
+	BUILDPACK_FILE="$3"
+	$CF buildpacks | grep ${BUILDPACK_NAME} >/dev/null
+	if [ "$?" -eq "0" ]; then
+		cf update-buildpack $BUILDPACK_NAME -p $BUILDPACK_FILE --enable
+	else
+		cf create-buildpack $BUILDPACK_NAME $BUILDPACK_FILE $BUILDPACK_ORDER --enable
+	fi
+}
+
+import_opsmgr_variables
+prepare_cf_cli
+authenticate
+setup_target_org
+setup_org_quota
+setup_target_space
+add_target_org_to_admin
+setup_package_path
+apply_open_security_group "$APPLY_OPEN_SECURITY_GROUP"
+
+# Deploy package elasticsearch_docker
+#
+
+
+
+
+# Deploy package cassandra_docker
+#
+
+
+
+
+# Deploy package usergrid_app
+#
+
+export PKG_NAME=usergrid_app
+export APP_NAME=usergrid_app-0.1.0
+export APP_HOST=usergrid_app
+export DOCKER_IMAGE=""
+export NEEDS_CF_CREDS=""
+export HEALTH_CHECK=""
+export AUTO_SERVICES=""
+export AUTO_SERVICES="${AUTO_SERVICES} <%= properties.usergrid_app.persistence_store_type %>"
+deploy_app "$PKG_NAME" "$APP_NAME" "$APP_HOST" "$DOCKER_IMAGE" "$NEEDS_CF_CREDS" "$HEALTH_CHECK" "$AUTO_SERVICES"
+
+
+

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/docker-bosh-cassandra_docker/monit
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/docker-bosh-cassandra_docker/monit b/deployment/pcf/jobs/docker-bosh-cassandra_docker/monit
new file mode 100644
index 0000000..39b40e3
--- /dev/null
+++ b/deployment/pcf/jobs/docker-bosh-cassandra_docker/monit
@@ -0,0 +1,23 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+check process docker-bosh-cassandra_docker
+  with pidfile /var/vcap/sys/run/docker-bosh-cassandra_docker/docker-bosh-cassandra_docker.pid
+  start program "/var/vcap/jobs/docker-bosh-cassandra_docker/bin/docker-bosh-cassandra_docker_ctl start"
+  stop program "/var/vcap/jobs/docker-bosh-cassandra_docker/bin/docker-bosh-cassandra_docker_ctl stop"
+  group vcap

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/docker-bosh-cassandra_docker/spec
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/docker-bosh-cassandra_docker/spec b/deployment/pcf/jobs/docker-bosh-cassandra_docker/spec
new file mode 100644
index 0000000..ed998e7
--- /dev/null
+++ b/deployment/pcf/jobs/docker-bosh-cassandra_docker/spec
@@ -0,0 +1,26 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: docker-bosh-cassandra_docker
+templates:
+  docker-bosh-cassandra_docker.sh.erb: bin/docker-bosh-cassandra_docker_ctl
+packages:
+- cassandra_docker
+- common
+properties: {}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/docker-bosh-cassandra_docker/templates/docker-bosh-cassandra_docker.sh.erb
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/docker-bosh-cassandra_docker/templates/docker-bosh-cassandra_docker.sh.erb b/deployment/pcf/jobs/docker-bosh-cassandra_docker/templates/docker-bosh-cassandra_docker.sh.erb
new file mode 100644
index 0000000..5669dda
--- /dev/null
+++ b/deployment/pcf/jobs/docker-bosh-cassandra_docker/templates/docker-bosh-cassandra_docker.sh.erb
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+set -e # exit immediately if a simple command exits with a non-zero status
+set -u # report the usage of uninitialized variables
+
+# Setup env vars and folders
+RUN_DIR=/var/vcap/sys/run/docker-bosh-cassandra_docker
+LOG_DIR=/var/vcap/sys/log/docker-bosh-cassandra_docker
+PACKAGES_DIR=/var/vcap/packages/cassandra_docker
+
+PIDFILE=$RUN_DIR/docker-bosh-cassandra_docker.pid
+
+source /var/vcap/packages/common/utils.sh
+
+case $1 in
+
+  start)
+    pid_guard $PIDFILE docker-bosh-cassandra_docker
+
+    mkdir -p $RUN_DIR
+    mkdir -p $LOG_DIR
+
+    chown vcap:vcap $RUN_DIR
+    chown -R vcap:vcap $LOG_DIR
+
+    echo $$ > $PIDFILE
+    chown vcap:vcap $PIDFILE
+
+    for image in $PACKAGES_DIR/*.tgz; do
+      /var/vcap/packages/docker/bin/docker \
+        --host unix:///var/vcap/sys/run/docker/docker.sock \
+        load -i $image \
+        >>$LOG_DIR/docker-bosh-cassandra_docker.stdout.log \
+        2>>$LOG_DIR/docker-bosh-cassandra_docker.stderr.log
+    done
+
+    # do nothing forever
+    exec tail -f /dev/null
+    ;;
+
+  stop)
+    kill_and_wait $PIDFILE
+
+    ;;
+  *)
+    echo "Usage: docker-bosh-cassandra_docker_ctl {start|stop}"
+
+    ;;
+
+esac
+exit 0
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/monit
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/monit b/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/monit
new file mode 100644
index 0000000..1846260
--- /dev/null
+++ b/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/monit
@@ -0,0 +1,23 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+check process docker-bosh-elasticsearch_docker
+  with pidfile /var/vcap/sys/run/docker-bosh-elasticsearch_docker/docker-bosh-elasticsearch_docker.pid
+  start program "/var/vcap/jobs/docker-bosh-elasticsearch_docker/bin/docker-bosh-elasticsearch_docker_ctl start"
+  stop program "/var/vcap/jobs/docker-bosh-elasticsearch_docker/bin/docker-bosh-elasticsearch_docker_ctl stop"
+  group vcap

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/spec
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/spec b/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/spec
new file mode 100644
index 0000000..7f66165
--- /dev/null
+++ b/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/spec
@@ -0,0 +1,26 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: docker-bosh-elasticsearch_docker
+templates:
+  docker-bosh-elasticsearch_docker.sh.erb: bin/docker-bosh-elasticsearch_docker_ctl
+packages:
+- elasticsearch_docker
+- common
+properties: {}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/templates/docker-bosh-elasticsearch_docker.sh.erb
----------------------------------------------------------------------
diff --git a/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/templates/docker-bosh-elasticsearch_docker.sh.erb b/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/templates/docker-bosh-elasticsearch_docker.sh.erb
new file mode 100644
index 0000000..2f3bab7
--- /dev/null
+++ b/deployment/pcf/jobs/docker-bosh-elasticsearch_docker/templates/docker-bosh-elasticsearch_docker.sh.erb
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+set -e # exit immediately if a simple command exits with a non-zero status
+set -u # report the usage of uninitialized variables
+
+# Setup env vars and folders
+RUN_DIR=/var/vcap/sys/run/docker-bosh-elasticsearch_docker
+LOG_DIR=/var/vcap/sys/log/docker-bosh-elasticsearch_docker
+PACKAGES_DIR=/var/vcap/packages/elasticsearch_docker
+
+PIDFILE=$RUN_DIR/docker-bosh-elasticsearch_docker.pid
+
+source /var/vcap/packages/common/utils.sh
+
+case $1 in
+
+  start)
+    pid_guard $PIDFILE docker-bosh-elasticsearch_docker
+
+    mkdir -p $RUN_DIR
+    mkdir -p $LOG_DIR
+
+    chown vcap:vcap $RUN_DIR
+    chown -R vcap:vcap $LOG_DIR
+
+    echo $$ > $PIDFILE
+    chown vcap:vcap $PIDFILE
+
+    for image in $PACKAGES_DIR/*.tgz; do
+      /var/vcap/packages/docker/bin/docker \
+        --host unix:///var/vcap/sys/run/docker/docker.sock \
+        load -i $image \
+        >>$LOG_DIR/docker-bosh-elasticsearch_docker.stdout.log \
+        2>>$LOG_DIR/docker-bosh-elasticsearch_docker.stderr.log
+    done
+
+    # do nothing forever
+    exec tail -f /dev/null
+    ;;
+
+  stop)
+    kill_and_wait $PIDFILE
+
+    ;;
+  *)
+    echo "Usage: docker-bosh-elasticsearch_docker_ctl {start|stop}"
+
+    ;;
+
+esac
+exit 0
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/cassandra_docker/packaging
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/cassandra_docker/packaging b/deployment/pcf/packages/cassandra_docker/packaging
new file mode 100644
index 0000000..2b1f9d5
--- /dev/null
+++ b/deployment/pcf/packages/cassandra_docker/packaging
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+# abort script on any command that exit with a non zero value
+set -e
+
+cp -r templates ${BOSH_INSTALL_TARGET}
+
+cp cassandra_docker/cassandra-2.1.tgz ${BOSH_INSTALL_TARGET}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/cassandra_docker/spec
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/cassandra_docker/spec b/deployment/pcf/packages/cassandra_docker/spec
new file mode 100644
index 0000000..17cc214
--- /dev/null
+++ b/deployment/pcf/packages/cassandra_docker/spec
@@ -0,0 +1,26 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: cassandra_docker
+
+dependencies: []
+
+files:
+- templates/all_open.json
+- cassandra_docker/cassandra-2.1.tgz

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/cf_cli/packaging
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/cf_cli/packaging b/deployment/pcf/packages/cf_cli/packaging
new file mode 100644
index 0000000..b2c38ba
--- /dev/null
+++ b/deployment/pcf/packages/cf_cli/packaging
@@ -0,0 +1,26 @@
+#! /bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+set -e
+
+mkdir -p ${BOSH_INSTALL_TARGET}/bin
+cd cf_cli
+tar zxvf cf-linux-amd64.tgz
+cp cf ${BOSH_INSTALL_TARGET}/bin/
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/cf_cli/spec
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/cf_cli/spec b/deployment/pcf/packages/cf_cli/spec
new file mode 100644
index 0000000..f9bc92b
--- /dev/null
+++ b/deployment/pcf/packages/cf_cli/spec
@@ -0,0 +1,25 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: cf_cli
+
+dependencies: []
+
+files:
+- cf_cli/cf-linux-amd64.tgz

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/common/packaging
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/common/packaging b/deployment/pcf/packages/common/packaging
new file mode 100644
index 0000000..7ca503a
--- /dev/null
+++ b/deployment/pcf/packages/common/packaging
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+set -e -x
+
+cp -a common/* ${BOSH_INSTALL_TARGET}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/common/spec
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/common/spec b/deployment/pcf/packages/common/spec
new file mode 100644
index 0000000..ad325c9
--- /dev/null
+++ b/deployment/pcf/packages/common/spec
@@ -0,0 +1,25 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: common
+
+dependencies: []
+
+files:
+- common/*

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/elasticsearch_docker/packaging
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/elasticsearch_docker/packaging b/deployment/pcf/packages/elasticsearch_docker/packaging
new file mode 100644
index 0000000..a1306d1
--- /dev/null
+++ b/deployment/pcf/packages/elasticsearch_docker/packaging
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+# abort script on any command that exit with a non zero value
+set -e
+
+cp -r templates ${BOSH_INSTALL_TARGET}
+
+cp elasticsearch_docker/elasticsearch-1.7.tgz ${BOSH_INSTALL_TARGET}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/elasticsearch_docker/spec
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/elasticsearch_docker/spec b/deployment/pcf/packages/elasticsearch_docker/spec
new file mode 100644
index 0000000..4a553ab
--- /dev/null
+++ b/deployment/pcf/packages/elasticsearch_docker/spec
@@ -0,0 +1,26 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: elasticsearch_docker
+
+dependencies: []
+
+files:
+- templates/all_open.json
+- elasticsearch_docker/elasticsearch-1.7.tgz

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/usergrid_app/packaging
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/usergrid_app/packaging b/deployment/pcf/packages/usergrid_app/packaging
new file mode 100644
index 0000000..586922b
--- /dev/null
+++ b/deployment/pcf/packages/usergrid_app/packaging
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+# abort script on any command that exit with a non zero value
+set -e
+
+cp -r templates ${BOSH_INSTALL_TARGET}
+
+cp usergrid_app/ROOT.war ${BOSH_INSTALL_TARGET}
+cp usergrid_app/manifest.yml ${BOSH_INSTALL_TARGET}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/packages/usergrid_app/spec
----------------------------------------------------------------------
diff --git a/deployment/pcf/packages/usergrid_app/spec b/deployment/pcf/packages/usergrid_app/spec
new file mode 100644
index 0000000..176821a
--- /dev/null
+++ b/deployment/pcf/packages/usergrid_app/spec
@@ -0,0 +1,27 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+name: usergrid_app
+
+dependencies: []
+
+files:
+- templates/all_open.json
+- usergrid_app/manifest.yml
+- usergrid_app/ROOT.war 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/run.sh
----------------------------------------------------------------------
diff --git a/deployment/pcf/run.sh b/deployment/pcf/run.sh
new file mode 100755
index 0000000..a4eb7c1
--- /dev/null
+++ b/deployment/pcf/run.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+export RELEASE_VERSION=2.1.0
+export TILE_METADATA_VERSION=1.6
+
+./createRelease.sh
+./createTile.sh

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/src/common/utils.sh
----------------------------------------------------------------------
diff --git a/deployment/pcf/src/common/utils.sh b/deployment/pcf/src/common/utils.sh
new file mode 100644
index 0000000..6325e7b
--- /dev/null
+++ b/deployment/pcf/src/common/utils.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+mkdir -p /var/vcap/sys/log
+
+exec > >(tee -a >(logger -p user.info -t vcap.$(basename $0).stdout) | awk -W interactive '{lineWithDate="echo [`date +\"%Y-%m-%d %H:%M:%S%z\"`] \"" $0 "\""; system(lineWithDate)  }' >>/var/vcap/sys/log/$(basename $0).log)
+exec 2> >(tee -a >(logger -p user.error -t vcap.$(basename $0).stderr) | awk -W interactive '{lineWithDate="echo [`date +\"%Y-%m-%d %H:%M:%S%z\"`] \"" $0 "\""; system(lineWithDate)  }' >>/var/vcap/sys/log/$(basename $0).err.log)
+
+pid_guard() {
+  echo "------------ STARTING `basename $0` at `date` --------------" | tee /dev/stderr
+  pidfile=$1
+  name=$2
+
+  if [ -f "$pidfile" ]; then
+    pid=$(head -1 "$pidfile")
+
+    if [ -n "$pid" ] && [ -e /proc/$pid ]; then
+      echo "$name is already running, please stop it first"
+      exit 1
+    fi
+
+    echo "Removing stale pidfile..."
+    rm $pidfile
+  fi
+}
+
+wait_pidfile() {
+  pidfile=$1
+  try_kill=$2
+  timeout=${3:-0}
+  force=${4:-0}
+  countdown=$(( $timeout * 10 ))
+
+  if [ -f "$pidfile" ]; then
+    pid=$(head -1 "$pidfile")
+
+    if [ -z "$pid" ]; then
+      echo "Unable to get pid from $pidfile"
+      exit 1
+    fi
+
+    if [ -e /proc/$pid ]; then
+      if [ "$try_kill" = "1" ]; then
+        echo "Killing $pidfile: $pid "
+        kill $pid
+      fi
+      while [ -e /proc/$pid ]; do
+        sleep 0.1
+        [ "$countdown" != '0' -a $(( $countdown % 10 )) = '0' ] && echo -n .
+        if [ $timeout -gt 0 ]; then
+          if [ $countdown -eq 0 ]; then
+            if [ "$force" = "1" ]; then
+              echo -ne "\nKill timed out, using kill -9 on $pid... "
+              kill -9 $pid
+              sleep 0.5
+            fi
+            break
+          else
+            countdown=$(( $countdown - 1 ))
+          fi
+        fi
+      done
+      if [ -e /proc/$pid ]; then
+        echo "Timed Out"
+      else
+        echo "Stopped"
+      fi
+    else
+      echo "Process $pid is not running"
+    fi
+
+    rm -f $pidfile
+  else
+    echo "Pidfile $pidfile doesn't exist"
+  fi
+}
+
+kill_and_wait() {
+  pidfile=$1
+  # Monit default timeout for start/stop is 30s
+  # Append 'with timeout {n} seconds' to monit start/stop program configs
+  timeout=${2:-25}
+  force=${3:-1}
+
+  wait_pidfile $pidfile 1 $timeout $force
+}
+
+running_in_container() {
+  grep -q '/instance' /proc/self/cgroup
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/src/templates/all_open.json
----------------------------------------------------------------------
diff --git a/deployment/pcf/src/templates/all_open.json b/deployment/pcf/src/templates/all_open.json
new file mode 100644
index 0000000..ef60dec
--- /dev/null
+++ b/deployment/pcf/src/templates/all_open.json
@@ -0,0 +1,6 @@
+[
+  {
+    "destination": "0.0.0.0-255.255.255.255",
+    "protocol": "all"
+  }
+]
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/src/usergrid_app/manifest.yml
----------------------------------------------------------------------
diff --git a/deployment/pcf/src/usergrid_app/manifest.yml b/deployment/pcf/src/usergrid_app/manifest.yml
new file mode 100644
index 0000000..0fe9295
--- /dev/null
+++ b/deployment/pcf/src/usergrid_app/manifest.yml
@@ -0,0 +1,22 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+---
+path: ROOT.war
+timeout: 180
+memory: 1024M


[42/50] [abbrv] usergrid git commit: Additional enhancements to cursor validation and error messages.

Posted by mr...@apache.org.
Additional enhancements to cursor validation and error messages.


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

Branch: refs/heads/master
Commit: 3df07791c394de2e7ec7e1f9559e1490f63af630
Parents: 72c9df1
Author: Michael Russo <mr...@apigee.com>
Authored: Tue Jun 7 09:32:15 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Tue Jun 7 09:32:15 2016 -0700

----------------------------------------------------------------------
 .../pipeline/cursor/CursorSerializerUtil.java   |  9 ---------
 .../pipeline/cursor/RequestCursor.java          | 21 ++++++++++++++++----
 2 files changed, 17 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/3df07791/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/CursorSerializerUtil.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/CursorSerializerUtil.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/CursorSerializerUtil.java
index 7acdd00..5728433 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/CursorSerializerUtil.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/CursorSerializerUtil.java
@@ -40,12 +40,6 @@ public class CursorSerializerUtil {
 
     private static final ObjectMapper MAPPER = new ObjectMapper( SMILE_FACTORY );
 
-    /**
-     * Aritrary number, just meant to keep us from having a DOS issue
-     */
-    private static final int MAX_SIZE = 1024;
-
-
     public static ObjectMapper getMapper() {
         return MAPPER;
     }
@@ -75,9 +69,6 @@ public class CursorSerializerUtil {
      */
     public static JsonNode fromString( final String base64EncodedJson ) {
 
-        Preconditions.checkArgument( base64EncodedJson.length() <= MAX_SIZE,
-            "Your cursor must be less than " + MAX_SIZE + " chars in length" );
-
         final byte[] data = Base64.getUrlDecoder().decode( base64EncodedJson );
 
         JsonNode jsonNode;

http://git-wip-us.apache.org/repos/asf/usergrid/blob/3df07791/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java
index acd6e25..0209794 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java
@@ -35,6 +35,10 @@ import java.util.Map;
  */
 public class RequestCursor {
 
+    /**
+     * Arbitrary number, just meant to keep us from having a DOS issue
+     */
+    private static final int MAX_SIZE = 1024;
 
     private static final int MAX_CURSOR_COUNT = 100;
 
@@ -74,9 +78,15 @@ public class RequestCursor {
      * Deserialize from the cursor as json nodes
      */
     private Map<Integer, JsonNode> fromCursor( final String cursor ) throws CursorParseException {
-        if(cursor.isEmpty()){
-            throw new IllegalArgumentException("cursor cannot be empty");
-        }
+
+
+        Preconditions.checkArgument( cursor != null, "Cursor cannot be null");
+
+        Preconditions.checkArgument( cursor.length() <= MAX_SIZE,
+            "Your cursor must be less than " + MAX_SIZE + " chars in length" );
+
+        Preconditions.checkArgument( !cursor.isEmpty(), "Cursor cannot have an empty value");
+
 
         try {
             JsonNode jsonNode = CursorSerializerUtil.fromString( cursor );
@@ -95,8 +105,11 @@ public class RequestCursor {
 
             return cursors;
         }
+        catch ( IllegalArgumentException ie ){
+            throw new IllegalArgumentException("Provided cursor has an invalid format and cannot be parsed.");
+        }
         catch ( Exception e ) {
-            throw new CursorParseException( "Unable to serialize cursor", e );
+            throw new CursorParseException( "Unable to deserialize cursor", e );
         }
     }
 }


[12/50] [abbrv] usergrid git commit: Merge branch 'release-2.1.1' into usegrid-1283-mgmt-app-init

Posted by mr...@apache.org.
Merge branch 'release-2.1.1' into usegrid-1283-mgmt-app-init


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

Branch: refs/heads/master
Commit: 8ebc28dfd8e0d1abe4edec8a3941175238400ea4
Parents: 12743f3 aae8fdf
Author: Dave Johnson <sn...@apache.org>
Authored: Tue May 24 10:01:25 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Tue May 24 10:01:25 2016 -0400

----------------------------------------------------------------------
 .../applications/ApplicationResourceIT.java     |  5 +--
 .../usergrid/security/shiro/ShiroCache.java     | 44 +++++++++++++++++++-
 2 files changed, 44 insertions(+), 5 deletions(-)
----------------------------------------------------------------------



[22/50] [abbrv] usergrid git commit: Made max-retries and intervals configurable for both lock manager and entity manager factory, also better error logging.

Posted by mr...@apache.org.
Made max-retries and intervals configurable for both lock manager and entity manager factory, also better error logging.


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

Branch: refs/heads/master
Commit: 61a35a041598af0e336199343ed6a489454980f6
Parents: fcd00e8
Author: Dave Johnson <sn...@apache.org>
Authored: Thu May 26 11:10:33 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Thu May 26 11:10:33 2016 -0400

----------------------------------------------------------------------
 .../corepersistence/CpEntityManagerFactory.java | 83 ++++++++++++++++----
 .../cassandra/AstyanaxLockManagerImpl.java      | 17 +++-
 .../exception/CollectionRuntimeException.java   | 11 +++
 3 files changed, 93 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/61a35a04/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
index b6fbc2a..ee28765 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
@@ -20,11 +20,10 @@ import com.google.common.base.Optional;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
+import com.google.common.util.concurrent.UncheckedExecutionException;
 import com.google.inject.Injector;
 import com.google.inject.Key;
 import com.google.inject.TypeLiteral;
-import com.netflix.astyanax.connectionpool.exceptions.BadRequestException;
-import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.commons.lang.StringUtils;
 import org.apache.usergrid.corepersistence.asyncevents.AsyncEventService;
 import org.apache.usergrid.corepersistence.index.IndexSchemaCacheFactory;
@@ -39,6 +38,7 @@ import org.apache.usergrid.persistence.cassandra.CassandraService;
 import org.apache.usergrid.persistence.cassandra.CounterUtils;
 import org.apache.usergrid.persistence.cassandra.Setup;
 import org.apache.usergrid.persistence.collection.EntityCollectionManager;
+import org.apache.usergrid.persistence.collection.exception.CollectionRuntimeException;
 import org.apache.usergrid.persistence.collection.serialization.impl.migration.EntityIdScope;
 import org.apache.usergrid.persistence.core.metrics.MetricsFactory;
 import org.apache.usergrid.persistence.core.migration.data.MigrationDataProvider;
@@ -68,6 +68,7 @@ import java.util.*;
 import static java.lang.String.CASE_INSENSITIVE_ORDER;
 import static org.apache.usergrid.persistence.Schema.PROPERTY_NAME;
 import static org.apache.usergrid.persistence.Schema.TYPE_APPLICATION;
+import static org.apache.usergrid.persistence.Schema.initLock;
 
 
 /**
@@ -107,7 +108,8 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
     private final GraphManagerFactory graphManagerFactory;
     private final IndexSchemaCacheFactory indexSchemaCacheFactory;
 
-    public static final String MANAGEMENT_APP_MAX_RETRIES= "management.app.max.retries";
+    public static final String MANAGEMENT_APP_INIT_MAXRETRIES= "management.app.init.max-retries";
+    public static final String MANAGEMENT_APP_INIT_INTERVAL = "management.app.init.interval";
 
 
     public CpEntityManagerFactory(
@@ -177,12 +179,19 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
                         }
                     }
 
-                    if ( app == null && throwable != null && throwable.getCause() instanceof BadRequestException) {
-                        // probably means schema has not been created yet
+                    final boolean missingKeyspace;
+                    if ( throwable instanceof CollectionRuntimeException ) {
+                        CollectionRuntimeException cre = (CollectionRuntimeException) throwable;
+                        missingKeyspace = cre.isMissingKeyspace();
                     } else {
-                        throw new RuntimeException( "Error getting application " + appId, throwable );
+                        missingKeyspace = false;
                     }
 
+                    if ( app == null && !missingKeyspace ) {
+                        throw new RuntimeException( "Error getting application " + appId, throwable );
+
+                    } // else keyspace is missing because setup/bootstrap not done yet
+
                     return entityManager;
                 }
             });
@@ -190,34 +199,77 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
 
 
     private void checkManagementApp(Properties properties) {
+
         int maxRetries = 100;
         try {
-            maxRetries = Integer.parseInt( properties.getProperty( MANAGEMENT_APP_MAX_RETRIES, "100" ));
+            maxRetries = Integer.parseInt( properties.getProperty( MANAGEMENT_APP_INIT_MAXRETRIES, "100" ));
+
+        } catch ( Exception e ) {
+            logger.error("Error parsing " + MANAGEMENT_APP_INIT_MAXRETRIES + ". Will use " + maxRetries, e );
+        }
+
+        int interval = 1000;
+        try {
+            interval = Integer.parseInt( properties.getProperty( MANAGEMENT_APP_INIT_INTERVAL, "1000" ));
 
         } catch ( Exception e ) {
-            logger.error("Error parsing " + MANAGEMENT_APP_MAX_RETRIES + ". Will use " + maxRetries, e );
+            logger.error("Error parsing " + MANAGEMENT_APP_INIT_INTERVAL + ". Will use " + maxRetries, e );
         }
 
         // hold up construction until we can access the management app
         int retries = 0;
         boolean managementAppFound = false;
+        boolean bootstrapping = false;
+        Set<Class> seenBefore = new HashSet<>(10);
         while ( !managementAppFound && retries++ < maxRetries ) {
             try {
-                getEntityManager( getManagementAppId() ).getApplication();
+                // bypass entity manager cache and get managementApp
+                managementApp = _getEntityManager( getManagementAppId() ).getApplication();
                 managementAppFound = true;
 
             } catch ( Throwable t ) {
-                String msg = "Error " + t.getClass() + " getting management app on try " + retries;
-                if ( logger.isDebugEnabled() ) {
+
+                if ( t instanceof CollectionRuntimeException ) {
+                    CollectionRuntimeException cre = (CollectionRuntimeException)t;
+                    if ( cre.isMissingKeyspace() ) {
+                        // we're bootstrapping, ignore this and continue
+                        bootstrapping = true;
+                        break;
+                    }
+                }
+                Throwable cause = t;
+
+                // there was an error, be as informative as possible
+                StringBuilder sb = new StringBuilder();
+                sb.append(retries).append(": Error (");
+
+                if ( t instanceof UncheckedExecutionException ) {
+                    UncheckedExecutionException uee = (UncheckedExecutionException)t;
+                    if ( uee.getCause() instanceof RuntimeException ) {
+                        cause = uee.getCause().getCause();
+                        sb.append(cause.getClass().getSimpleName()).append(") ")
+                          .append(uee.getCause().getMessage());
+                    } else {
+                        cause = uee.getCause();
+                        sb.append(cause.getClass().getSimpleName()).append(") ").append(t.getMessage());
+                    }
+                } else {
+                    sb.append(t.getCause().getClass().getSimpleName()).append(") ").append(t.getMessage());
+                }
+
+                String msg = sb.toString();
+                if ( !seenBefore.contains( cause.getClass() ) ) {
                     logger.error( msg, t);
                 } else {
                     logger.error(msg);
                 }
-                try { Thread.sleep( 1000 ); } catch (InterruptedException ignored) {}
+                seenBefore.add( cause.getClass() );
+
+                try { Thread.sleep( interval ); } catch (InterruptedException ignored) {}
             }
         }
 
-        if ( !managementAppFound ) {
+        if ( !managementAppFound && !bootstrapping ) {
             // exception here will prevent WAR from being deployed
             throw new RuntimeException( "Unable to get management app after " + retries + " retries" );
         }
@@ -323,8 +375,9 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
         // Ensure the management application is initialized
         initMgmtAppInternal();
 
-        EntityManager managementEm = getEntityManager( getManagementAppId() );
-        EntityManager appEm = getEntityManager(applicationId);
+        // Get entity managers by bypassing the entity manager cache because it expects apps to already exist
+        final EntityManager managementEm = _getEntityManager( getManagementAppId() );
+        EntityManager appEm = _getEntityManager(applicationId);
 
         final String appName = buildAppName(organizationName, name);
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/61a35a04/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
index 9bf6694..6acce47 100644
--- a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
@@ -22,6 +22,8 @@ import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.netflix.astyanax.Keyspace;
 import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+import com.netflix.astyanax.connectionpool.exceptions.NoAvailableHostsException;
+import com.netflix.astyanax.connectionpool.exceptions.PoolTimeoutException;
 import com.netflix.astyanax.ddl.ColumnFamilyDefinition;
 import com.netflix.astyanax.ddl.KeyspaceDefinition;
 import com.netflix.astyanax.model.ColumnFamily;
@@ -63,6 +65,7 @@ public class AstyanaxLockManagerImpl implements LockManager {
         int maxRetries = cassandraFig.getLockManagerInitRetries();
         int retries = 0;
         boolean famReady = false;
+        Set<Class> seenBefore = new HashSet<>(10);
         while ( !famReady && retries++ < maxRetries ) {
             try {
                 keyspace = cassandraCluster.getLocksKeyspace();
@@ -71,13 +74,21 @@ public class AstyanaxLockManagerImpl implements LockManager {
                 famReady = true;
 
             } catch ( Throwable t ) {
-                String msg = "Error " + t.getClass().getSimpleName() + " creating locks keyspace try " + retries;
-                if ( logger.isDebugEnabled() ) {
+                final String msg;
+                if ( t instanceof PoolTimeoutException || t instanceof NoAvailableHostsException) {
+                    msg = retries + ": Cannot connect to Cassandra (" + t.getClass().getSimpleName() + ")";
+                } else {
+                    msg = retries + ": Error (" + t.getClass().getSimpleName() + ") tries=" + retries;
+                }
+                if ( !seenBefore.contains( t.getClass() ) ) {
                     logger.error( msg, t );
                 } else {
                     logger.error( msg );
                 }
-                try { Thread.sleep( cassandraFig.getLockManagerInitInterval() ); } catch (InterruptedException ignored) {}
+                seenBefore.add( t.getClass() );
+                try {
+                    Thread.sleep( cassandraFig.getLockManagerInitInterval() );
+                } catch (InterruptedException ignored) {}
             }
         }
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/61a35a04/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java
index 431122e..f27e2d7 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/exception/CollectionRuntimeException.java
@@ -17,6 +17,7 @@
  */
 package org.apache.usergrid.persistence.collection.exception;
 
+import com.netflix.astyanax.connectionpool.exceptions.BadRequestException;
 import org.apache.usergrid.persistence.collection.MvccEntity;
 import org.apache.usergrid.persistence.core.scope.ApplicationScope;
 
@@ -56,6 +57,16 @@ public class CollectionRuntimeException extends RuntimeException {
         this.applicationScope = scope;
     }
 
+    public boolean isMissingKeyspace() {
+        if ( getCause() instanceof BadRequestException ) {
+            BadRequestException bre = (BadRequestException)getCause();
+            String msg = bre.getMessage();
+            if ( msg.contains("Keyspace") && msg.contains( "does not exist" ) ) {
+                return true;
+            }
+        }
+        return false;
+    }
 
     public ApplicationScope getApplicationScope() {
         return applicationScope;


[10/50] [abbrv] usergrid git commit: Minor refactoring and formatting changes.

Posted by mr...@apache.org.
Minor refactoring and formatting changes.


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

Branch: refs/heads/master
Commit: e9e7c39c46ca0b49b5891ee04bdac648e9777cee
Parents: 0b41620
Author: Dave Johnson <sn...@apache.org>
Authored: Fri May 20 16:00:21 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri May 20 16:00:21 2016 -0400

----------------------------------------------------------------------
 .../pipeline/read/search/CandidateEntityFilter.java     | 12 +++++++++---
 .../java/org/apache/usergrid/persistence/IndexIT.java   |  2 +-
 2 files changed, 10 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/e9e7c39c/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
index e02e6c7..4aa6c8d 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
@@ -163,17 +163,19 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate
 
     private void nestedFieldSet( Map<String, Field> result, String[] parts, Map<String, Field> fieldMap) {
         if ( parts.length > 0 ) {
+
             if ( fieldMap.containsKey( parts[0] )) {
                 Field field = fieldMap.get( parts[0] );
                 if ( field instanceof EntityObjectField ) {
                     EntityObjectField eof = (EntityObjectField)field;
-                    if ( result.get( parts[0] ) == null ) {
-                        result.put( parts[0], new EntityObjectField( parts[0], new EntityObject() ) );
-                    }
+                    result.putIfAbsent( parts[0], new EntityObjectField( parts[0], new EntityObject() ) );
+
+                    // recursion
                     nestedFieldSet(
                         ((EntityObjectField)result.get( parts[0] )).getValue().getFieldMap(),
                         Arrays.copyOfRange(parts, 1, parts.length),
                         eof.getValue().getFieldMap());
+
                 } else {
                     result.put( parts[0], field );
                 }
@@ -184,11 +186,15 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate
 
     private boolean nestedFieldCheck( String[] parts, Map<String, Field> fieldMap) {
         if ( parts.length > 0 ) {
+
             if ( fieldMap.containsKey( parts[0] )) {
                 Field field = fieldMap.get( parts[0] );
                 if ( field instanceof EntityObjectField ) {
                     EntityObjectField eof = (EntityObjectField)field;
+
+                    // recursion
                     return nestedFieldCheck( Arrays.copyOfRange(parts, 1, parts.length), eof.getValue().getFieldMap());
+
                 } else {
                     return true;
                 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/e9e7c39c/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
----------------------------------------------------------------------
diff --git a/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java b/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
index aaf4c33..d62f88e 100644
--- a/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
+++ b/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
@@ -528,7 +528,7 @@ public class IndexIT extends AbstractCoreIT {
             assertTrue( first.getDynamicProperties().size() == 3 );
         }
 
-        // multiple nested fields with one doubly-nesed field
+        // multiple nested fields with one doubly-nested field
         {
             Query query = Query.fromQL( "select data.rando, data.mondo, data.misc.range where status = 'pickled'" );
             Results r = em.searchCollection( em.getApplicationRef(), "names", query );


[11/50] [abbrv] usergrid git commit: Improvements to error handling in cache key generation

Posted by mr...@apache.org.
Improvements to error handling in cache key generation


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

Branch: refs/heads/master
Commit: ed4e67c855a1d1062d0cfa5976d05db6b044f11a
Parents: aae8fdf
Author: Dave Johnson <sn...@apache.org>
Authored: Mon May 23 11:41:44 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Mon May 23 11:41:44 2016 -0400

----------------------------------------------------------------------
 .../usergrid/security/shiro/ShiroCache.java     | 80 ++++++++++++--------
 1 file changed, 49 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/ed4e67c8/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java b/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
index b4803b1..6c5ac6c 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
@@ -184,51 +184,69 @@ public class ShiroCache<K, V> implements Cache<K,V> {
 
         String ret = null;
 
-        final String typeName = typeRef.getType().getTypeName();
+        Throwable throwable = null;
 
-        if ( key instanceof SimplePrincipalCollection) {
+        String errorMessage = null;
 
-            SimplePrincipalCollection spc = (SimplePrincipalCollection)key;
+        try {
 
-            if ( spc.getPrimaryPrincipal() instanceof UserPrincipal) {
+            final String typeName = typeRef.getType().getTypeName();
 
-                // principal is a user, use UUID as cache key
-                UserPrincipal p = (UserPrincipal) spc.getPrimaryPrincipal();
-                ret = p.getUser().getUuid().toString() + "_" + typeName;
-            }
+            if (key instanceof SimplePrincipalCollection) {
+
+                SimplePrincipalCollection spc = (SimplePrincipalCollection) key;
+
+                if (spc.getPrimaryPrincipal() instanceof UserPrincipal) {
+
+                    // principal is a user, use UUID as cache key
+                    UserPrincipal p = (UserPrincipal) spc.getPrimaryPrincipal();
+                    ret = p.getUser().getUuid().toString() + "_" + typeName;
+
+                } else if (spc.getPrimaryPrincipal() instanceof PrincipalIdentifier) {
 
-            else if ( spc.getPrimaryPrincipal() instanceof PrincipalIdentifier ) {
+                    // principal is not user, try to get something unique as cache key
+                    PrincipalIdentifier p = (PrincipalIdentifier) spc.getPrimaryPrincipal();
+                    if (p.getAccessTokenCredentials() != null) {
+                        ret = p.getAccessTokenCredentials().getToken() + "_" + typeName;
+                    } else {
+                        ret = p.getApplicationId() + "_" + typeName;
+                    }
 
-                // principal is not user, try to get something unique as cache key
-                PrincipalIdentifier p = (PrincipalIdentifier) spc.getPrimaryPrincipal();
-                if (p.getAccessTokenCredentials() != null) {
-                    ret = p.getAccessTokenCredentials().getToken() + "_" + typeName;
                 } else {
-                    ret = p.getApplicationId() + "_" + typeName;
+                    errorMessage = "Unknown principal type: " + key.getClass().getSimpleName();
                 }
-            }
 
-        } else if ( key instanceof ApplicationGuestPrincipal ) {
-            ApplicationGuestPrincipal agp = (ApplicationGuestPrincipal) key;
-            ret = agp.getApplicationId() + "_" + typeName;
+            } else if (key instanceof ApplicationGuestPrincipal) {
+                ApplicationGuestPrincipal agp = (ApplicationGuestPrincipal) key;
+                ret = agp.getApplicationId() + "_" + typeName;
+
+            } else if (key instanceof ApplicationPrincipal) {
+                ApplicationPrincipal ap = (ApplicationPrincipal) key;
+                ret = ap.getApplicationId() + "_" + typeName;
+
+            } else if (key instanceof OrganizationPrincipal) {
+                OrganizationPrincipal op = (OrganizationPrincipal) key;
+                ret = op.getOrganizationId() + "_" + typeName;
 
-        } else if ( key instanceof ApplicationPrincipal ) {
-            ApplicationPrincipal ap = (ApplicationPrincipal) key;
-            ret = ap.getApplicationId() + "_" + typeName;
+            } else if (key instanceof UserPrincipal) {
+                UserPrincipal up = (UserPrincipal) key;
+                ret = up.getUser().getUuid() + "_" + typeName;
 
-        } else if ( key instanceof OrganizationPrincipal ) {
-            OrganizationPrincipal op = (OrganizationPrincipal) key;
-            ret = op.getOrganizationId() + "_" + typeName;
+            } else {
+                errorMessage = "Unknown key type: " + key.getClass().getSimpleName();
+            }
+
+        } catch ( Throwable t ) {
+            throwable = t;
+        }
 
-        } else if ( key instanceof UserPrincipal ) {
-            UserPrincipal up = (UserPrincipal)key;
-            ret = up.getUser().getUuid() + "_" + typeName;
+        if ( throwable != null ) {
+            errorMessage = "Error generating cache key for key type " + key.getClass().getSimpleName();
+            throw new CacheException( errorMessage, throwable );
         }
 
-        if ( ret == null) {
-            String msg = "Unknown key type: " + key.getClass().getSimpleName();
-            logger.error(msg);
-            throw new RuntimeException(msg);
+        if ( ret == null ) {
+            throw new CacheException( errorMessage );
         }
 
         return ret;


[20/50] [abbrv] usergrid git commit: Add retry logic and logging in AstyanaxLockManagerImpl and CpEntityManagerFactory, also ASL header in CassandraCluster

Posted by mr...@apache.org.
Add retry logic and logging in AstyanaxLockManagerImpl and CpEntityManagerFactory, also ASL header in CassandraCluster


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

Branch: refs/heads/master
Commit: 910811d258b359a3c207c1ef34014d1ba28afebe
Parents: ba10e7f
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 25 13:56:51 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 25 13:56:51 2016 -0400

----------------------------------------------------------------------
 .../corepersistence/CpEntityManagerFactory.java |  8 ++---
 .../cassandra/AstyanaxLockManagerImpl.java      | 36 +++++++++++++-------
 .../core/astyanax/CassandraCluster.java         | 24 ++++++++++---
 3 files changed, 47 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/910811d2/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
index d2417be..84872aa 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManagerFactory.java
@@ -174,17 +174,17 @@ public class CpEntityManagerFactory implements EntityManagerFactory, Application
         int maxRetries = 1000;
         int retries = 0;
         boolean managementAppFound = false;
-        Set<Class> seenBefore = new HashSet<>(100);
         while ( !managementAppFound && retries++ < maxRetries ) {
             try {
                 getEntityManager( getManagementAppId() ).getApplication();
                 managementAppFound = true;
 
             } catch ( Throwable t ) {
-                if ( seenBefore.contains( t.getClass() )) { // don't log full stack trace if we've seen same before
-                    logger.error("Error {} getting management app on try {}", t.getClass().getSimpleName(), retries);
+                String msg = "Error " + t.getClass() + " getting management app on try " + retries;
+                if ( logger.isDebugEnabled() ) {
+                    logger.error( msg, t);
                 } else {
-                    logger.error("Error getting management app on try {}", t.getClass().getSimpleName(), t);
+                    logger.error(msg);
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/910811d2/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
index a69aee2..49ff52e 100644
--- a/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/locking/cassandra/AstyanaxLockManagerImpl.java
@@ -37,9 +37,7 @@ import org.apache.usergrid.persistence.core.astyanax.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 
 @Singleton
@@ -50,8 +48,8 @@ public class AstyanaxLockManagerImpl implements LockManager {
 
 
     private final CassandraFig cassandraFig;
-    private final Keyspace keyspace;
-    private final ColumnFamily columnFamily;
+    private Keyspace keyspace;
+    private ColumnFamily columnFamily;
     private static final int MINIMUM_LOCK_EXPIRATION = 60000; // 1 minute
 
     @Inject
@@ -59,14 +57,28 @@ public class AstyanaxLockManagerImpl implements LockManager {
                                    CassandraCluster cassandraCluster ) throws ConnectionException {
 
         this.cassandraFig = cassandraFig;
-        this.keyspace = cassandraCluster.getLocksKeyspace();
-
-        createLocksKeyspace();
-
-        this.columnFamily = createLocksColumnFamily();
-
-
 
+        // hold up construction until we can create the column family
+        int maxRetries = 1000;
+        int retries = 0;
+        boolean famReady = false;
+        while ( !famReady && retries++ < maxRetries ) {
+            try {
+                keyspace = cassandraCluster.getLocksKeyspace();
+                createLocksKeyspace();
+                columnFamily = createLocksColumnFamily();
+                famReady = true;
+
+            } catch ( Throwable t ) {
+                String msg = "Error " + t.getClass().getSimpleName() + " creating locks keyspace try " + retries;
+                if ( logger.isDebugEnabled() ) {
+                    logger.error( msg, t );
+                } else {
+                    logger.error( msg );
+                }
+                try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
+            }
+        }
 
     }
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/910811d2/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraCluster.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraCluster.java b/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraCluster.java
index 0adac8e..6abc143 100644
--- a/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraCluster.java
+++ b/stack/corepersistence/common/src/main/java/org/apache/usergrid/persistence/core/astyanax/CassandraCluster.java
@@ -1,15 +1,29 @@
-package org.apache.usergrid.persistence.core.astyanax;
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
+package org.apache.usergrid.persistence.core.astyanax;
 
 import com.netflix.astyanax.Keyspace;
-
 import java.util.Map;
 
-
 public interface CassandraCluster {
 
-
     Map<String, Keyspace> getKeyspaces();
 
     Keyspace getApplicationKeyspace();


[25/50] [abbrv] usergrid git commit: Ensure that field names are treated consistently and in a case-insensitive way.

Posted by mr...@apache.org.
Ensure that field names are treated consistently and in a case-insensitive way.


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

Branch: refs/heads/master
Commit: 5452d68c29bb59ec8794639cdc8d6d819792e8bb
Parents: 151abf7
Author: Dave Johnson <sn...@apache.org>
Authored: Wed Jun 1 09:56:01 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed Jun 1 09:56:01 2016 -0400

----------------------------------------------------------------------
 .../read/search/CandidateEntityFilter.java      |  13 +++
 .../model/field/value/EntityObject.java         |  15 ++-
 .../queries/SelectMappingsQueryTest.java        | 105 +++++++++++++++++++
 3 files changed, 128 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/5452d68c/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
index 4aa6c8d..7770436 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
@@ -161,6 +161,13 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate
     }
 
 
+    /**
+     * Sets field in result map with support for nested fields via recursion.
+     *
+     * @param result The result map of filtered fields
+     * @param parts The parts of the field name (more than one if field is nested)
+     * @param fieldMap Map of fields of the object
+     */
     private void nestedFieldSet( Map<String, Field> result, String[] parts, Map<String, Field> fieldMap) {
         if ( parts.length > 0 ) {
 
@@ -184,6 +191,12 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate
     }
 
 
+    /**
+     * Check to see if field should be included in filtered result with support for nested fields via recursion.
+     *
+     * @param parts The parts of the field name (more than one if field is nested)
+     * @param fieldMap Map of fields of the object
+     */
     private boolean nestedFieldCheck( String[] parts, Map<String, Field> fieldMap) {
         if ( parts.length > 0 ) {
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/5452d68c/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java
index db44e87..a157029 100644
--- a/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java
+++ b/stack/corepersistence/model/src/main/java/org/apache/usergrid/persistence/model/field/value/EntityObject.java
@@ -19,10 +19,7 @@
 package org.apache.usergrid.persistence.model.field.value;
 
 import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
 
 import org.apache.usergrid.persistence.model.field.Field;
 
@@ -41,11 +38,19 @@ public class EntityObject implements Serializable {
     @JsonIgnore
     private long size;
 
+    // field names are treated in case-insensitive way by design
+    static class CaseInsensitiveComparator implements Comparator<String> {
+        public int compare(String o1, String o2) {
+            return o1.compareToIgnoreCase(o2);
+        }
+    }
+    public static final CaseInsensitiveComparator INSTANCE = new CaseInsensitiveComparator();
+
     /**
      * Fields the users can set
      */
     @JsonTypeInfo( use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class" )
-    private final Map<String, Field> fields = new HashMap<String, Field>();
+    private Map<String, Field> fields = new TreeMap<String, Field>(INSTANCE);
 
     /**
      * Add the field, return the old one if it existed

http://git-wip-us.apache.org/repos/asf/usergrid/blob/5452d68c/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
new file mode 100644
index 0000000..eb6aeee
--- /dev/null
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.usergrid.rest.applications.queries;
+
+import org.apache.usergrid.rest.test.resource.model.Collection;
+import org.apache.usergrid.rest.test.resource.model.Entity;
+import org.apache.usergrid.rest.test.resource.model.QueryParameters;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+
+public class SelectMappingsQueryTest extends QueryTestBase {
+    private static final Logger logger = LoggerFactory.getLogger(OrderByTest.class);
+
+
+    @Test
+    public void testNestedSelectFieldNames() throws Exception {
+
+        generateTestEntities(20, "things");
+
+        QueryParameters params = new QueryParameters()
+            .setQuery("select actor.displayName,sometestprop where sometestprop = 'testprop'");
+        Collection things = this.app().collection("things").get(params);
+        assertEquals( 10, things.getNumOfEntities() );
+
+        Iterator<Entity> iter = things.iterator();
+        while ( iter.hasNext() ) {
+
+            Entity entity = iter.next();
+            assertEquals( 5, entity.getDynamicProperties().size() );
+
+            assertNotNull( entity.getDynamicProperties().get("uuid") );
+            assertNotNull( entity.getDynamicProperties().get("type") );
+            assertNotNull( entity.getDynamicProperties().get("metadata") );
+            assertNotNull( entity.getDynamicProperties().get("sometestprop") );
+
+            Map<String, Object> actor = (Map<String, Object>)entity.getDynamicProperties().get("actor");
+            assertNotNull( actor );
+            assertNotNull( actor.get("displayName") );
+
+        }
+    }
+
+
+    /**
+     * Shows that field names are case-insensitive.
+     * If you define two fields with same name but different cases, behavior is undefined.
+     */
+    @Test
+    public void testFieldNameCaseSensitivity() throws Exception {
+
+        int numberOfEntities = 10;
+        String collectionName = "things";
+
+        Entity[] entities = new Entity[numberOfEntities];
+        Entity props = new Entity();
+
+        for (int i = 0; i < numberOfEntities; i++) {
+            props.put("testProp", "a");
+            props.put("testprop", "b");
+            entities[i] = app().collection(collectionName).post(props);
+        }
+        refreshIndex();
+
+        {
+            QueryParameters params = new QueryParameters()
+                .setQuery( "select * where testProp = 'b'" );
+            Collection things = this.app().collection( "things" ).get( params );
+
+            // if field names were case sensitive, this would fail
+            assertEquals( numberOfEntities, things.getNumOfEntities() );
+        }
+
+        {
+            QueryParameters params = new QueryParameters()
+                .setQuery( "select * where testprop='b'" );
+            Collection things = this.app().collection( "things" ).get( params );
+
+            assertEquals( numberOfEntities, things.getNumOfEntities() );
+        }
+
+    }
+
+}


[43/50] [abbrv] usergrid git commit: Update event handling to better handle case when no index requests are returned from event processing.

Posted by mr...@apache.org.
Update event handling to better handle case when no index requests are returned from event processing.


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

Branch: refs/heads/master
Commit: 7af4f8454ff9f2270835a2983fa41c390d4602f5
Parents: 3df0779
Author: Michael Russo <mr...@apigee.com>
Authored: Tue Jun 14 13:57:14 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Tue Jun 14 13:57:14 2016 -0700

----------------------------------------------------------------------
 .../asyncevents/AsyncEventServiceImpl.java      | 31 +++++++++++++++-----
 1 file changed, 24 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/7af4f845/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
index fa175ab..8d050fe 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
@@ -355,6 +355,11 @@ public class AsyncEventServiceImpl implements AsyncEventService {
                     throw new Exception("Unknown EventType for message: "+ message.getStringBody().trim());
                 }
 
+                if( single.isEmpty() ){
+                    logger.warn("No index operation messages came back from event processing for msg {} ",
+                        message.getStringBody().trim());
+                }
+
 
                 // if no exception happens and the QueueMessage is returned in these results, it will get ack'd
                 return new IndexEventResult(Optional.of(single), Optional.of(message), thisEvent.getCreationTime());
@@ -370,8 +375,16 @@ public class AsyncEventServiceImpl implements AsyncEventService {
 
             } catch (Exception e) {
 
+                // NPEs don't have a detail message, so add something for our log statement to identify better
+                final String errorMessage;
+                if( e instanceof NullPointerException ) {
+                    errorMessage = "NullPointerException";
+                }else{
+                    errorMessage = e.getMessage();
+                }
+
                 // if the event fails to process, log and return empty message result so it doesn't get ack'd
-                logger.error("{}. Failed to process message: {}", e.getMessage(), message.getStringBody().trim() );
+                logger.error("{}. Failed to process message: {}", errorMessage, message.getStringBody().trim() );
                 return new IndexEventResult(Optional.absent(), Optional.absent(), thisEvent.getCreationTime());
             }
         });
@@ -427,7 +440,8 @@ public class AsyncEventServiceImpl implements AsyncEventService {
 
         final EntityIndexOperation entityIndexOperation = new EntityIndexOperation( applicationScope, entityId, updatedAfter);
 
-        return eventBuilder.buildEntityIndex( entityIndexOperation ).toBlocking().lastOrDefault(null);
+        // default this observable's return to empty index operation message if nothing is emitted
+        return eventBuilder.buildEntityIndex( entityIndexOperation ).toBlocking().lastOrDefault(new IndexOperationMessage());
     }
 
 
@@ -453,9 +467,10 @@ public class AsyncEventServiceImpl implements AsyncEventService {
 
         final EntityCollectionManager ecm = entityCollectionManagerFactory.createCollectionManager( edgeIndexEvent.getApplicationScope() );
 
+        // default this observable's return to empty index operation message if nothing is emitted
         return ecm.load( edgeIndexEvent.getEntityId() )
             .flatMap( loadedEntity -> eventBuilder.buildNewEdge(edgeIndexEvent.getApplicationScope(), loadedEntity, edgeIndexEvent.getEdge()) )
-            .toBlocking().lastOrDefault(null);
+            .toBlocking().lastOrDefault(new IndexOperationMessage());
 
     }
 
@@ -487,7 +502,8 @@ public class AsyncEventServiceImpl implements AsyncEventService {
             logger.debug("Deleting in app scope {} with edge {}", applicationScope, edge);
         }
 
-        return eventBuilder.buildDeleteEdge(applicationScope, edge).toBlocking().lastOrDefault(null);
+        // default this observable's return to empty index operation message if nothing is emitted
+        return eventBuilder.buildDeleteEdge(applicationScope, edge).toBlocking().lastOrDefault(new IndexOperationMessage());
 
     }
 
@@ -600,9 +616,9 @@ public class AsyncEventServiceImpl implements AsyncEventService {
         final Id entityId = deIndexOldVersionsEvent.getEntityIdScope().getId();
         final UUID markedVersion = deIndexOldVersionsEvent.getMarkedVersion();
 
+        // default this observable's return to empty index operation message if nothing is emitted
         return eventBuilder.deIndexOldVersions( applicationScope, entityId, markedVersion )
-            .toBlocking().lastOrDefault(null);
-
+            .toBlocking().lastOrDefault(new IndexOperationMessage());
 
     }
 
@@ -675,7 +691,8 @@ public class AsyncEventServiceImpl implements AsyncEventService {
 
         entityDeleteResults.getCompactedNode().toBlocking().lastOrDefault(null);
 
-        return entityDeleteResults.getIndexObservable().toBlocking().lastOrDefault(null);
+        // default this observable's return to empty index operation message if nothing is emitted
+        return entityDeleteResults.getIndexObservable().toBlocking().lastOrDefault(new IndexOperationMessage());
 
     }
 


[04/50] [abbrv] usergrid git commit: Test for doubly nested field, plus some formatting changes.

Posted by mr...@apache.org.
Test for doubly nested field, plus some formatting changes.


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

Branch: refs/heads/master
Commit: 0b4162035ee7d54199bd2250c2b3ac31354516b1
Parents: 3eec8e5
Author: Dave Johnson <sn...@apache.org>
Authored: Thu May 19 08:57:42 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Thu May 19 08:57:42 2016 -0400

----------------------------------------------------------------------
 .../read/search/CandidateEntityFilter.java      | 16 +++++++-----
 .../apache/usergrid/persistence/IndexIT.java    | 27 +++++++++++++++-----
 2 files changed, 30 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/0b416203/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
index 261259b..e02e6c7 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java
@@ -52,9 +52,9 @@ import rx.Observable;
 
 
 /**
- * Loads entities from an incoming CandidateResult emissions into entities, then streams them on
- * performs internal buffering for efficiency.  Note that all entities may not be emitted if our load crosses page boundaries.  It is up to the
- * collector to determine when to stop streaming entities.
+ * Loads entities from an incoming CandidateResult emissions into entities, then streams them on performs internal
+ * buffering for efficiency.  Note that all entities may not be emitted if our load crosses page boundaries.
+ * It is up to the collector to determine when to stop streaming entities.
  */
 public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate>, FilterResult<Entity>> {
 
@@ -93,11 +93,12 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate
             entityCollectionManagerFactory.createCollectionManager( applicationScope );
 
 
-        final EntityIndex applicationIndex =
-            entityIndexFactory.createEntityIndex(indexLocationStrategyFactory.getIndexLocationStrategy(applicationScope) );
+        final EntityIndex applicationIndex = entityIndexFactory
+            .createEntityIndex(indexLocationStrategyFactory.getIndexLocationStrategy(applicationScope) );
 
         //buffer them to get a page size we can make 1 network hop
-        final Observable<FilterResult<Entity>> searchIdSetObservable = candidateResultsObservable.buffer( pipelineContext.getLimit() )
+        final Observable<FilterResult<Entity>> searchIdSetObservable =
+            candidateResultsObservable.buffer( pipelineContext.getLimit() )
 
             //load them
             .flatMap( candidateResults -> {
@@ -198,7 +199,8 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate
 
 
     /**
-     * Our collector to collect entities.  Not quite a true collector, but works within our operational flow as this state is mutable and difficult to represent functionally
+     * Our collector to collect entities.  Not quite a true collector, but works within our operational
+     * flow as this state is mutable and difficult to represent functionally
      */
     private static final class EntityVerifier {
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/0b416203/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
----------------------------------------------------------------------
diff --git a/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java b/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
index 3b9f95a..aaf4c33 100644
--- a/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
+++ b/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
@@ -477,6 +477,10 @@ public class IndexIT extends AbstractCoreIT {
                 put("xfactor", 5.1);
                 put("rando", "bar");
                 put("mondo", "2000");
+                put("frosting", "chocolate");
+                put("misc", new HashMap() {{
+                    put("range", "open");
+                }});
             }});
         }};
         em.create("names", entity1);
@@ -488,12 +492,17 @@ public class IndexIT extends AbstractCoreIT {
                 put("xfactor", 5.1);
                 put("rando", "bar");
                 put("mondo", "2001");
+                put("frosting", "orange");
+                put("misc", new HashMap() {{
+                    put("range", "open");
+                }});
             }});
         }};
         em.create("names", entity2);
 
         app.refreshIndex();
 
+        // simple single-field select mapping
         {
             Query query = Query.fromQL("select status where status = 'pickled'");
             Results r = em.searchCollection( em.getApplicationRef(), "names", query );
@@ -502,6 +511,7 @@ public class IndexIT extends AbstractCoreIT {
             assertTrue(first.getDynamicProperties().size() == 2);
         }
 
+        // simple single-field plus nested field select mapping
         {
             Query query = Query.fromQL( "select status, data.rando where data.rando = 'bar'" );
             Results r = em.searchCollection( em.getApplicationRef(), "names", query );
@@ -518,23 +528,28 @@ public class IndexIT extends AbstractCoreIT {
             assertTrue( first.getDynamicProperties().size() == 3 );
         }
 
+        // multiple nested fields with one doubly-nesed field
         {
-            //  query for only one bogus field name should return empty entities
-            Query query = Query.fromQL( "select data.rando,data.mondo where status = 'pickled'" );
+            Query query = Query.fromQL( "select data.rando, data.mondo, data.misc.range where status = 'pickled'" );
             Results r = em.searchCollection( em.getApplicationRef(), "names", query );
             assertTrue( r.getEntities() != null && r.getEntities().size() == 2 );
 
             Entity first = r.getEntities().get( 0 );
 
-            assertNotNull( first.getProperty("data") );
-            assertEquals( ((Map<String, Object>)first.getProperty("data")).get("rando"), "bar" );
-            assertEquals( ((Map<String, Object>)first.getProperty("data")).get("mondo"), "2001" );
+            Map<String, Object> data = ((Map<String, Object>)first.getProperty("data"));
+            assertNotNull( data );
+            assertEquals( data.get("rando"), "bar" );
+            assertEquals( data.get("mondo"), "2001" );
+            assertNull( data.get("frosting") );
+
+            Map<String, Object> misc = (Map<String, Object>)data.get("misc");
+            assertEquals( misc.get("range"), "open" );
 
             assertTrue( first.getDynamicProperties().size() == 2 );
         }
 
+        //  query for one bogus field name should return empty entities
         {
-            //  query for only one bogus field name should return empty entities
             Query query = Query.fromQL( "select data.bogusfieldname where status = 'pickled'" );
             Results r = em.searchCollection( em.getApplicationRef(), "names", query );
             assertTrue( r.getEntities() != null && r.getEntities().size() == 2 );


[39/50] [abbrv] usergrid git commit: Merge commit 'refs/pull/534/head' of github.com:apache/usergrid into release-2.1.1

Posted by mr...@apache.org.
Merge commit 'refs/pull/534/head' of github.com:apache/usergrid into release-2.1.1


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

Branch: refs/heads/master
Commit: 38909adaa0e6332f3fdb198a5bd394009d7213d4
Parents: cc7a867 48780f0
Author: Michael Russo <mr...@apigee.com>
Authored: Mon Jun 6 10:51:59 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Mon Jun 6 10:51:59 2016 -0700

----------------------------------------------------------------------
 .../corepersistence/CpEntityManager.java        |   2 +-
 .../corepersistence/EntityManagerFig.java       |   2 +-
 .../asyncevents/AsyncEventService.java          |   6 +-
 .../asyncevents/AsyncEventServiceImpl.java      |  11 +-
 .../asyncevents/EventBuilder.java               |   6 +-
 .../asyncevents/EventBuilderImpl.java           |  46 ++++---
 .../model/DeIndexOldVersionsEvent.java          |  12 +-
 .../corepersistence/index/IndexService.java     |  23 +++-
 .../corepersistence/index/IndexServiceImpl.java |  86 +++++++------
 .../collection/EntityCollectionManager.java     |  10 +-
 .../impl/EntityCollectionManagerImpl.java       |  40 +++++-
 .../serialization/SerializationFig.java         |   5 +
 .../serialization/impl/LogEntryIterator.java    | 128 +++++++++++++++++++
 .../usergrid/persistence/index/EntityIndex.java |   5 +-
 .../usergrid/persistence/index/IndexFig.java    |   2 +-
 .../index/impl/EsEntityIndexImpl.java           |  64 +++-------
 .../persistence/index/impl/EntityIndexTest.java |  41 ------
 17 files changed, 320 insertions(+), 169 deletions(-)
----------------------------------------------------------------------



[06/50] [abbrv] usergrid git commit: Account for every type of principal

Posted by mr...@apache.org.
Account for every type of principal


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

Branch: refs/heads/master
Commit: 5107ccf592346cbd0afb65b6a83985bd062ce2dc
Parents: e2ebc46
Author: Dave Johnson <sn...@apache.org>
Authored: Fri May 20 10:07:11 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri May 20 10:07:11 2016 -0400

----------------------------------------------------------------------
 .../usergrid/security/shiro/ShiroCache.java     | 44 +++++++++++++++-----
 1 file changed, 33 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/5107ccf5/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java b/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
index e14442c..b4803b1 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
@@ -182,31 +182,53 @@ public class ShiroCache<K, V> implements Cache<K,V> {
     /** key is the user UUID in string form + class name of key */
     private String getKeyString( K key ) {
 
-        // both authc and authz caches use same column family
-        // make sure keys unique to key type
-        String keyClass = key.getClass().getSimpleName();
+        String ret = null;
 
-        // if we can't get a user UUID or access token, then we have a guest
-        String ret = keyClass + "_guest";
+        final String typeName = typeRef.getType().getTypeName();
 
         if ( key instanceof SimplePrincipalCollection) {
+
             SimplePrincipalCollection spc = (SimplePrincipalCollection)key;
 
-            // principal is a user, use UUID as cache key
             if ( spc.getPrimaryPrincipal() instanceof UserPrincipal) {
+
+                // principal is a user, use UUID as cache key
                 UserPrincipal p = (UserPrincipal) spc.getPrimaryPrincipal();
-                ret = p.getUser().getUuid().toString() + "_" + keyClass;
+                ret = p.getUser().getUuid().toString() + "_" + typeName;
             }
 
             else if ( spc.getPrimaryPrincipal() instanceof PrincipalIdentifier ) {
-                PrincipalIdentifier p = (PrincipalIdentifier)spc.getPrimaryPrincipal();
 
                 // principal is not user, try to get something unique as cache key
-                if ( p.getAccessTokenCredentials() != null ) {
-                    ret = p.getAccessTokenCredentials().getToken() + "_" + keyClass;
-
+                PrincipalIdentifier p = (PrincipalIdentifier) spc.getPrimaryPrincipal();
+                if (p.getAccessTokenCredentials() != null) {
+                    ret = p.getAccessTokenCredentials().getToken() + "_" + typeName;
+                } else {
+                    ret = p.getApplicationId() + "_" + typeName;
                 }
             }
+
+        } else if ( key instanceof ApplicationGuestPrincipal ) {
+            ApplicationGuestPrincipal agp = (ApplicationGuestPrincipal) key;
+            ret = agp.getApplicationId() + "_" + typeName;
+
+        } else if ( key instanceof ApplicationPrincipal ) {
+            ApplicationPrincipal ap = (ApplicationPrincipal) key;
+            ret = ap.getApplicationId() + "_" + typeName;
+
+        } else if ( key instanceof OrganizationPrincipal ) {
+            OrganizationPrincipal op = (OrganizationPrincipal) key;
+            ret = op.getOrganizationId() + "_" + typeName;
+
+        } else if ( key instanceof UserPrincipal ) {
+            UserPrincipal up = (UserPrincipal)key;
+            ret = up.getUser().getUuid() + "_" + typeName;
+        }
+
+        if ( ret == null) {
+            String msg = "Unknown key type: " + key.getClass().getSimpleName();
+            logger.error(msg);
+            throw new RuntimeException(msg);
         }
 
         return ret;


[28/50] [abbrv] usergrid git commit: Additional test.

Posted by mr...@apache.org.
Additional test.


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

Branch: refs/heads/master
Commit: 317714bc4e5be27a220420c4df4ab281309ba086
Parents: e9228e1
Author: Dave Johnson <sn...@apache.org>
Authored: Fri Jun 3 08:30:42 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Fri Jun 3 08:30:42 2016 -0400

----------------------------------------------------------------------
 .../queries/SelectMappingsQueryTest.java        | 38 ++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/317714bc/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
index 4a291b6..fd33c15 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
@@ -103,7 +103,7 @@ public class SelectMappingsQueryTest extends QueryTestBase {
      * Field named testProp can be over-written by field named TESTPROP.
      */
     @Test
-    public void testFieldOverride() throws Exception {
+    public void testFieldOverride1() throws Exception {
 
         String collectionName = "things";
 
@@ -119,7 +119,7 @@ public class SelectMappingsQueryTest extends QueryTestBase {
         app().collection( collectionName ).post( entity );
         refreshIndex();
 
-        // testProp and TESTPROP should now have newValue
+        // testProp and TESTPROP should new be queryable by new value
 
         QueryParameters params = new QueryParameters()
             .setQuery( "select * where testProp='" + newValue + "'" );
@@ -131,4 +131,38 @@ public class SelectMappingsQueryTest extends QueryTestBase {
         things = app().collection( "things" ).get( params );
         assertEquals( 1, things.getNumOfEntities() );
     }
+
+    /**
+     * Field named testProp can be over-written by field named TESTPROP.
+     */
+    @Test
+    public void testFieldOverride2() throws Exception {
+
+        String collectionName = "things";
+
+        // create entity with TESTPROP=value
+        String value = RandomStringUtils.randomAlphabetic( 20 );
+        Entity entity = new Entity().withProp( "TESTPROP", value );
+        app().collection( collectionName ).post( entity );
+        refreshIndex();
+
+        // override with testProp=newValue
+        String newValue = RandomStringUtils.randomAlphabetic( 20 );
+        entity = new Entity().withProp( "testProp", newValue );
+        app().collection( collectionName ).post( entity );
+        refreshIndex();
+
+        // testProp and TESTPROP should new be queryable by new value
+
+        QueryParameters params = new QueryParameters()
+            .setQuery( "select * where testProp='" + newValue + "'" );
+        Collection things = this.app().collection( "things" ).get( params );
+        assertEquals( 1, things.getNumOfEntities() );
+
+        params = new QueryParameters()
+            .setQuery( "select * where TESTPROP='" + newValue + "'" );
+        things = app().collection( "things" ).get( params );
+        assertEquals( 1, things.getNumOfEntities() );
+    }
+
 }


[16/50] [abbrv] usergrid git commit: Revert all changes to ServiceManager

Posted by mr...@apache.org.
Revert all changes to ServiceManager


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

Branch: refs/heads/master
Commit: 7d2de990705c0fb8380a03620862815854e9fd73
Parents: 6daba1d
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 25 10:20:24 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 25 10:20:24 2016 -0400

----------------------------------------------------------------------
 .../usergrid/services/ServiceManager.java       | 25 +++++++++++---------
 1 file changed, 14 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/7d2de990/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
index e5ef407..a9892f5 100644
--- a/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
+++ b/stack/services/src/main/java/org/apache/usergrid/services/ServiceManager.java
@@ -17,29 +17,32 @@
 package org.apache.usergrid.services;
 
 
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import org.apache.commons.lang.StringUtils;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ApplicationContext;
 import org.apache.usergrid.batch.service.SchedulerService;
 import org.apache.usergrid.locking.LockManager;
 import org.apache.usergrid.mq.QueueManager;
 import org.apache.usergrid.persistence.Entity;
 import org.apache.usergrid.persistence.EntityManager;
 import org.apache.usergrid.persistence.EntityRef;
+import org.apache.usergrid.persistence.cassandra.CassandraService;
 import org.apache.usergrid.persistence.entities.Application;
 import org.apache.usergrid.services.ServiceParameter.IdParameter;
 import org.apache.usergrid.services.applications.ApplicationsService;
 import org.apache.usergrid.services.exceptions.UndefinedServiceEntityTypeException;
 import org.apache.usergrid.utils.ListUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.ApplicationContext;
 
-import java.lang.reflect.Modifier;
-import java.util.*;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
+import org.apache.commons.lang.StringUtils;
+
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 
 import static org.apache.usergrid.persistence.SimpleEntityRef.ref;
 import static org.apache.usergrid.utils.InflectionUtils.pluralize;


[26/50] [abbrv] usergrid git commit: Tests to illustrate case-insensitive handling of Entity field names.

Posted by mr...@apache.org.
Tests to illustrate case-insensitive handling of Entity field names.


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

Branch: refs/heads/master
Commit: e9228e111f338aabf34b334e2661e1966116f23a
Parents: 5452d68
Author: Dave Johnson <sn...@apache.org>
Authored: Thu Jun 2 15:33:28 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Thu Jun 2 15:33:28 2016 -0400

----------------------------------------------------------------------
 .../queries/SelectMappingsQueryTest.java        | 79 +++++++++++++-------
 1 file changed, 54 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/e9228e11/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
----------------------------------------------------------------------
diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
index eb6aeee..4a291b6 100644
--- a/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
+++ b/stack/rest/src/test/java/org/apache/usergrid/rest/applications/queries/SelectMappingsQueryTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.usergrid.rest.applications.queries;
 
+import org.apache.commons.lang.RandomStringUtils;
 import org.apache.usergrid.rest.test.resource.model.Collection;
 import org.apache.usergrid.rest.test.resource.model.Entity;
 import org.apache.usergrid.rest.test.resource.model.QueryParameters;
@@ -34,6 +35,9 @@ public class SelectMappingsQueryTest extends QueryTestBase {
     private static final Logger logger = LoggerFactory.getLogger(OrderByTest.class);
 
 
+    /**
+     * Select field mappings may include nested entity fields.
+     */
     @Test
     public void testNestedSelectFieldNames() throws Exception {
 
@@ -64,42 +68,67 @@ public class SelectMappingsQueryTest extends QueryTestBase {
 
 
     /**
-     * Shows that field names are case-insensitive.
-     * If you define two fields with same name but different cases, behavior is undefined.
+     * When entity posted with two duplicate names with different cases, last one wins.
      */
     @Test
-    public void testFieldNameCaseSensitivity() throws Exception {
+    public void testMixedCaseDupField() throws Exception {
 
-        int numberOfEntities = 10;
         String collectionName = "things";
 
-        Entity[] entities = new Entity[numberOfEntities];
-        Entity props = new Entity();
+        String value = RandomStringUtils.randomAlphabetic( 20 );
+        String otherValue = RandomStringUtils.randomAlphabetic( 20 );
 
-        for (int i = 0; i < numberOfEntities; i++) {
-            props.put("testProp", "a");
-            props.put("testprop", "b");
-            entities[i] = app().collection(collectionName).post(props);
-        }
+        // create entity with testProp=value
+        Entity entity = new Entity()
+            .withProp( "testProp", value )
+            .withProp( "TESTPROP", otherValue);
+        app().collection( collectionName ).post( entity );
         refreshIndex();
 
-        {
-            QueryParameters params = new QueryParameters()
-                .setQuery( "select * where testProp = 'b'" );
-            Collection things = this.app().collection( "things" ).get( params );
+        // testProp and TESTPROP should now have otherValue
 
-            // if field names were case sensitive, this would fail
-            assertEquals( numberOfEntities, things.getNumOfEntities() );
-        }
+        QueryParameters params = new QueryParameters()
+            .setQuery( "select * where testProp='" + otherValue + "'" );
+        Collection things = this.app().collection( "things" ).get( params );
+        assertEquals( 1, things.getNumOfEntities() );
+
+        params = new QueryParameters()
+            .setQuery( "select * where TESTPROP='" + otherValue + "'" );
+        things = app().collection( "things" ).get( params );
+        assertEquals( 1, things.getNumOfEntities() );
+    }
 
-        {
-            QueryParameters params = new QueryParameters()
-                .setQuery( "select * where testprop='b'" );
-            Collection things = this.app().collection( "things" ).get( params );
 
-            assertEquals( numberOfEntities, things.getNumOfEntities() );
-        }
+    /**
+     * Field named testProp can be over-written by field named TESTPROP.
+     */
+    @Test
+    public void testFieldOverride() throws Exception {
 
-    }
+        String collectionName = "things";
 
+        // create entity with testProp=value
+        String value = RandomStringUtils.randomAlphabetic( 20 );
+        Entity entity = new Entity().withProp( "testProp", value );
+        app().collection( collectionName ).post( entity );
+        refreshIndex();
+
+        // override with TESTPROP=newValue
+        String newValue = RandomStringUtils.randomAlphabetic( 20 );
+        entity = new Entity().withProp( "TESTPROP", newValue );
+        app().collection( collectionName ).post( entity );
+        refreshIndex();
+
+        // testProp and TESTPROP should now have newValue
+
+        QueryParameters params = new QueryParameters()
+            .setQuery( "select * where testProp='" + newValue + "'" );
+        Collection things = this.app().collection( "things" ).get( params );
+        assertEquals( 1, things.getNumOfEntities() );
+
+        params = new QueryParameters()
+            .setQuery( "select * where TESTPROP='" + newValue + "'" );
+        things = app().collection( "things" ).get( params );
+        assertEquals( 1, things.getNumOfEntities() );
+    }
 }


[03/50] [abbrv] usergrid git commit: Two fields.

Posted by mr...@apache.org.
Two fields.


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

Branch: refs/heads/master
Commit: 3eec8e55eb57b889be1f2d0d13b44d20a98879dd
Parents: 596e0fc
Author: Dave Johnson <sn...@apache.org>
Authored: Wed May 18 18:58:17 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Wed May 18 18:58:17 2016 -0400

----------------------------------------------------------------------
 .../src/test/java/org/apache/usergrid/persistence/IndexIT.java  | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/3eec8e55/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
----------------------------------------------------------------------
diff --git a/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java b/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
index 7e38f17..3b9f95a 100644
--- a/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
+++ b/stack/core/src/test/java/org/apache/usergrid/persistence/IndexIT.java
@@ -476,6 +476,7 @@ public class IndexIT extends AbstractCoreIT {
             put("data", new HashMap() {{
                 put("xfactor", 5.1);
                 put("rando", "bar");
+                put("mondo", "2000");
             }});
         }};
         em.create("names", entity1);
@@ -486,6 +487,7 @@ public class IndexIT extends AbstractCoreIT {
             put("data", new HashMap() {{
                 put("xfactor", 5.1);
                 put("rando", "bar");
+                put("mondo", "2001");
             }});
         }};
         em.create("names", entity2);
@@ -518,7 +520,7 @@ public class IndexIT extends AbstractCoreIT {
 
         {
             //  query for only one bogus field name should return empty entities
-            Query query = Query.fromQL( "select data.rando where status = 'pickled'" );
+            Query query = Query.fromQL( "select data.rando,data.mondo where status = 'pickled'" );
             Results r = em.searchCollection( em.getApplicationRef(), "names", query );
             assertTrue( r.getEntities() != null && r.getEntities().size() == 2 );
 
@@ -526,6 +528,7 @@ public class IndexIT extends AbstractCoreIT {
 
             assertNotNull( first.getProperty("data") );
             assertEquals( ((Map<String, Object>)first.getProperty("data")).get("rando"), "bar" );
+            assertEquals( ((Map<String, Object>)first.getProperty("data")).get("mondo"), "2001" );
 
             assertTrue( first.getDynamicProperties().size() == 2 );
         }


[05/50] [abbrv] usergrid git commit: Better Shiro cache key logic

Posted by mr...@apache.org.
Better Shiro cache key logic


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

Branch: refs/heads/master
Commit: e2ebc468b2e72cb9cec98bd8f91ee07d507d1c59
Parents: 7fdca3d
Author: Dave Johnson <sn...@apache.org>
Authored: Thu May 19 22:39:05 2016 -0400
Committer: Dave Johnson <sn...@apache.org>
Committed: Thu May 19 22:39:05 2016 -0400

----------------------------------------------------------------------
 .../usergrid/security/shiro/ShiroCache.java     | 22 ++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/e2ebc468/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
----------------------------------------------------------------------
diff --git a/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java b/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
index 88466bf..e14442c 100644
--- a/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
+++ b/stack/services/src/main/java/org/apache/usergrid/security/shiro/ShiroCache.java
@@ -182,16 +182,34 @@ public class ShiroCache<K, V> implements Cache<K,V> {
     /** key is the user UUID in string form + class name of key */
     private String getKeyString( K key ) {
 
+        // both authc and authz caches use same column family
+        // make sure keys unique to key type
+        String keyClass = key.getClass().getSimpleName();
+
+        // if we can't get a user UUID or access token, then we have a guest
+        String ret = keyClass + "_guest";
+
         if ( key instanceof SimplePrincipalCollection) {
             SimplePrincipalCollection spc = (SimplePrincipalCollection)key;
 
+            // principal is a user, use UUID as cache key
             if ( spc.getPrimaryPrincipal() instanceof UserPrincipal) {
                 UserPrincipal p = (UserPrincipal) spc.getPrimaryPrincipal();
-                return p.getUser().getUuid().toString();
+                ret = p.getUser().getUuid().toString() + "_" + keyClass;
+            }
+
+            else if ( spc.getPrimaryPrincipal() instanceof PrincipalIdentifier ) {
+                PrincipalIdentifier p = (PrincipalIdentifier)spc.getPrimaryPrincipal();
+
+                // principal is not user, try to get something unique as cache key
+                if ( p.getAccessTokenCredentials() != null ) {
+                    ret = p.getAccessTokenCredentials().getToken() + "_" + keyClass;
+
+                }
             }
         }
 
-        return key.toString() + "_" + key.getClass().getSimpleName();
+        return ret;
     }
 
 }


[31/50] [abbrv] usergrid git commit: Merge commit 'refs/pull/518/head' of github.com:apache/usergrid into release-2.1.1

Posted by mr...@apache.org.
Merge commit 'refs/pull/518/head' of github.com:apache/usergrid into release-2.1.1


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

Branch: refs/heads/master
Commit: e6cf6ed4f3bd8b542fc72c3bc1d558898bad88a4
Parents: a1cb1f5 1d0e73b
Author: Michael Russo <mr...@apigee.com>
Authored: Fri Jun 3 07:46:06 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Fri Jun 3 07:46:06 2016 -0700

----------------------------------------------------------------------
 .../usergrid/rest/security/SecuredResourceFilterFactory.java       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------



[29/50] [abbrv] usergrid git commit: Merge commit 'refs/pull/528/head' of github.com:apache/usergrid into release-2.1.1

Posted by mr...@apache.org.
Merge commit 'refs/pull/528/head' of github.com:apache/usergrid into release-2.1.1


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

Branch: refs/heads/master
Commit: 8976b414a7e62fa22f9e894eaf50edfe60c4dd76
Parents: 317714b 4b8e546
Author: Michael Russo <mr...@apigee.com>
Authored: Fri Jun 3 07:42:30 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Fri Jun 3 07:42:30 2016 -0700

----------------------------------------------------------------------
 .../main/resources/usergrid-default.properties  |   3 +-
 .../corepersistence/CpEntityManagerFactory.java | 243 ++++++++++++++-----
 .../apache/usergrid/locking/LockManager.java    |   5 +
 .../cassandra/AstyanaxLockManagerImpl.java      |  30 ++-
 .../locking/noop/NoOpLockManagerImpl.java       |   5 +
 .../exception/CollectionRuntimeException.java   |  11 +
 .../core/astyanax/CassandraCluster.java         |  24 +-
 .../persistence/core/astyanax/CassandraFig.java |  18 +-
 .../usergrid/services/ServiceManager.java       |   8 +
 .../services/ServiceManagerFactory.java         |  12 +
 10 files changed, 285 insertions(+), 74 deletions(-)
----------------------------------------------------------------------



[34/50] [abbrv] usergrid git commit: USERGRID-1295 - Re-introduce a more efficient de-index upon entity delete and entity updates. Remove the inefficient code as a safety measure so it can't be used again.

Posted by mr...@apache.org.
USERGRID-1295 - Re-introduce a more efficient de-index upon entity delete and entity updates.  Remove the inefficient code as a safety measure so it can't be used again.


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

Branch: refs/heads/master
Commit: 7143cbaf6c26b4db00d14fb3a1b9e3eb8a2e068e
Parents: 66bb5cd
Author: Michael Russo <mr...@apigee.com>
Authored: Fri Jun 3 22:18:12 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Fri Jun 3 22:18:12 2016 -0700

----------------------------------------------------------------------
 .../corepersistence/CpEntityManager.java        |   2 +-
 .../corepersistence/EntityManagerFig.java       |   2 +-
 .../asyncevents/AsyncEventService.java          |   6 +-
 .../asyncevents/AsyncEventServiceImpl.java      |  11 +-
 .../asyncevents/EventBuilder.java               |   6 +-
 .../asyncevents/EventBuilderImpl.java           |  46 ++++---
 .../model/DeIndexOldVersionsEvent.java          |  12 +-
 .../corepersistence/index/IndexService.java     |  23 +++-
 .../corepersistence/index/IndexServiceImpl.java |  86 +++++++------
 .../collection/EntityCollectionManager.java     |  10 +-
 .../impl/EntityCollectionManagerImpl.java       |  32 ++++-
 .../serialization/SerializationFig.java         |   5 +
 .../serialization/impl/LogEntryIterator.java    | 128 +++++++++++++++++++
 .../usergrid/persistence/index/EntityIndex.java |   5 +-
 .../usergrid/persistence/index/IndexFig.java    |   2 +-
 .../index/impl/EsEntityIndexImpl.java           |  64 +++-------
 .../persistence/index/impl/EntityIndexTest.java |  41 ------
 17 files changed, 313 insertions(+), 168 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
index 68f5d71..fd31cf6 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
@@ -610,7 +610,7 @@ public class CpEntityManager implements EntityManager {
 
             // queue up an event to clean-up older versions than this one from the index
             if (entityManagerFig.getDeindexOnUpdate()) {
-                indexService.queueDeIndexOldVersion( applicationScope, entityId );
+                indexService.queueDeIndexOldVersion( applicationScope, cpEntity.getId(), cpEntity.getVersion());
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/core/src/main/java/org/apache/usergrid/corepersistence/EntityManagerFig.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/EntityManagerFig.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/EntityManagerFig.java
index 4c50aee..655a968 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/EntityManagerFig.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/EntityManagerFig.java
@@ -39,6 +39,6 @@ public interface EntityManagerFig extends GuicyFig {
     int sleep();
 
     @Key( "usergrid.entityManager.enable_deindex_on_update" )
-    @Default( "false" )
+    @Default( "true" )
     boolean getDeindexOnUpdate();
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventService.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventService.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventService.java
index 9f34604..d833cf7 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventService.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventService.java
@@ -27,6 +27,8 @@ import org.apache.usergrid.persistence.index.impl.IndexOperationMessage;
 import org.apache.usergrid.persistence.model.entity.Entity;
 import org.apache.usergrid.persistence.model.entity.Id;
 
+import java.util.UUID;
+
 
 /**
  * Low level queue service for events in the entity.  These events are fire and forget, and will always be asynchronous
@@ -83,11 +85,11 @@ public interface AsyncEventService extends ReIndexAction {
     void queueIndexOperationMessage( final IndexOperationMessage indexOperationMessage );
 
     /**
-     *
      * @param applicationScope
      * @param entityId
+     * @param markedVersion
      */
-    void queueDeIndexOldVersion(final ApplicationScope applicationScope, final Id entityId);
+    void queueDeIndexOldVersion(final ApplicationScope applicationScope, final Id entityId, UUID markedVersion);
 
     /**
      * current queue depth

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
index 3b01292..fa175ab 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/AsyncEventServiceImpl.java
@@ -584,11 +584,11 @@ public class AsyncEventServiceImpl implements AsyncEventService {
 
 
     @Override
-    public void queueDeIndexOldVersion(final ApplicationScope applicationScope, final Id entityId) {
+    public void queueDeIndexOldVersion(final ApplicationScope applicationScope, final Id entityId, UUID markedVersion) {
 
         // queue the de-index of old versions to the topic so cleanup happens in all regions
         offerTopic( new DeIndexOldVersionsEvent( queueFig.getPrimaryRegion(),
-            new EntityIdScope( applicationScope, entityId)) );
+            new EntityIdScope( applicationScope, entityId), markedVersion) );
 
     }
 
@@ -596,10 +596,11 @@ public class AsyncEventServiceImpl implements AsyncEventService {
     public IndexOperationMessage handleDeIndexOldVersionEvent ( final DeIndexOldVersionsEvent deIndexOldVersionsEvent){
 
 
-        ApplicationScope applicationScope = deIndexOldVersionsEvent.getEntityIdScope().getApplicationScope();
-        Id entityId = deIndexOldVersionsEvent.getEntityIdScope().getId();
+        final ApplicationScope applicationScope = deIndexOldVersionsEvent.getEntityIdScope().getApplicationScope();
+        final Id entityId = deIndexOldVersionsEvent.getEntityIdScope().getId();
+        final UUID markedVersion = deIndexOldVersionsEvent.getMarkedVersion();
 
-        return eventBuilder.deIndexOlderVersions( applicationScope, entityId )
+        return eventBuilder.deIndexOldVersions( applicationScope, entityId, markedVersion )
             .toBlocking().lastOrDefault(null);
 
 

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilder.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilder.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilder.java
index 1f62029..4db9f4b 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilder.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilder.java
@@ -21,12 +21,12 @@ package org.apache.usergrid.corepersistence.asyncevents;
 
 
 import java.util.List;
+import java.util.UUID;
 
 import org.apache.usergrid.corepersistence.index.EntityIndexOperation;
 import org.apache.usergrid.persistence.collection.MvccLogEntry;
 import org.apache.usergrid.persistence.core.scope.ApplicationScope;
 import org.apache.usergrid.persistence.graph.Edge;
-import org.apache.usergrid.persistence.index.impl.IndexOperation;
 import org.apache.usergrid.persistence.index.impl.IndexOperationMessage;
 import org.apache.usergrid.persistence.model.entity.Entity;
 import org.apache.usergrid.persistence.model.entity.Id;
@@ -78,9 +78,11 @@ public interface EventBuilder {
      * Find all versions of the entity older than the latest and de-index them.
      * @param applicationScope
      * @param entityId
+     * @param markedVersion
      * @return
      */
-    Observable<IndexOperationMessage> deIndexOlderVersions(ApplicationScope applicationScope, Id entityId );
+    Observable<IndexOperationMessage> deIndexOldVersions( ApplicationScope applicationScope,
+                                                          Id entityId, UUID markedVersion );
 
     /**
      * A bean to hold both our observables so the caller can choose the subscription mechanism.  Note that

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilderImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilderImpl.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilderImpl.java
index 5c827c6..02a7588 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilderImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/EventBuilderImpl.java
@@ -20,11 +20,10 @@
 package org.apache.usergrid.corepersistence.asyncevents;
 
 
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
-import org.apache.usergrid.persistence.collection.VersionSet;
 import org.apache.usergrid.utils.UUIDUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -118,7 +117,7 @@ public class EventBuilderImpl implements EventBuilder {
 
         //TODO USERGRID-1123: Implement so we don't iterate logs twice (latest DELETED version, then to get all DELETED)
 
-        MvccLogEntry mostRecentlyMarked = ecm.getVersions( entityId ).toBlocking()
+        MvccLogEntry mostRecentlyMarked = ecm.getVersionsFromMaxToMin( entityId, UUIDUtils.newTimeUUID() ).toBlocking()
             .firstOrDefault( null, mvccLogEntry -> mvccLogEntry.getState() == MvccLogEntry.State.DELETED );
 
         // De-indexing and entity deletes don't check log entries.  We must do that first. If no DELETED logs, then
@@ -127,13 +126,16 @@ public class EventBuilderImpl implements EventBuilder {
         Observable<List<MvccLogEntry>> ecmDeleteObservable = Observable.empty();
 
         if(mostRecentlyMarked != null){
+
+            // fetch entity versions to be de-index by looking in cassandra
             deIndexObservable =
-                indexService.deleteEntityIndexes( applicationScope, entityId, mostRecentlyMarked.getVersion() );
+                indexService.deIndexEntity(applicationScope, entityId, mostRecentlyMarked.getVersion(),
+                    getVersionsOlderThanMarked(ecm, entityId, mostRecentlyMarked.getVersion()));
 
             ecmDeleteObservable =
-                ecm.getVersions( entityId )
+                ecm.getVersionsFromMaxToMin( entityId, mostRecentlyMarked.getVersion() )
                     .filter( mvccLogEntry->
-                        UUIDUtils.compare(mvccLogEntry.getVersion(), mostRecentlyMarked.getVersion()) <= 0)
+                        mvccLogEntry.getVersion().timestamp() <= mostRecentlyMarked.getVersion().timestamp() )
                     .buffer( serializationFig.getBufferSize() )
                     .doOnNext( buffer -> ecm.delete( buffer ) );
         }
@@ -173,7 +175,8 @@ public class EventBuilderImpl implements EventBuilder {
 
 
     @Override
-    public Observable<IndexOperationMessage> deIndexOlderVersions(final ApplicationScope applicationScope, Id entityId ){
+    public Observable<IndexOperationMessage> deIndexOldVersions( final ApplicationScope applicationScope,
+                                                                 final Id entityId, final UUID markedVersion ){
 
         if (logger.isDebugEnabled()) {
             logger.debug("Removing old versions of entity {} from index in app scope {}", entityId, applicationScope );
@@ -181,24 +184,31 @@ public class EventBuilderImpl implements EventBuilder {
 
         final EntityCollectionManager ecm = entityCollectionManagerFactory.createCollectionManager( applicationScope );
 
-        // find all versions of the entity that come before the provided entityId
-        VersionSet latestVersions = ecm.getLatestVersion(Collections.singletonList(entityId) ).toBlocking()
-            .firstOrDefault( null );
 
-        // If there are no versions before this, allow it to return an empty observable
-        Observable<IndexOperationMessage> deIndexObservable = Observable.empty();
+        return indexService.deIndexOldVersions( applicationScope, entityId,
+            getVersionsOlderThanMarked(ecm, entityId, markedVersion), markedVersion);
 
-        if(latestVersions.getMaxVersion(entityId) != null){
+    }
 
-            UUID latestVersion = latestVersions.getMaxVersion(entityId).getVersion();
 
-            deIndexObservable =
-                indexService.deleteEntityIndexes( applicationScope, entityId, latestVersion);
+    private List<UUID> getVersionsOlderThanMarked( final EntityCollectionManager ecm,
+                                                   final Id entityId, final UUID markedVersion ){
 
-        }
+        final List<UUID> versions = new ArrayList<>();
+
+        // only take last 5 versions to avoid eating memory. a tool can be built for massive cleanups for old usergrid
+        // clusters that do not have this in-line cleanup
+        ecm.getVersionsFromMaxToMin( entityId, markedVersion)
+            .take(5)
+            .forEach( mvccLogEntry -> {
+                if ( mvccLogEntry.getVersion().timestamp() < markedVersion.timestamp() ) {
+                    versions.add(mvccLogEntry.getVersion());
+                }
+
+            });
 
-        return  deIndexObservable;
 
+        return versions;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/model/DeIndexOldVersionsEvent.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/model/DeIndexOldVersionsEvent.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/model/DeIndexOldVersionsEvent.java
index 59694d5..1f00e14 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/model/DeIndexOldVersionsEvent.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/asyncevents/model/DeIndexOldVersionsEvent.java
@@ -21,6 +21,8 @@ package org.apache.usergrid.corepersistence.asyncevents.model;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import org.apache.usergrid.persistence.collection.serialization.impl.migration.EntityIdScope;
 
+import java.util.UUID;
+
 
 /**
  * An index event de-indexing documents for Entity versions older than the provided Entity
@@ -31,12 +33,16 @@ public final class DeIndexOldVersionsEvent extends AsyncEvent {
     @JsonProperty
     protected EntityIdScope entityIdScope;
 
+    @JsonProperty
+    protected UUID markedVersion;
+
     public DeIndexOldVersionsEvent() {
     }
 
-    public DeIndexOldVersionsEvent(String sourceRegion, EntityIdScope entityIdScope) {
+    public DeIndexOldVersionsEvent(String sourceRegion, EntityIdScope entityIdScope, UUID markedVersion) {
         super(sourceRegion);
         this.entityIdScope = entityIdScope;
+        this.markedVersion = markedVersion;
     }
 
 
@@ -47,4 +53,8 @@ public final class DeIndexOldVersionsEvent extends AsyncEvent {
     public EntityIdScope getEntityIdScope() {
         return entityIdScope;
     }
+
+    public UUID getMarkedVersion() {
+        return  markedVersion;
+    }
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexService.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexService.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexService.java
index 54eb464..b989a9c 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexService.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexService.java
@@ -20,17 +20,16 @@
 package org.apache.usergrid.corepersistence.index;
 
 
+import java.util.List;
 import java.util.UUID;
 
 import org.apache.usergrid.persistence.core.scope.ApplicationScope;
 import org.apache.usergrid.persistence.graph.Edge;
-import org.apache.usergrid.persistence.index.IndexEdge;
 import org.apache.usergrid.persistence.index.impl.IndexOperationMessage;
 import org.apache.usergrid.persistence.model.entity.Entity;
 import org.apache.usergrid.persistence.model.entity.Id;
 
 import rx.Observable;
-import rx.observables.ConnectableObservable;
 
 
 /**
@@ -71,18 +70,28 @@ public interface IndexService {
     Observable<IndexOperationMessage> deleteIndexEdge(final ApplicationScope applicationScope, final Edge edge);
 
 
-
-
     /**
-     * Delete all indexes with the specified entityId
+     * De-index all documents with the specified entityId and versions provided.  This will also remove any documents
+     * where the entity is a source/target node ( index docs where this entityId is a part of connections).
      *
      * @param applicationScope
      * @param entityId
+     * @param markedVersion
      * @return
      */
-    Observable<IndexOperationMessage> deleteEntityIndexes(final ApplicationScope applicationScope, final Id entityId,
-                                                         final UUID markedVersion);
+    Observable<IndexOperationMessage> deIndexEntity(final ApplicationScope applicationScope, final Id entityId,
+                                                    final UUID markedVersion, final List<UUID> allVersionsBeforeMarked);
 
 
+    /**
+     * De-index all documents with the specified entityId and versions of the entityId provided
+     *
+     * @param applicationScope
+     * @param entityId
+     * @param markedVersion
+     * @return
+     */
+    Observable<IndexOperationMessage> deIndexOldVersions(final ApplicationScope applicationScope, final Id entityId,
+                                                         final List<UUID> versions, UUID markedVersion);
 
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexServiceImpl.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexServiceImpl.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexServiceImpl.java
index 9509626..54b18bb 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexServiceImpl.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/index/IndexServiceImpl.java
@@ -20,12 +20,7 @@
 package org.apache.usergrid.corepersistence.index;
 
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
+import java.util.*;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -56,8 +51,6 @@ import org.apache.usergrid.persistence.model.entity.Entity;
 import org.apache.usergrid.persistence.model.entity.Id;
 import org.apache.usergrid.persistence.model.entity.SimpleId;
 import org.apache.usergrid.utils.InflectionUtils;
-import org.apache.usergrid.utils.JsonUtils;
-import org.apache.usergrid.utils.UUIDUtils;
 
 import com.codahale.metrics.Timer;
 import com.google.common.base.Optional;
@@ -66,9 +59,7 @@ import com.google.inject.Singleton;
 
 import rx.Observable;
 
-import static org.apache.usergrid.corepersistence.util.CpNamingUtils.createSearchEdgeFromSource;
-import static org.apache.usergrid.corepersistence.util.CpNamingUtils.generateScopeFromSource;
-import static org.apache.usergrid.corepersistence.util.CpNamingUtils.generateScopeFromTarget;
+import static org.apache.usergrid.corepersistence.util.CpNamingUtils.*;
 import static org.apache.usergrid.persistence.Schema.TYPE_APPLICATION;
 
 
@@ -278,42 +269,61 @@ public class IndexServiceImpl implements IndexService {
         return ObservableTimer.time( batches, addTimer );
     }
 
-    //This should look up the entityId and delete any documents with a timestamp that comes before
-    //The edges that are connected will be compacted away from the graph.
+
     @Override
-    public Observable<IndexOperationMessage> deleteEntityIndexes( final ApplicationScope applicationScope,
-                                                                  final Id entityId, final UUID markedVersion ) {
+    public Observable<IndexOperationMessage> deIndexEntity( final ApplicationScope applicationScope, final Id entityId,
+                                                            final UUID markedVersion,
+                                                            final List<UUID> allVersionsBeforeMarked ) {
 
-        //bootstrap the lower modules from their caches
-        final EntityIndex ei = entityIndexFactory.createEntityIndex(indexLocationStrategyFactory.getIndexLocationStrategy(applicationScope) );
+        final EntityIndex ei = entityIndexFactory.
+            createEntityIndex(indexLocationStrategyFactory.getIndexLocationStrategy(applicationScope) );
 
-        CandidateResults crs = ei.getAllEntityVersionsBeforeMarkedVersion( entityId, markedVersion );
 
-        //If we get no search results, its possible that something was already deleted or
-        //that it wasn't indexed yet. In either case we can't delete anything and return an empty observable..
-        if(crs.isEmpty()) {
-            return Observable.empty();
-        }
+        final SearchEdge searchEdgeFromSource = createSearchEdgeFromSource( new SimpleEdge( applicationScope.getApplication(),
+            CpNamingUtils.getEdgeTypeFromCollectionName( InflectionUtils.pluralize( entityId.getType() ) ), entityId,
+            entityId.getUuid().timestamp() ) );
+
+
+        final EntityIndexBatch batch = ei.createBatch();
+
+        // de-index each version of the entity before the marked version
+        allVersionsBeforeMarked.forEach(version -> batch.deindex(searchEdgeFromSource, entityId, version));
 
-        UUID timeUUID = UUIDUtils.isTimeBased(entityId.getUuid()) ? entityId.getUuid() : UUIDUtils.newTimeUUID();
-        //not actually sure about the timestamp but ah well. works.
-        SearchEdge searchEdge = createSearchEdgeFromSource( new SimpleEdge( applicationScope.getApplication(),
+
+        // for now, query the index to remove docs where the entity is source/target node and older than markedVersion
+        // TODO: investigate getting this information from graph
+        CandidateResults candidateResults = ei.getNodeDocsOlderThanMarked(entityId, markedVersion );
+        candidateResults.forEach(candidateResult -> batch.deindex(candidateResult));
+
+        return Observable.just(batch.build());
+
+    }
+
+    @Override
+    public Observable<IndexOperationMessage> deIndexOldVersions(final ApplicationScope applicationScope,
+                                                                final Id entityId,
+                                                                final List<UUID> versions,
+                                                                UUID markedVersion) {
+
+        final EntityIndex ei = entityIndexFactory.
+            createEntityIndex(indexLocationStrategyFactory.getIndexLocationStrategy(applicationScope) );
+
+
+        final SearchEdge searchEdgeFromSource = createSearchEdgeFromSource( new SimpleEdge( applicationScope.getApplication(),
             CpNamingUtils.getEdgeTypeFromCollectionName( InflectionUtils.pluralize( entityId.getType() ) ), entityId,
-            timeUUID.timestamp() ) );
+             entityId.getUuid().timestamp() ) );
 
 
-        final Observable<IndexOperationMessage>  batches = Observable.from( crs )
-                //collect results into a single batch
-                .collect( () -> ei.createBatch(), ( batch, candidateResult ) -> {
-                    if (logger.isDebugEnabled()) {
-                        logger.debug("Deindexing on edge {} for entity {} added to batch", searchEdge, entityId);
-                    }
-                    batch.deindex( candidateResult );
-                } )
-                    //return the future from the batch execution
-                .map( batch ->batch.build() );
+        final EntityIndexBatch batch = ei.createBatch();
+
+        versions.forEach( version -> {
+
+            batch.deindex(searchEdgeFromSource, entityId, version);
+
+        });
+
+        return Observable.just(batch.build());
 
-        return ObservableTimer.time(batches, indexTimer);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java
index 9de8f41..22fbb5f 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/EntityCollectionManager.java
@@ -20,6 +20,7 @@ package org.apache.usergrid.persistence.collection;
 
 
 import java.util.Collection;
+import java.util.UUID;
 
 import org.apache.usergrid.persistence.core.util.Health;
 import org.apache.usergrid.persistence.model.entity.Entity;
@@ -98,13 +99,20 @@ public interface EntityCollectionManager {
     Observable<EntitySet> load( Collection<Id> entityIds );
 
     /**
-     * Get all versions of the log entry, from Max to min
+     * Get all versions of the log entry, from min to max
      * @param entityId
      * @return An observable stream of mvccLog entries
      */
     Observable<MvccLogEntry> getVersions(final Id entityId);
 
     /**
+     * Get all versions of the log entry, from max to min
+     * @param entityId
+     * @return An observable stream of mvccLog entries
+     */
+    Observable<MvccLogEntry> getVersionsFromMaxToMin(final Id entityId, final UUID startVersion);
+
+    /**
      * Delete these versions from cassandra.  Must be atomic so that read log entries are only removed.  Entity data
      * and log entry will be deleted
      * @param entries

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
index e71e6bb..70b06ba 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/impl/EntityCollectionManagerImpl.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.UUID;
 
 import com.netflix.astyanax.model.ConsistencyLevel;
+import org.apache.usergrid.persistence.collection.serialization.impl.LogEntryIterator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -279,6 +280,19 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager {
         } );
     }
 
+    @Override
+    public Observable<MvccLogEntry> getVersionsFromMaxToMin( final Id entityId, final UUID startVersion ) {
+        ValidationUtils.verifyIdentity( entityId );
+
+        return Observable.create( new ObservableIterator<MvccLogEntry>( "Log entry iterator" ) {
+            @Override
+            protected Iterator<MvccLogEntry> getIterator() {
+                return new LogEntryIterator( mvccLogEntrySerializationStrategy, applicationScope, entityId, startVersion,
+                    serializationFig.getBufferSize() );
+            }
+        } );
+    }
+
 
     @Override
     public Observable<MvccLogEntry> delete( final Collection<MvccLogEntry> entries ) {
@@ -359,6 +373,7 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager {
                     if ( entity == null || !entity.getEntity().isPresent() ) {
                         final MutationBatch valueDelete =
                             uniqueValueSerializationStrategy.delete( applicationScope, expectedUnique );
+
                         deleteBatch.mergeShallow( valueDelete );
                         continue;
                     }
@@ -370,10 +385,23 @@ public class EntityCollectionManagerImpl implements EntityCollectionManager {
                     response.addEntity( expectedUnique.getField(), entity );
                 }
 
-                //TODO: explore making this an Async process
-                //We'll repair it again if we have to
                 deleteBatch.execute();
 
+                // optionally sleep after read repair as some tasks immediately try to write after the delete
+                if ( serializationFig.getReadRepairDelay() > 0 ){
+
+                    try {
+
+                        Thread.sleep(Math.min(serializationFig.getReadRepairDelay(), 200L));
+
+                    } catch (InterruptedException e) {
+
+                        // do nothing if sleep fails; log and continue on
+                        logger.warn("Sleep during unique value read repair failed.");
+                    }
+
+                }
+
                 return response;
             }
             catch ( ConnectionException e ) {

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java
index 96759ba..12033fe 100644
--- a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/SerializationFig.java
@@ -57,4 +57,9 @@ public interface SerializationFig extends GuicyFig {
     @Key ( "usergrid.uniqueverify.poolsize" )
     @Default( "150" )
     int getUniqueVerifyPoolSize();
+
+
+    @Key ( "collection.readrepair.delay" )
+    @Default( "0" ) // in milliseconds
+    int getReadRepairDelay();
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/LogEntryIterator.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/LogEntryIterator.java b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/LogEntryIterator.java
new file mode 100644
index 0000000..de6b2bc
--- /dev/null
+++ b/stack/corepersistence/collection/src/main/java/org/apache/usergrid/persistence/collection/serialization/impl/LogEntryIterator.java
@@ -0,0 +1,128 @@
+package org.apache.usergrid.persistence.collection.serialization.impl;
+
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.UUID;
+
+import org.apache.usergrid.persistence.collection.MvccLogEntry;
+import org.apache.usergrid.persistence.collection.serialization.MvccLogEntrySerializationStrategy;
+import org.apache.usergrid.persistence.core.scope.ApplicationScope;
+import org.apache.usergrid.persistence.model.entity.Id;
+
+import com.google.common.base.Preconditions;
+import com.netflix.astyanax.connectionpool.exceptions.ConnectionException;
+
+
+/**
+ * Iterator that will iterate all versions of the entity from max to min
+ */
+public class LogEntryIterator implements Iterator<MvccLogEntry> {
+
+
+    private final MvccLogEntrySerializationStrategy logEntrySerializationStrategy;
+    private final ApplicationScope scope;
+    private final Id entityId;
+    private final int pageSize;
+
+
+    private Iterator<MvccLogEntry> elementItr;
+    private UUID nextStart;
+    private UUID startVersion;
+
+
+    /**
+     * @param logEntrySerializationStrategy The serialization strategy to get the log entries
+     * @param scope The scope of the entity
+     * @param entityId The id of the entity
+     * @param pageSize The fetch size to get when querying the serialization strategy
+     */
+    public LogEntryIterator( final MvccLogEntrySerializationStrategy logEntrySerializationStrategy,
+                             final ApplicationScope scope, final Id entityId,
+                             final UUID startVersion, final int pageSize ) {
+
+        Preconditions.checkArgument( pageSize > 0, "pageSize must be > 0" );
+
+        this.logEntrySerializationStrategy = logEntrySerializationStrategy;
+        this.scope = scope;
+        this.entityId = entityId;
+        this.pageSize = pageSize;
+        this.startVersion = startVersion;
+
+    }
+
+
+    @Override
+    public boolean hasNext() {
+        if ( elementItr == null || !elementItr.hasNext() && nextStart != null ) {
+            try {
+                advance();
+            }
+            catch ( ConnectionException e ) {
+                throw new RuntimeException( "Unable to query cassandra", e );
+            }
+        }
+
+        return elementItr.hasNext();
+    }
+
+
+    @Override
+    public MvccLogEntry next() {
+        if ( !hasNext() ) {
+            throw new NoSuchElementException( "No more elements exist" );
+        }
+
+        return elementItr.next();
+    }
+
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException( "Remove is unsupported" );
+    }
+
+
+    /**
+     * Advance our iterator
+     */
+    public void advance() throws ConnectionException {
+
+        final int requestedSize;
+        UUID start;
+
+        if ( nextStart != null ) {
+            requestedSize = pageSize + 1;
+            start = nextStart;
+        }
+        else {
+            requestedSize = pageSize;
+            start = startVersion;
+        }
+
+        //loop through even entry that's < this one and remove it
+        List<MvccLogEntry> results = logEntrySerializationStrategy.load( scope, entityId, start, requestedSize );
+
+        //we always remove the first version if it's equal since it's returned
+        if ( nextStart != null && results.size() > 0 && results.get( 0 ).getVersion().equals( nextStart ) ) {
+            results.remove( 0 );
+        }
+
+
+
+        //we have results, set our next start.  If we miss our start version (due to deletion) and we request a +1, we want to ensure we set our next, hence the >=
+        if ( results.size() >= pageSize ) {
+            nextStart = results.get( results.size() - 1 ).getVersion();
+        }
+        //nothing left to do
+        else {
+            nextStart = null;
+        }
+
+
+
+
+        elementItr = results.iterator();
+    }
+}

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java
index 81f900c..8ab2d41 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java
@@ -113,14 +113,13 @@ public interface EntityIndex extends CPManager {
     CandidateResults getAllEdgeDocuments(final IndexEdge edge, final Id entityId);
 
     /**
-     * Returns all entity documents that match the entityId and come before the marked version
+     * Returns all entity docs that match the entityId being the nodeId ( aka connections where entityId = sourceNode)
      *
      * @param entityId      The entityId to match when searching
      * @param markedVersion The version that has been marked for deletion. All version before this one must be deleted.
      * @return
      */
-    CandidateResults getAllEntityVersionsBeforeMarkedVersion(final Id entityId, final UUID markedVersion);
-
+    CandidateResults getNodeDocsOlderThanMarked(final Id entityId, final UUID markedVersion);
     /**
      * delete all application records
      *

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java
index e81219a..3dbf5e5 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java
@@ -202,7 +202,7 @@ public interface IndexFig extends GuicyFig {
     @Key( "elasticsearch_queue_error_sleep_ms" )
     long getSleepTimeForQueueError();
 
-    @Default("1000")
+    @Default("100")
     @Key( ELASTICSEARCH_VERSION_QUERY_LIMIT )
     int getVersionQueryLimit();
 }

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java
index 10ee91e..3b60b57 100644
--- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java
+++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java
@@ -533,7 +533,9 @@ public class EsEntityIndexImpl implements EntityIndex,VersionedData {
 
 
     @Override
-    public CandidateResults getAllEntityVersionsBeforeMarkedVersion( final Id entityId, final UUID markedVersion ) {
+    public CandidateResults getNodeDocsOlderThanMarked(final Id entityId, final UUID markedVersion ) {
+
+        // TODO: investigate if functionality via iterator so a caller can page the deletion until all is gone
 
         Preconditions.checkNotNull( entityId, "entityId cannot be null" );
         Preconditions.checkNotNull(markedVersion, "markedVersion cannot be null");
@@ -544,12 +546,8 @@ public class EsEntityIndexImpl implements EntityIndex,VersionedData {
 
         final long markedTimestamp = markedVersion.timestamp();
 
-        // never let the limit be less than 2 as there are potential indefinite paging issues
-        final int searchLimit = Math.max(2, indexFig.getVersionQueryLimit());
-
-        // this query will find the document for the entity itself
-        final QueryBuilder entityQuery = QueryBuilders
-            .termQuery(IndexingUtils.ENTITY_ID_FIELDNAME, IndexingUtils.entityId(entityId));
+        // never let this fetch more than 100 to save memory
+        final int searchLimit = Math.min(100, indexFig.getVersionQueryLimit());
 
         // this query will find all the documents where this entity is a source/target node
         final QueryBuilder nodeQuery = QueryBuilders
@@ -562,49 +560,25 @@ public class EsEntityIndexImpl implements EntityIndex,VersionedData {
 
             long queryTimestamp = 0L;
 
-            while(true){
+            QueryBuilder timestampQuery =  QueryBuilders
+                .rangeQuery(IndexingUtils.EDGE_TIMESTAMP_FIELDNAME)
+                .gte(queryTimestamp)
+                .lt(markedTimestamp);
 
-                QueryBuilder timestampQuery =  QueryBuilders
-                    .rangeQuery(IndexingUtils.EDGE_TIMESTAMP_FIELDNAME)
-                    .gte(queryTimestamp)
-                    .lte(markedTimestamp);
+            QueryBuilder finalQuery = QueryBuilders
+                .boolQuery()
+                .must(timestampQuery)
+                .must(nodeQuery);
 
-                QueryBuilder entityQueryWithTimestamp = QueryBuilders
-                    .boolQuery()
-                    .must(entityQuery)
-                    .must(timestampQuery);
+            searchResponse = srb
+                .setQuery(finalQuery)
+                .setSize(searchLimit)
+                .execute()
+                .actionGet();
 
-                QueryBuilder finalQuery = QueryBuilders
-                    .boolQuery()
-                    .should(entityQueryWithTimestamp)
-                    .should(nodeQuery)
-                    .minimumNumberShouldMatch(1);
 
-                searchResponse = srb
-                    .setQuery(finalQuery)
-                    .setSize(searchLimit)
-                    .execute()
-                    .actionGet();
+            candidates = aggregateScrollResults(candidates, searchResponse, markedVersion);
 
-                int responseSize = searchResponse.getHits().getHits().length;
-                if(responseSize == 0){
-                    break;
-                }
-
-                candidates = aggregateScrollResults(candidates, searchResponse, markedVersion);
-
-                // update queryTimestamp to be the timestamp of the last entity returned from the query
-                queryTimestamp = (long) searchResponse
-                    .getHits().getAt(responseSize - 1)
-                    .getSource().get(IndexingUtils.EDGE_TIMESTAMP_FIELDNAME);
-
-
-                if(responseSize < searchLimit){
-
-                    break;
-                }
-
-            }
         }
         catch ( Throwable t ) {
             logger.error( "Unable to communicate with Elasticsearch", t.getMessage() );

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7143cbaf/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
----------------------------------------------------------------------
diff --git a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
index 008ec80..c84635d 100644
--- a/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
+++ b/stack/corepersistence/queryindex/src/test/java/org/apache/usergrid/persistence/index/impl/EntityIndexTest.java
@@ -383,47 +383,6 @@ public class EntityIndexTest extends BaseIT {
     }
 
 
-    /**
-     * Tests that we aggregate results only before the halfway version point.
-     */
-    @Test
-    public void testScollingDeindex() {
-
-        int numberOfEntities = 1000;
-        int versionToSearchFor = numberOfEntities / 2;
-
-
-        UUID entityUUID = UUID.randomUUID();
-        Id entityId = new SimpleId( "mehCar" );
-
-        Map entityMap = new HashMap() {{
-            put( "name", "Toyota Corolla" );
-            put( "introduced", 1966 );
-            put( "topspeed", 111 );
-        }};
-
-        Entity[] entity = new Entity[numberOfEntities];
-        for(int i = 0; i < numberOfEntities; i++) {
-            entity[i] = EntityIndexMapUtils.fromMap( entityMap );
-            EntityUtils.setId(entity[i], entityId);
-            EntityUtils.setVersion(entity[i], UUIDGenerator.newTimeUUID());
-            entity[i].setField(new UUIDField(IndexingUtils.ENTITY_ID_FIELDNAME, entityUUID));
-
-            IndexEdge searchEdge = new IndexEdgeImpl( appId, "mehCars", SearchEdge.NodeType.SOURCE, System.currentTimeMillis()*1000 );
-
-            //index the new entity. This is where the loop will be set to create like 100 entities.
-            indexProducer.put(entityIndex.createBatch().index( searchEdge, entity[i] ).build()).subscribe();
-
-        }
-        entityIndex.refreshAsync().toBlocking().first();
-
-        CandidateResults candidateResults = entityIndex
-            .getAllEntityVersionsBeforeMarkedVersion( entity[versionToSearchFor].getId(),
-                entity[versionToSearchFor].getVersion() );
-        assertEquals( 501, candidateResults.size() );
-    }
-
-
 
     private CandidateResults testQuery( final SearchEdge scope, final SearchTypes searchTypes,
                                       final String queryString,


[40/50] [abbrv] usergrid git commit: bug fix - When cursor queryparam is passed in with an empty value then throw 400.

Posted by mr...@apache.org.
bug fix - When cursor queryparam is passed in with an empty value then throw 400.


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

Branch: refs/heads/master
Commit: 0eaea9890b5149f2e7203a90c1dd37a886bbd12c
Parents: 38909ad
Author: Ayesha Dastagiri <ay...@gmail.com>
Authored: Mon Jun 6 13:55:41 2016 -0700
Committer: Ayesha Dastagiri <ay...@gmail.com>
Committed: Mon Jun 6 13:55:41 2016 -0700

----------------------------------------------------------------------
 .../pipeline/cursor/RequestCursor.java            | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/0eaea989/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java
----------------------------------------------------------------------
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java
index dc6ae71..acd6e25 100644
--- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java
+++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/cursor/RequestCursor.java
@@ -20,17 +20,15 @@
 package org.apache.usergrid.corepersistence.pipeline.cursor;
 
 
-import java.util.Base64;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import com.fasterxml.jackson.core.Base64Variant;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
 
 /**
  * A cursor that has been passed in with our request.  Adds utils for parsing values
@@ -76,13 +74,13 @@ public class RequestCursor {
      * Deserialize from the cursor as json nodes
      */
     private Map<Integer, JsonNode> fromCursor( final String cursor ) throws CursorParseException {
-        try {
-
-
+        if(cursor.isEmpty()){
+            throw new IllegalArgumentException("cursor cannot be empty");
+        }
 
+        try {
             JsonNode jsonNode = CursorSerializerUtil.fromString( cursor );
 
-
             Preconditions
                 .checkArgument( jsonNode.size() <= MAX_CURSOR_COUNT, " You cannot have more than " + MAX_CURSOR_COUNT + " cursors" );
 


[49/50] [abbrv] usergrid git commit: Add Pivotal Cloud Foundry source for creating Usergrid Tile ( CF deployment + bosh release )

Posted by mr...@apache.org.
Add Pivotal Cloud Foundry source for creating Usergrid Tile ( CF deployment + bosh release )


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

Branch: refs/heads/master
Commit: 29c287b22c030164faef4d57e2e7fa51fbaaf2f1
Parents: 8814a14
Author: Michael Russo <mr...@apigee.com>
Authored: Wed Jun 15 09:21:40 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Wed Jun 15 09:21:40 2016 -0700

----------------------------------------------------------------------
 deployment/pcf/LICENSE                          | 201 ++++++++
 deployment/pcf/README.md                        |  44 ++
 deployment/pcf/addBlobs.sh                      |  25 +
 deployment/pcf/apache-usergrid-tile-1.6.yml     | 510 +++++++++++++++++++
 deployment/pcf/config/blobs.yml                 |  19 +
 deployment/pcf/config/final.yml                 |  24 +
 deployment/pcf/content_migrations.yml           |  53 ++
 deployment/pcf/createRelease.sh                 |  24 +
 deployment/pcf/createTile.sh                    |  32 ++
 deployment/pcf/jobs/delete-all/monit            |  17 +
 deployment/pcf/jobs/delete-all/spec             |  44 ++
 .../jobs/delete-all/templates/delete-all.sh.erb | 131 +++++
 deployment/pcf/jobs/deploy-all/monit            |  18 +
 deployment/pcf/jobs/deploy-all/spec             | 145 ++++++
 .../jobs/deploy-all/templates/deploy-all.sh.erb | 384 ++++++++++++++
 .../pcf/jobs/docker-bosh-cassandra_docker/monit |  23 +
 .../pcf/jobs/docker-bosh-cassandra_docker/spec  |  26 +
 .../docker-bosh-cassandra_docker.sh.erb         |  69 +++
 .../jobs/docker-bosh-elasticsearch_docker/monit |  23 +
 .../jobs/docker-bosh-elasticsearch_docker/spec  |  26 +
 .../docker-bosh-elasticsearch_docker.sh.erb     |  69 +++
 .../pcf/packages/cassandra_docker/packaging     |  26 +
 deployment/pcf/packages/cassandra_docker/spec   |  26 +
 deployment/pcf/packages/cf_cli/packaging        |  26 +
 deployment/pcf/packages/cf_cli/spec             |  25 +
 deployment/pcf/packages/common/packaging        |  23 +
 deployment/pcf/packages/common/spec             |  25 +
 .../pcf/packages/elasticsearch_docker/packaging |  26 +
 .../pcf/packages/elasticsearch_docker/spec      |  26 +
 deployment/pcf/packages/usergrid_app/packaging  |  27 +
 deployment/pcf/packages/usergrid_app/spec       |  27 +
 deployment/pcf/run.sh                           |  25 +
 deployment/pcf/src/common/utils.sh              | 107 ++++
 deployment/pcf/src/templates/all_open.json      |   6 +
 deployment/pcf/src/usergrid_app/manifest.yml    |  22 +
 35 files changed, 2324 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/LICENSE
----------------------------------------------------------------------
diff --git a/deployment/pcf/LICENSE b/deployment/pcf/LICENSE
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/deployment/pcf/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   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.

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/README.md
----------------------------------------------------------------------
diff --git a/deployment/pcf/README.md b/deployment/pcf/README.md
new file mode 100644
index 0000000..0a002ed
--- /dev/null
+++ b/deployment/pcf/README.md
@@ -0,0 +1,44 @@
+# Bosh Release + PCF Tile for Apache Usergrid
+
+This is a bosh release for the apache usergrid. The scripts provided can help create the bosh release and tile for Apache Usergrid.
+A version of the tile is available here: https://s3.amazonaws.com/usergrid-v2-public/usergrid_v2.pivotal
+
+# Components Dependency
+* Apache usergrid warfile
+  Grab the code from: https://github.com/apache/usergrid
+  Build the war file and save it as ROOT.war 
+* CF CLI Linux binary
+  Download the CF CLI linux binary (64 bit) from: https://github.com/cloudfoundry/cli/releases
+* ElasticSearch and Cassandra. 
+  Apache Usergrid requires ElasticSearch and Cassandra to search and manage data.
+  The Bosh release uses dockerized images to run both ElasticSearch and Cassandra.
+  Create docker images for both elastic search (v1.7) and cassandra (v2.1) and save them locally as tarballs
+* Docker Bosh Release
+  To run docker images within Bosh, we need the docker bosh release.
+  Download v23 from: http://bosh.io/releases/github.com/cf-platform-eng/docker-boshrelease?all=1
+
+# Building Bosh release
+* Ensure following files are available at the root of the apache-usergrid-release directory
+```
+cf-linux-amd64.tgz          # downloaded from CF cli github repo
+ROOT.war                    # built from usergrid repo
+cassandra-2.1.tgz           # Saved Cassandra 2.1 docker image 
+elasticsearch-1.7.tgz       # Saved ElasticSearch 1.7 docker image 
+docker-boshrelease-23.tgz   # Docker Bosh release v23
+```
+* Run addBlobs.sh
+  Important to ensure the above blobs filenames match the entries inside the addBlobs.sh (& each of the packages/*/packaging file)
+* Run ./createRelease.sh
+  Edit the version as required inside the script
+# Building Tile
+* Edit the apache-usergrid-tile-1.6.yml to refer to the correct version of release tarball (for docker bosh release and usergrid)
+* Run ./createTile.sh
+  Edit the file names or versions as needed.
+  The docker-boshrelease-23.tgz file should be present in the directory to create a valid working tile
+  The script should create the usergrid.pivotal tile file.
+
+# Notes
+* Ensure the usergrid war file is named ROOT.war (or rename all references of ROOT.war with different file name) before running addBlobs.sh
+* If newer versions are being used, please check and replace the associated versions inside packages/<package-name>/spec & packages/<packagge-name>/packaging file to deal with correct files.
+* Update the tile metadata file if newer release versions are used
+* Update the content_migrations.yml if new tile version is being published

http://git-wip-us.apache.org/repos/asf/usergrid/blob/29c287b2/deployment/pcf/addBlobs.sh
----------------------------------------------------------------------
diff --git a/deployment/pcf/addBlobs.sh b/deployment/pcf/addBlobs.sh
new file mode 100755
index 0000000..35cdbca
--- /dev/null
+++ b/deployment/pcf/addBlobs.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+#
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  The ASF licenses this file to You
+#  under the Apache License, Version 2.0 (the "License"); you may not
+#  use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.  For additional information regarding
+#  copyright in this work, please see the NOTICE file in the top level
+#  directory of this distribution.
+#
+
+bosh add blob ROOT.war usergrid_app
+bosh add blob cassandra-2.1.tgz cassandra_docker
+bosh add blob elasticsearch-1.7.tgz elasticsearch_docker
+bosh add blob cf-linux-amd64.tgz cf_cli
+bosh upload blobs


[30/50] [abbrv] usergrid git commit: Merge commit 'refs/pull/532/head' of github.com:apache/usergrid into release-2.1.1

Posted by mr...@apache.org.
Merge commit 'refs/pull/532/head' of github.com:apache/usergrid into release-2.1.1


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

Branch: refs/heads/master
Commit: a1cb1f5f45352a3dc7e7c0df91bb037e027d0ddd
Parents: 8976b41 ed4e67c
Author: Michael Russo <mr...@apigee.com>
Authored: Fri Jun 3 07:42:43 2016 -0700
Committer: Michael Russo <mr...@apigee.com>
Committed: Fri Jun 3 07:42:43 2016 -0700

----------------------------------------------------------------------
 .../usergrid/security/shiro/ShiroCache.java     | 80 ++++++++++++--------
 1 file changed, 49 insertions(+), 31 deletions(-)
----------------------------------------------------------------------