Fix race condition between AtomixManager and metadata providers startup

Change-Id: I4799c079455e0e5c79a800ba3108b4c9eedbe1b2
diff --git a/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java b/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java
index 3cf47ba..df77d09 100644
--- a/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java
+++ b/core/net/src/main/java/org/onosproject/cluster/impl/ClusterMetadataManager.java
@@ -15,8 +15,8 @@
  */
 package org.onosproject.cluster.impl;
 
+import com.google.common.collect.ImmutableList;
 import org.onlab.packet.IpAddress;
-import org.onlab.util.Tools;
 import org.onosproject.cluster.ClusterMetadata;
 import org.onosproject.cluster.ClusterMetadataAdminService;
 import org.onosproject.cluster.ClusterMetadataEvent;
@@ -31,10 +31,14 @@
 import org.onosproject.cluster.PartitionId;
 import org.onosproject.net.provider.AbstractListenerProviderRegistry;
 import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.store.atomix.ClusterActivator;
 import org.onosproject.store.service.Versioned;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
 import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
 import org.slf4j.Logger;
 
 import java.net.Inet4Address;
@@ -45,6 +49,9 @@
 import java.net.URL;
 import java.net.UnknownHostException;
 import java.util.Enumeration;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onosproject.security.AppGuard.checkPermission;
@@ -67,12 +74,16 @@
     private static final int MAX_WAIT_TRIES = 600;
     private static final int MAX_WAIT_MS = 100;
 
+    private List<String> requiredProviders = ImmutableList.of("file", "default");
+
     private final Logger log = getLogger(getClass());
     private ControllerNode localNode;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    private ClusterActivator clusterActivator;
+
     @Activate
     public void activate() {
-        // FIXME: Need to ensure all cluster metadata providers are registered before we activate
         eventDispatcher.addSink(ClusterMetadataEvent.class, listenerRegistry);
         log.info("Started");
     }
@@ -84,22 +95,22 @@
     }
 
     @Override
-    public ClusterMetadata getClusterMetadata() {
-        checkPermission(CLUSTER_READ);
-        waitForAvailableProvider();
-        Versioned<ClusterMetadata> metadata = getProvider().getClusterMetadata();
-        return metadata.value();
+    public synchronized ClusterMetadataProviderService register(ClusterMetadataProvider provider) {
+        ClusterMetadataProviderService s = super.register(provider);
+        Set<String> providerNames = getProviders().stream().map(ProviderId::scheme).collect(Collectors.toSet());
+        if (providerNames.containsAll(requiredProviders)) {
+            // Safe to release Atomix now, cluster metadata is ready
+            clusterActivator.activateCluster();
+        }
+        return s;
     }
 
-    // FIXME: Temporary hack to navigate around bootstrap timing issue
-    private void waitForAvailableProvider() {
-        for (int i = 0; i < MAX_WAIT_TRIES && getProvider() == null; i++) {
-            Tools.delay(MAX_WAIT_MS);
-        }
-        if (getProvider() == null) {
-            log.error("Unable to find cluster metadata provider");
-            throw new IllegalStateException("Unable to find cluster metadata provider");
-        }
+
+    @Override
+    public ClusterMetadata getClusterMetadata() {
+        checkPermission(CLUSTER_READ);
+        Versioned<ClusterMetadata> metadata = getProvider().getClusterMetadata();
+        return metadata.value();
     }
 
     @Override