ONOS-1731 Fixed app gossip store & manager to deal with staggered app load on startup.

Change-Id: Ie88f5659646c11b906a63204f97083b6deb64adb
diff --git a/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java b/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java
index 6e3c3df..7754a12 100644
--- a/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java
+++ b/core/net/src/main/java/org/onosproject/app/impl/ApplicationManager.java
@@ -69,10 +69,16 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected EventDeliveryService eventDispatcher;
 
+    private boolean initializing;
+
     @Activate
     public void activate() {
         eventDispatcher.addSink(ApplicationEvent.class, listenerRegistry);
+
+        initializing = true;
         store.setDelegate(delegate);
+        initializing = false;
+
         log.info("Started");
     }
 
@@ -207,8 +213,12 @@
     private synchronized void installAppFeatures(Application app) throws Exception {
         for (String name : app.features()) {
             Feature feature = featuresService.getFeature(name);
-            if (!featuresService.isInstalled(feature)) {
+            if (feature != null && !featuresService.isInstalled(feature)) {
                 featuresService.installFeature(name);
+            } else if (feature == null && !initializing) {
+                // Suppress feature-not-found reporting during startup since these
+                // can arise naturally from the staggered cluster install.
+                log.warn("Feature {} not found", name);
             }
         }
     }
@@ -216,8 +226,10 @@
     private synchronized void uninstallAppFeatures(Application app) throws Exception {
         for (String name : app.features()) {
             Feature feature = featuresService.getFeature(name);
-            if (featuresService.isInstalled(feature)) {
+            if (feature != null && featuresService.isInstalled(feature)) {
                 featuresService.uninstallFeature(name);
+            } else if (feature == null) {
+                log.warn("Feature {} not found", name);
             }
         }
     }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java b/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java
index 7e7ec06..4910ce4 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/app/GossipApplicationStore.java
@@ -85,6 +85,8 @@
 public class GossipApplicationStore extends ApplicationArchive
         implements ApplicationStore {
 
+    private static final int MAX_LOAD_RETRIES = 3;
+
     private final Logger log = getLogger(getClass());
 
     private static final MessageSubject APP_BITS_REQUEST = new MessageSubject("app-bits-request");
@@ -163,10 +165,16 @@
      */
     private void loadFromDisk() {
         for (String name : getApplicationNames()) {
-            Application app = create(getApplicationDescription(name), false);
-            if (app != null && isActive(app.id().name())) {
-                activate(app.id(), false);
-                // load app permissions
+            for (int i = 0; i < MAX_LOAD_RETRIES; i++) {
+                try {
+                    Application app = create(getApplicationDescription(name), false);
+                    if (app != null && isActive(app.id().name())) {
+                        activate(app.id(), false);
+                        // load app permissions
+                    }
+                } catch (Exception e) {
+                    log.warn("Unable to load application {} from disk; retrying", name);
+                }
             }
         }
     }