1. Refactored ConsistentMap and StorageServive (renamed from DatabaseService) to api bundle.
2. Misc bug fixes uncovered during testing

Change-Id: I1219c5264831bcfa93565f764511f89de35a949d
diff --git a/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java b/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java
new file mode 100644
index 0000000..cf90ab0
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java
@@ -0,0 +1,200 @@
+package org.onosproject.store.service;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * A distributed, strongly consistent map.
+ * <p>
+ * This map offers strong read-after-update (where update == create/update/delete)
+ * consistency. All operations to the map are serialized and applied in a consistent
+ * manner.
+ * <p>
+ * The stronger consistency comes at the expense of availability in
+ * the event of a network partition. A network partition can be either due to
+ * a temporary disruption in network connectivity between participating nodes
+ * or due to a node being temporarily down.
+ * </p><p>
+ * All values stored in this map are versioned and the API supports optimistic
+ * concurrency by allowing conditional updates that take into consideration
+ * the version or value that was previously read.
+ * </p><p>
+ * The map also supports atomic batch updates (transactions). One can provide a list
+ * of updates to be applied atomically if and only if all the operations are guaranteed
+ * to succeed i.e. all their preconditions are met. For example, the precondition
+ * for a putIfAbsent API call is absence of a mapping for the key. Similarly, the
+ * precondition for a conditional replace operation is the presence of an expected
+ * version or value
+ * </p><p>
+ * This map does not allow null values. All methods can throw a ConsistentMapException
+ * (which extends RuntimeException) to indicate failures.
+ *
+ */
+public interface ConsistentMap<K, V> {
+
+    /**
+     * Returns the number of entries in the map.
+     *
+     * @return map size.
+     */
+    int size();
+
+    /**
+     * Returns true if the map is empty.
+     *
+     * @return true if map has no entries, false otherwise.
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns true if this map contains a mapping for the specified key.
+     *
+     * @param key key
+     * @return true if map contains key, false otherwise.
+     */
+    boolean containsKey(K key);
+
+    /**
+     * Returns true if this map contains the specified value.
+     *
+     * @param value value
+     * @return true if map contains value, false otherwise.
+     */
+    boolean containsValue(V value);
+
+    /**
+     * Returns the value (and version) to which the specified key is mapped, or null if this
+     * map contains no mapping for the key.
+     *
+     * @param key the key whose associated value (and version) is to be returned
+     * @return the value (and version) to which the specified key is mapped, or null if
+     * this map contains no mapping for the key
+     */
+    Versioned<V> get(K key);
+
+    /**
+     * Associates the specified value with the specified key in this map (optional operation).
+     * If the map previously contained a mapping for the key, the old value is replaced by the
+     * specified value.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value (and version) associated with key, or null if there was
+     * no mapping for key.
+     */
+    Versioned<V> put(K key, V value);
+
+    /**
+     * Removes the mapping for a key from this map if it is present (optional operation).
+     *
+     * @param key key whose value is to be removed from the map
+     * @return the value (and version) to which this map previously associated the key,
+     * or null if the map contained no mapping for the key.
+     */
+    Versioned<V> remove(K key);
+
+    /**
+     * Removes all of the mappings from this map (optional operation).
+     * The map will be empty after this call returns.
+     */
+    void clear();
+
+    /**
+     * Returns a Set view of the keys contained in this map.
+     * This method differs from the behavior of java.util.Map.keySet() in that
+     * what is returned is a unmodifiable snapshot view of the keys in the ConsistentMap.
+     * Attempts to modify the returned set, whether direct or via its iterator,
+     * result in an UnsupportedOperationException.
+     *
+     * @return a set of the keys contained in this map
+     */
+    Set<K> keySet();
+
+    /**
+     * Returns the collection of values (and associated versions) contained in this map.
+     * This method differs from the behavior of java.util.Map.values() in that
+     * what is returned is a unmodifiable snapshot view of the values in the ConsistentMap.
+     * Attempts to modify the returned collection, whether direct or via its iterator,
+     * result in an UnsupportedOperationException.
+     *
+     * @return a collection of the values (and associated versions) contained in this map
+     */
+    Collection<Versioned<V>> values();
+
+    /**
+     * Returns the set of entries contained in this map.
+     * This method differs from the behavior of java.util.Map.entrySet() in that
+     * what is returned is a unmodifiable snapshot view of the entries in the ConsistentMap.
+     * Attempts to modify the returned set, whether direct or via its iterator,
+     * result in an UnsupportedOperationException.
+     *
+     * @return set of entries contained in this map.
+     */
+    Set<Entry<K, Versioned<V>>> entrySet();
+
+    /**
+     * If the specified key is not already associated with a value
+     * associates it with the given value and returns null, else returns the current value.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key or null
+     * if key does not already mapped to a value.
+     */
+    Versioned<V> putIfAbsent(K key, V value);
+
+    /**
+     * Removes the entry for the specified key only if it is currently
+     * mapped to the specified value.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value expected to be associated with the specified key
+     * @return true if the value was removed
+     */
+    boolean remove(K key, V value);
+
+    /**
+     * Removes the entry for the specified key only if its current
+     * version in the map is equal to the specified version.
+     *
+     * @param key key with which the specified version is associated
+     * @param version version expected to be associated with the specified key
+     * @return true if the value was removed
+     */
+    boolean remove(K key, long version);
+
+    /**
+     * Replaces the entry for the specified key only if currently mapped
+     * to the specified value.
+     *
+     * @param key key with which the specified value is associated
+     * @param oldValue value expected to be associated with the specified key
+     * @param newValue value to be associated with the specified key
+     * @return true if the value was replaced
+     */
+    boolean replace(K key, V oldValue, V newValue);
+
+    /**
+     * Replaces the entry for the specified key only if it is currently mapped to the
+     * specified version.
+     *
+     * @param key key key with which the specified value is associated
+     * @param oldVersion version expected to be associated with the specified key
+     * @param newValue value to be associated with the specified key
+     * @return true if the value was replaced
+     */
+    boolean replace(K key, long oldVersion, V newValue);
+
+    /**
+     * Atomically apply the specified list of updates to the map.
+     * If any of the updates cannot be applied due to a precondition
+     * violation, none of the updates will be applied and the state of
+     * the map remains unaltered.
+     *
+     * @param updates list of updates to apply atomically.
+     * @return true if the map was updated.
+     */
+    boolean batchUpdate(List<UpdateOperation<K, V>> updates);
+}
diff --git a/core/api/src/main/java/org/onosproject/store/service/ConsistentMapException.java b/core/api/src/main/java/org/onosproject/store/service/ConsistentMapException.java
new file mode 100644
index 0000000..2ba4dee
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/store/service/ConsistentMapException.java
@@ -0,0 +1,26 @@
+package org.onosproject.store.service;
+
+/**
+ * Top level exception for ConsistentMap failures.
+ */
+@SuppressWarnings("serial")
+public class ConsistentMapException extends RuntimeException {
+    public ConsistentMapException() {
+    }
+
+    public ConsistentMapException(Throwable t) {
+        super(t);
+    }
+
+    /**
+     * ConsistentMap operation timeout.
+     */
+    public static class Timeout extends ConsistentMapException {
+    }
+
+    /**
+     * ConsistentMap operation interrupted.
+     */
+    public static class Interrupted extends ConsistentMapException {
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/store/service/Serializer.java b/core/api/src/main/java/org/onosproject/store/service/Serializer.java
new file mode 100644
index 0000000..f43090f
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/store/service/Serializer.java
@@ -0,0 +1,22 @@
+package org.onosproject.store.service;
+
+/**
+ * Interface for serialization for store artifacts.
+ */
+public interface Serializer {
+    /**
+     * Serialize the specified object.
+     * @param object object to serialize.
+     * @return serialized bytes.
+     * @param <T> encoded type
+     */
+    <T> byte[] encode(T object);
+
+    /**
+     * Deserialize the specified bytes.
+     * @param bytes byte array to deserialize.
+     * @return deserialized object.
+     * @param <T> decoded type
+     */
+    <T> T decode(byte[] bytes);
+}
\ 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
new file mode 100644
index 0000000..cfae271
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/store/service/StorageService.java
@@ -0,0 +1,27 @@
+package org.onosproject.store.service;
+
+/**
+ * Storage service.
+ * <p>
+ * This service provides operations for creating key-value stores.
+ * One can chose to create key-value stores with varying properties such
+ * as strongly consistent vs eventually consistent, durable vs volatile.
+ * <p>
+ * Various store implementations should leverage the data structures provided
+ * by this service
+ */
+public interface StorageService {
+
+    /**
+     * Creates a ConsistentMap.
+     *
+     * @param name map name
+     * @param serializer serializer to use for serializing keys and values.
+     * @return consistent map.
+     * @param <K> key type
+     * @param <V> value type
+     */
+    <K, V> ConsistentMap<K , V> createConsistentMap(String name, Serializer serializer);
+
+    // TODO: add API for creating Eventually Consistent Map.
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onosproject/store/service/UpdateOperation.java b/core/api/src/main/java/org/onosproject/store/service/UpdateOperation.java
new file mode 100644
index 0000000..224efbe
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/store/service/UpdateOperation.java
@@ -0,0 +1,182 @@
+package org.onosproject.store.service;
+
+import static com.google.common.base.Preconditions.*;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Database update operation.
+ *
+ * @param <K> key type.
+ * @param <V> value type.
+ */
+public class UpdateOperation<K, V> {
+
+    /**
+     * Type of database update operation.
+     */
+    public static enum Type {
+        PUT,
+        PUT_IF_ABSENT,
+        PUT_IF_VERSION_MATCH,
+        PUT_IF_VALUE_MATCH,
+        REMOVE,
+        REMOVE_IF_VERSION_MATCH,
+        REMOVE_IF_VALUE_MATCH,
+    }
+
+    private Type type;
+    private String tableName;
+    private K key;
+    private V value;
+    private V currentValue;
+    private long currentVersion = -1;
+
+    /**
+     * Returns the type of update operation.
+     * @return type of update.
+     */
+    public Type type() {
+        return type;
+    }
+
+    /**
+     * Returns the tableName being updated.
+     * @return table name.
+     */
+    public String tableName() {
+        return tableName;
+    }
+
+    /**
+     * Returns the item key being updated.
+     * @return item key
+     */
+    public K key() {
+        return key;
+    }
+
+    /**
+     * Returns the new value.
+     * @return item's target value.
+     */
+    public V value() {
+        return value;
+    }
+
+    /**
+     * Returns the expected current value in the database value for the key.
+     * @return current value in database.
+     */
+    public V currentValue() {
+        return currentValue;
+    }
+
+    /**
+     * Returns the expected current version in the database for the key.
+     * @return expected version.
+     */
+    public long currentVersion() {
+        return currentVersion;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("type", type)
+            .add("tableName", tableName)
+            .add("key", key)
+            .add("value", value)
+            .add("currentValue", currentValue)
+            .add("currentVersion", currentVersion)
+            .toString();
+    }
+
+    /**
+     * Creates a new builder instance.
+     * @param <K> key type.
+     * @param <V> value type.
+     *
+     * @return builder.
+     */
+    public static <K, V> Builder<K, V> newBuilder() {
+        return new Builder<>();
+    }
+
+    /**
+     * UpdatOperation builder.
+     *
+     * @param <K> key type.
+     * @param <V> value type.
+     */
+    public static final class Builder<K, V> {
+
+        private UpdateOperation<K, V> operation = new UpdateOperation<>();
+
+        public UpdateOperation<K, V> build() {
+            validateInputs();
+            return operation;
+        }
+
+        public Builder<K, V> withType(Type type) {
+            operation.type = checkNotNull(type, "type cannot be null");
+            return this;
+        }
+
+        public Builder<K, V> withTableName(String tableName) {
+            operation.tableName = checkNotNull(tableName, "tableName cannot be null");
+            return this;
+        }
+
+        public Builder<K, V> withKey(K key) {
+            operation.key = checkNotNull(key, "key cannot be null");
+            return this;
+        }
+
+        public Builder<K, V> withCurrentValue(V value) {
+            operation.currentValue = checkNotNull(value, "currentValue cannot be null");
+            return this;
+        }
+
+        public Builder<K, V> withValue(V value) {
+            operation.value = checkNotNull(value, "value cannot be null");
+            return this;
+        }
+
+        public Builder<K, V> withCurrentVersion(long version) {
+            checkArgument(version >= 0, "version cannot be negative");
+            operation.currentVersion = version;
+            return this;
+        }
+
+        private void validateInputs() {
+            checkNotNull(operation.type, "type must be specified");
+            checkNotNull(operation.tableName, "table name must be specified");
+            checkNotNull(operation.key, "key must be specified");
+            switch (operation.type) {
+            case PUT:
+            case PUT_IF_ABSENT:
+                checkNotNull(operation.value, "value must be specified.");
+                break;
+            case PUT_IF_VERSION_MATCH:
+                checkNotNull(operation.value, "value must be specified.");
+                checkState(operation.currentVersion >= 0, "current version must be specified");
+                break;
+            case PUT_IF_VALUE_MATCH:
+                checkNotNull(operation.value, "value must be specified.");
+                checkNotNull(operation.currentValue, "currentValue must be specified.");
+                break;
+            case REMOVE:
+                break;
+            case REMOVE_IF_VERSION_MATCH:
+                checkState(operation.currentVersion >= 0, "current version must be specified");
+                break;
+            case REMOVE_IF_VALUE_MATCH:
+                checkNotNull(operation.currentValue, "currentValue must be specified.");
+                break;
+            default:
+                throw new IllegalStateException("Unknown operation type");
+            }
+        }
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/store/service/Versioned.java b/core/api/src/main/java/org/onosproject/store/service/Versioned.java
new file mode 100644
index 0000000..2026437
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/store/service/Versioned.java
@@ -0,0 +1,50 @@
+package org.onosproject.store.service;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Versioned value.
+ *
+ * @param <V> value type.
+ */
+public class Versioned<V> {
+
+    private final V value;
+    private final long version;
+
+    /**
+     * Constructs a new versioned value.
+     * @param value value
+     * @param version version
+     */
+    public Versioned(V value, long version) {
+        this.value = value;
+        this.version = version;
+    }
+
+    /**
+     * Returns the value.
+     *
+     * @return value.
+     */
+    public V value() {
+        return value;
+    }
+
+    /**
+     * Returns the version.
+     *
+     * @return version
+     */
+    public long version() {
+        return version;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+            .add("value", value)
+            .add("version", version)
+            .toString();
+    }
+}