Added support for a distributed set implementation that is backed by Consistent Map

Change-Id: Ic393d305d31abcdf1dd4c9afc3b9234f8d50da2d
diff --git a/core/api/src/main/java/org/onosproject/store/service/SetBuilder.java b/core/api/src/main/java/org/onosproject/store/service/SetBuilder.java
new file mode 100644
index 0000000..cd2e060
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/store/service/SetBuilder.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015 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.store.service;
+
+import java.util.Set;
+
+/**
+ * Builder for distributed set.
+ *
+ * @param <E> type set elements.
+ */
+public interface SetBuilder<E> {
+
+    /**
+     * Sets the name of the set.
+     * <p>
+     * Each set is identified by a unique name.
+     * </p>
+     * <p>
+     * Note: This is a mandatory parameter.
+     * </p>
+     *
+     * @param name name of the set
+     * @return this SetBuilder
+     */
+    public SetBuilder<E> withName(String name);
+
+    /**
+     * Sets a serializer that can be used to serialize
+     * the elements add to the set. The serializer
+     * builder should be pre-populated with any classes that will be
+     * put into the set.
+     * <p>
+     * Note: This is a mandatory parameter.
+     * </p>
+     *
+     * @param serializer serializer
+     * @return this SetBuilder
+     */
+    public SetBuilder<E> withSerializer(Serializer serializer);
+
+    /**
+     * Builds an set based on the configuration options
+     * supplied to this builder.
+     *
+     * @return new set
+     * @throws java.lang.RuntimeException if a mandatory parameter is missing
+     */
+    public Set<E> build();
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/store/service/StorageService.java b/core/api/src/main/java/org/onosproject/store/service/StorageService.java
index c8a394d..e165a95 100644
--- a/core/api/src/main/java/org/onosproject/store/service/StorageService.java
+++ b/core/api/src/main/java/org/onosproject/store/service/StorageService.java
@@ -52,4 +52,12 @@
      * @return builder for an eventually consistent map
      */
     <K, V> ConsistentMapBuilder<K, V> consistentMapBuilder();
+
+    /**
+     * Creates a new distributed set builder.
+     *
+     * @param <E> set element type
+     * @return builder for an distributed set
+     */
+    <E> SetBuilder<E> setBuilder();
 }
\ No newline at end of file
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
index 39d1bab..f0ff5c2 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+
 import net.kuujo.copycat.CopycatConfig;
 import net.kuujo.copycat.cluster.ClusterConfig;
 import net.kuujo.copycat.cluster.Member;
@@ -32,6 +33,7 @@
 import net.kuujo.copycat.protocol.Consistency;
 import net.kuujo.copycat.protocol.Protocol;
 import net.kuujo.copycat.util.concurrent.NamedThreadFactory;
+
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -48,6 +50,7 @@
 import org.onosproject.store.service.EventuallyConsistentMapBuilder;
 import org.onosproject.store.service.MapInfo;
 import org.onosproject.store.service.PartitionInfo;
+import org.onosproject.store.service.SetBuilder;
 import org.onosproject.store.service.StorageAdminService;
 import org.onosproject.store.service.StorageService;
 import org.onosproject.store.service.TransactionContext;
@@ -301,6 +304,11 @@
     }
 
     @Override
+    public <E> SetBuilder<E> setBuilder() {
+        return new DefaultSetBuilder<>(partitionedDatabase);
+    }
+
+    @Override
     public List<MapInfo> getMapInfo() {
         List<MapInfo> maps = Lists.newArrayList();
         maps.addAll(getMapInfo(inMemoryDatabase));
@@ -328,4 +336,4 @@
             throw new ConsistentMapException(e.getCause());
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDistributedSet.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDistributedSet.java
new file mode 100644
index 0000000..e6eac62
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDistributedSet.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2015 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.store.consistent.impl;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+
+import com.google.common.collect.Sets;
+
+/**
+ * Implementation of distributed set that is backed by a ConsistentMap.
+
+ * @param <E> set element type
+ */
+public class DefaultDistributedSet<E> implements Set<E> {
+
+    private final ConsistentMap<E, Boolean> backingMap;
+
+    public DefaultDistributedSet(String name, Database database, Serializer serializer) {
+        backingMap = new DefaultConsistentMap<>(name, database, serializer);
+    }
+
+    @Override
+    public int size() {
+        return backingMap.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return backingMap.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+        return backingMap.containsKey((E) o);
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return backingMap.keySet().iterator();
+    }
+
+    @Override
+    public Object[] toArray() {
+        return backingMap.keySet().stream().toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+        return backingMap.keySet().stream().toArray(size -> a);
+    }
+
+    @Override
+    public boolean add(E e) {
+        return backingMap.putIfAbsent(e, true) == null;
+    }
+
+    @Override
+    public boolean remove(Object o) {
+        return backingMap.remove((E) o, true);
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        return c.stream()
+                .allMatch(this::contains);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+        return c.stream()
+                .map(this::add)
+                .reduce(Boolean::logicalOr)
+                .orElse(false);
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        Set<?> retainSet = Sets.newHashSet(c);
+        return backingMap.keySet()
+                .stream()
+                .filter(k -> !retainSet.contains(k))
+                .map(this::remove)
+                .reduce(Boolean::logicalOr)
+                .orElse(false);
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        Set<?> removeSet = Sets.newHashSet(c);
+        return backingMap.keySet()
+            .stream()
+            .filter(removeSet::contains)
+            .map(this::remove)
+            .reduce(Boolean::logicalOr)
+            .orElse(false);
+    }
+
+    @Override
+    public void clear() {
+        backingMap.clear();
+    }
+}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultSetBuilder.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultSetBuilder.java
new file mode 100644
index 0000000..dfc9c40
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultSetBuilder.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 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.store.consistent.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Set;
+
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.SetBuilder;
+
+/**
+ * Default Set builder.
+ *
+ * @param <E> type for set elements
+ */
+public class DefaultSetBuilder<E> implements SetBuilder<E> {
+
+    private Serializer serializer;
+    private String name;
+    private final Database database;
+
+    public DefaultSetBuilder(Database database) {
+        this.database = checkNotNull(database);
+    }
+
+    @Override
+    public SetBuilder<E> withName(String name) {
+        checkArgument(name != null && !name.isEmpty());
+        this.name = name;
+        return this;
+    }
+
+    @Override
+    public SetBuilder<E> withSerializer(Serializer serializer) {
+        checkArgument(serializer != null);
+        this.serializer = serializer;
+        return this;
+    }
+
+    private boolean validInputs() {
+        return name != null && serializer != null;
+    }
+
+    @Override
+    public Set<E> build() {
+        checkState(validInputs());
+        return new DefaultDistributedSet<>(name, database, serializer);
+    }
+}