Using provider pattern for cluster metadata.

Change-Id: I5a572b3df9149be959dde9868a9c594dec26a3e0
diff --git a/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java
index f0334aa..63a04d1 100644
--- a/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java
+++ b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadata.java
@@ -20,10 +20,10 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 
-import org.apache.commons.collections.CollectionUtils;
+import org.onosproject.net.Provided;
+import org.onosproject.net.provider.ProviderId;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Verify.verifyNotNull;
 import static com.google.common.base.Verify.verify;
 
 import com.google.common.base.MoreObjects;
@@ -38,21 +38,49 @@
  * of {@link org.onosproject.cluster.ControllerNode nodes} and the collection of data
  * {@link org.onosproject.cluster.Partition partitions}.
  */
-public final class ClusterMetadata {
+public final class ClusterMetadata implements Provided {
 
     // Name to use when the ClusterMetadataService is in transient state
     public static final String NO_NAME = "";
 
-    private String name;
-    private Set<ControllerNode> nodes;
-    private Set<Partition> partitions;
+    private final ProviderId providerId;
+    private final String name;
+    private final Set<ControllerNode> nodes;
+    private final Set<Partition> partitions;
 
-    /**
-     * Returns a new cluster metadata builder.
-     * @return The cluster metadata builder.
-     */
-    public static Builder builder() {
-        return new Builder();
+    private ClusterMetadata() {
+        providerId = null;
+        name = null;
+        nodes = null;
+        partitions = null;
+    }
+
+    public ClusterMetadata(ProviderId providerId,
+            String name,
+            Set<ControllerNode> nodes,
+            Set<Partition> partitions) {
+        this.providerId = checkNotNull(providerId);
+        this.name = checkNotNull(name);
+        this.nodes = ImmutableSet.copyOf(checkNotNull(nodes));
+        // verify that partitions are constituted from valid cluster nodes.
+        boolean validPartitions = Collections2.transform(nodes, ControllerNode::id)
+                .containsAll(partitions
+                        .stream()
+                        .flatMap(r -> r.getMembers().stream())
+                        .collect(Collectors.toSet()));
+        verify(validPartitions, "Partition locations must be valid cluster nodes");
+        this.partitions = ImmutableSet.copyOf(checkNotNull(partitions));
+    }
+
+    public ClusterMetadata(String name,
+            Set<ControllerNode> nodes,
+            Set<Partition> partitions) {
+        this(new ProviderId("none", "none"), name, nodes, partitions);
+    }
+
+    @Override
+    public ProviderId providerId() {
+        return providerId;
     }
 
     /**
@@ -84,6 +112,7 @@
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(ClusterMetadata.class)
+                .add("providerId", providerId)
                 .add("name", name)
                 .add("nodes", nodes)
                 .add("partitions", partitions)
@@ -92,7 +121,7 @@
 
     @Override
     public int hashCode() {
-        return Arrays.deepHashCode(new Object[] {name, nodes, partitions});
+        return Arrays.deepHashCode(new Object[] {providerId, name, nodes, partitions});
     }
 
     /*
@@ -116,74 +145,4 @@
         return Sets.symmetricDifference(this.nodes, that.nodes).isEmpty()
                 && Sets.symmetricDifference(this.partitions, that.partitions).isEmpty();
     }
-
-    /**
-     * Builder for a {@link ClusterMetadata} instance.
-     */
-    public static class Builder {
-
-        private final ClusterMetadata metadata;
-
-        public Builder() {
-            metadata = new ClusterMetadata();
-        }
-
-        /**
-         * Sets the cluster name, returning the cluster metadata builder for method chaining.
-         * @param name cluster name
-         * @return this cluster metadata builder
-         */
-        public Builder withName(String name) {
-            metadata.name = checkNotNull(name);
-            return this;
-        }
-
-        /**
-         * Sets the collection of cluster nodes, returning the cluster metadata builder for method chaining.
-         * @param controllerNodes collection of cluster nodes
-         * @return this cluster metadata builder
-         */
-        public Builder withControllerNodes(Collection<ControllerNode> controllerNodes) {
-            metadata.nodes = ImmutableSet.copyOf(checkNotNull(controllerNodes));
-            return this;
-        }
-
-        /**
-         * Sets the partitions, returning the cluster metadata builder for method chaining.
-         * @param partitions collection of partitions
-         * @return this cluster metadata builder
-         */
-        public Builder withPartitions(Collection<Partition> partitions) {
-            metadata.partitions = ImmutableSet.copyOf(checkNotNull(partitions));
-            return this;
-        }
-
-        /**
-         * Builds the cluster metadata.
-         * @return cluster metadata
-         * @throws com.google.common.base.VerifyException VerifyException if the metadata is misconfigured
-         */
-        public ClusterMetadata build() {
-            verifyMetadata();
-            return metadata;
-        }
-
-        /**
-         * Validates the constructed metadata for semantic correctness.
-         * @throws VerifyException if the metadata is misconfigured.
-         */
-        private void verifyMetadata() {
-            verifyNotNull(metadata.getName(), "Cluster name must be specified");
-            verify(CollectionUtils.isNotEmpty(metadata.getNodes()), "Cluster nodes must be specified");
-            verify(CollectionUtils.isNotEmpty(metadata.getPartitions()), "Cluster partitions must be specified");
-
-            // verify that partitions are constituted from valid cluster nodes.
-            boolean validPartitions = Collections2.transform(metadata.getNodes(), ControllerNode::id)
-                    .containsAll(metadata.getPartitions()
-                            .stream()
-                            .flatMap(r -> r.getMembers().stream())
-                            .collect(Collectors.toSet()));
-            verify(validPartitions, "Partition locations must be valid cluster nodes");
-        }
-    }
 }
diff --git a/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataProvider.java
similarity index 74%
rename from core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java
rename to core/api/src/main/java/org/onosproject/cluster/ClusterMetadataProvider.java
index 99361d8..5d9afd7 100644
--- a/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStore.java
+++ b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataProvider.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Open Networking Laboratory
+ * Copyright 2015-2016 Open Networking Laboratory
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,27 +15,31 @@
  */
 package org.onosproject.cluster;
 
-import java.util.Collection;
+import java.util.Set;
 
-import org.onosproject.store.Store;
+import org.onosproject.net.provider.Provider;
 import org.onosproject.store.service.Versioned;
 
 /**
- * Manages persistence of {@link ClusterMetadata cluster metadata}; not intended for direct use.
+ * Abstraction of a {@link ClusterMetadata cluster metadata} provider.
  */
-public interface ClusterMetadataStore extends Store<ClusterMetadataEvent, ClusterMetadataStoreDelegate> {
+public interface ClusterMetadataProvider extends Provider {
 
     /**
-     * Returns the cluster metadata.
-     * <p>
-     * The retuned metadata is encapsulated as a {@link Versioned versioned} and therefore has a specific version.
+     * Tells if this provider is currently available and therefore can provide ClusterMetadata.
+     * @return {@code true} if this provider is available and can provide cluster metadata.
+     */
+    boolean isAvailable();
+
+    /**
+     * Returns the current cluster metadata.
      * @return cluster metadata
      */
     Versioned<ClusterMetadata> getClusterMetadata();
 
     /**
-     * Updates the cluster metadata.
-     * @param metadata new metadata value
+     * Updates cluster metadata.
+     * @param metadata new metadata
      */
     void setClusterMetadata(ClusterMetadata metadata);
 
@@ -54,12 +58,12 @@
     /**
      * Removes a controller node from the list of active members for a partition.
      * @param partitionId partition identifier
-     * @param nodeId id of controller node
+     * @param nodeId identifier of controller node
      */
     void removeActivePartitionMember(PartitionId partitionId, NodeId nodeId);
 
     /**
-     * Returns the collection of controller nodes that are the active members for a partition.
+     * Returns the set of controller nodes that are the active members for a partition.
      * <p>
      * Active members of a partition are typically those that are actively
      * participating in the data replication protocol being employed. When
@@ -72,5 +76,5 @@
      * @param partitionId partition identifier
      * @return identifiers of controller nodes that are active members
      */
-    Collection<NodeId> getActivePartitionMembers(PartitionId partitionId);
-}
\ No newline at end of file
+    Set<NodeId> getActivePartitionMembers(PartitionId partitionId);
+}
diff --git a/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataProviderRegistry.java
similarity index 67%
rename from core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java
rename to core/api/src/main/java/org/onosproject/cluster/ClusterMetadataProviderRegistry.java
index b56b7a2..f74e498 100644
--- a/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataStoreDelegate.java
+++ b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataProviderRegistry.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015 Open Networking Laboratory
+ * Copyright 2015-2016 Open Networking Laboratory
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,10 +15,11 @@
  */
 package org.onosproject.cluster;
 
-import org.onosproject.store.StoreDelegate;
+import org.onosproject.net.provider.ProviderRegistry;
 
 /**
- * Cluster metadata store delegate abstraction.
+ * Abstraction of a cluster metadata provider registry.
  */
-public interface ClusterMetadataStoreDelegate extends StoreDelegate<ClusterMetadataEvent> {
-}
\ No newline at end of file
+public interface ClusterMetadataProviderRegistry
+    extends ProviderRegistry<ClusterMetadataProvider, ClusterMetadataProviderService> {
+}
diff --git a/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataProviderService.java b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataProviderService.java
new file mode 100644
index 0000000..d8e15e6
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/cluster/ClusterMetadataProviderService.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015-2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cluster;
+
+import org.onosproject.net.provider.ProviderService;
+import org.onosproject.store.service.Versioned;
+
+/**
+ * Service through which a {@link ClusterMetadataProvider provider} can notify core of
+ * updates made to cluster metadata.
+ */
+public interface ClusterMetadataProviderService extends ProviderService<ClusterMetadataProvider> {
+
+    /**
+     * Notifies about a change to cluster metadata.
+     * @param newMetadata new cluster metadata value
+     */
+    void clusterMetadataChanged(Versioned<ClusterMetadata> newMetadata);
+
+    /**
+     * Notifies that a node just become the active member of a partition.
+     * @param partitionId partition identifier
+     * @param nodeId identifier of node
+     */
+    void newActiveMemberForPartition(PartitionId partitionId, NodeId nodeId);
+}
diff --git a/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderRegistry.java b/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderRegistry.java
index bcf5fae..73234d5 100644
--- a/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderRegistry.java
+++ b/core/api/src/main/java/org/onosproject/net/provider/AbstractProviderRegistry.java
@@ -108,4 +108,14 @@
         return providersByScheme.get(deviceId.uri().getScheme());
     }
 
+    /**
+     * Returns the provider registered with the specified scheme.
+     *
+     * @param scheme provider scheme
+     * @return provider
+     */
+    protected synchronized P getProvider(String scheme) {
+        return providersByScheme.get(scheme);
+    }
+
 }