[ONOS-6324] Add getOrDefault method to ConsistentMap.

Change-Id: Ice7ad6260c6eb8076320ef469874c0c4ceeadc19
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncConsistentMap.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncConsistentMap.java
index ce725e24..2f4a665 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncConsistentMap.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncConsistentMap.java
@@ -83,6 +83,11 @@
     }
 
     @Override
+    public CompletableFuture<Versioned<V>> getOrDefault(K key, V defaultValue) {
+        return delegateMap.getOrDefault(key, defaultValue);
+    }
+
+    @Override
     public CompletableFuture<Versioned<V>> computeIf(K key,
             Predicate<? super V> condition,
             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncConsistentTreeMap.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncConsistentTreeMap.java
index 31d5f8e..48c0b85 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncConsistentTreeMap.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/DelegatingAsyncConsistentTreeMap.java
@@ -160,6 +160,11 @@
     }
 
     @Override
+    public CompletableFuture<Versioned<V>> getOrDefault(String key, V defaultValue) {
+        return delegateMap.getOrDefault(key, defaultValue);
+    }
+
+    @Override
     public CompletableFuture<Versioned<V>> computeIf(
             String key,
             Predicate<? super V> condition,
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/PartitionedAsyncConsistentMap.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/PartitionedAsyncConsistentMap.java
index 6378024..9adcb33 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/PartitionedAsyncConsistentMap.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/PartitionedAsyncConsistentMap.java
@@ -94,12 +94,18 @@
                             Match.ifValue(true),
                             false);
     }
+
     @Override
     public CompletableFuture<Versioned<V>> get(K key) {
         return getMap(key).get(key);
     }
 
     @Override
+    public CompletableFuture<Versioned<V>> getOrDefault(K key, V defaultValue) {
+        return getMap(key).getOrDefault(key, defaultValue);
+    }
+
+    @Override
     public CompletableFuture<Versioned<V>> computeIf(K key,
             Predicate<? super V> condition,
             BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/TranscodingAsyncConsistentMap.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/TranscodingAsyncConsistentMap.java
index f3938ce..2afb5df 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/TranscodingAsyncConsistentMap.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/TranscodingAsyncConsistentMap.java
@@ -109,6 +109,16 @@
     }
 
     @Override
+    public CompletableFuture<Versioned<V1>> getOrDefault(K1 key, V1 defaultValue) {
+        try {
+            return backingMap.getOrDefault(keyEncoder.apply(key), valueEncoder.apply(defaultValue))
+                    .thenApply(versionedValueTransform);
+        } catch (Exception e) {
+            return Tools.exceptionalFuture(e);
+        }
+    }
+
+    @Override
     public CompletableFuture<Versioned<V1>> computeIf(K1 key,
             Predicate<? super V1> condition,
             BiFunction<? super K1, ? super V1, ? extends V1> remappingFunction) {
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/TranscodingAsyncConsistentTreeMap.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/TranscodingAsyncConsistentTreeMap.java
index e7d86ff..747008f 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/TranscodingAsyncConsistentTreeMap.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/impl/TranscodingAsyncConsistentTreeMap.java
@@ -66,6 +66,7 @@
         this.versionedValueTransform = v -> v == null ? null :
                 v.map(valueDecoder);
     }
+
     @Override
     public CompletableFuture<String> firstKey() {
         return backingMap.firstKey();
@@ -226,6 +227,11 @@
     }
 
     @Override
+    public CompletableFuture<Versioned<V1>> getOrDefault(String key, V1 defaultValue) {
+        return backingMap.getOrDefault(key, valueEncoder.apply(defaultValue)).thenApply(versionedValueTransform);
+    }
+
+    @Override
     public CompletableFuture<Versioned<V1>> computeIf(
             String key, Predicate<? super V1> condition,
             BiFunction<? super String, ? super V1, ? extends V1>
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMap.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMap.java
index df567d2..afa67f5 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMap.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMap.java
@@ -42,6 +42,7 @@
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.ContainsValue;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.EntrySet;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.Get;
+import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.GetOrDefault;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.IsEmpty;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.KeySet;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.Listen;
@@ -128,6 +129,11 @@
     }
 
     @Override
+    public CompletableFuture<Versioned<byte[]>> getOrDefault(String key, byte[] defaultValue) {
+        return client.submit(new GetOrDefault(key, defaultValue));
+    }
+
+    @Override
     public CompletableFuture<Set<String>> keySet() {
         return client.submit(new KeySet());
     }
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapCommands.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapCommands.java
index eb9e158..20b13f1 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapCommands.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapCommands.java
@@ -454,6 +454,43 @@
     }
 
     /**
+     * Get or default query.
+     */
+    @SuppressWarnings("serial")
+    public static class GetOrDefault extends KeyQuery<Versioned<byte[]>> {
+        private byte[] defaultValue;
+
+        public GetOrDefault() {
+        }
+
+        public GetOrDefault(String key, byte[] defaultValue) {
+            super(key);
+            this.defaultValue = defaultValue;
+        }
+
+        /**
+         * Returns the default value.
+         *
+         * @return the default value
+         */
+        public byte[] defaultValue() {
+            return defaultValue;
+        }
+
+        @Override
+        public void writeObject(BufferOutput<?> buffer, Serializer serializer) {
+            super.writeObject(buffer, serializer);
+            serializer.writeObject(defaultValue, buffer);
+        }
+
+        @Override
+        public void readObject(BufferInput<?> buffer, Serializer serializer) {
+            super.readObject(buffer, serializer);
+            defaultValue = serializer.readObject(buffer);
+        }
+    }
+
+    /**
      * Is empty query.
      */
     @SuppressWarnings("serial")
@@ -546,6 +583,7 @@
             registry.register(ContainsKey.class, -761);
             registry.register(ContainsValue.class, -762);
             registry.register(Get.class, -763);
+            registry.register(GetOrDefault.class, -778);
             registry.register(EntrySet.class, -764);
             registry.register(Values.class, -765);
             registry.register(KeySet.class, -766);
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapState.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapState.java
index a6473ae..3a99b02 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapState.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapState.java
@@ -47,6 +47,7 @@
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.ContainsValue;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.EntrySet;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.Get;
+import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.GetOrDefault;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.IsEmpty;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.KeySet;
 import org.onosproject.store.primitives.resources.impl.AtomixConsistentMapCommands.Listen;
@@ -101,6 +102,7 @@
         executor.register(ContainsValue.class, this::containsValue);
         executor.register(EntrySet.class, this::entrySet);
         executor.register(Get.class, this::get);
+        executor.register(GetOrDefault.class, this::getOrDefault);
         executor.register(IsEmpty.class, this::isEmpty);
         executor.register(KeySet.class, this::keySet);
         executor.register(Size.class, this::size);
@@ -159,8 +161,7 @@
     /**
      * Handles a get commit.
      *
-     * @param commit
-     *            get commit
+     * @param commit get commit
      * @return value mapped to key
      */
     protected Versioned<byte[]> get(Commit<? extends Get> commit) {
@@ -172,6 +173,21 @@
     }
 
     /**
+     * Handles a get or default commit.
+     *
+     * @param commit get or default commit
+     * @return value mapped to key
+     */
+    protected Versioned<byte[]> getOrDefault(Commit<? extends GetOrDefault> commit) {
+        try {
+            Versioned<byte[]> value = toVersioned(mapEntries.get(commit.operation().key()));
+            return value != null ? value : new Versioned<>(commit.operation().defaultValue(), 0);
+        } finally {
+            commit.close();
+        }
+    }
+
+    /**
      * Handles a count commit.
      *
      * @param commit size commit
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMap.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMap.java
index 8dde3148..3dd34fd 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMap.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMap.java
@@ -56,6 +56,7 @@
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.FirstEntry;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.FloorKey;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.Get;
+import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.GetOrDefault;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.HigherKey;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.IsEmpty;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.KeySet;
@@ -131,6 +132,11 @@
     }
 
     @Override
+    public CompletableFuture<Versioned<byte[]>> getOrDefault(String key, byte[] defaultValue) {
+        return client.submit(new GetOrDefault(key, defaultValue));
+    }
+
+    @Override
     public CompletableFuture<Set<String>> keySet() {
         return client.submit(new KeySet());
     }
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapCommands.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapCommands.java
index 231915d..59cf1a5 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapCommands.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapCommands.java
@@ -277,7 +277,7 @@
     }
 
     /**
-     * Get query command.
+     * Get query.
      */
     @SuppressWarnings("serial")
     public static class Get extends KeyQuery<Versioned<byte[]>> {
@@ -290,6 +290,43 @@
     }
 
     /**
+     * Get or default query.
+     */
+    @SuppressWarnings("serial")
+    public static class GetOrDefault extends KeyQuery<Versioned<byte[]>> {
+        private byte[] defaultValue;
+
+        public GetOrDefault() {
+        }
+
+        public GetOrDefault(String key, byte[] defaultValue) {
+            super(key);
+            this.defaultValue = defaultValue;
+        }
+
+        /**
+         * Returns the default value.
+         *
+         * @return the default value
+         */
+        public byte[] defaultValue() {
+            return defaultValue;
+        }
+
+        @Override
+        public void writeObject(BufferOutput<?> buffer, Serializer serializer) {
+            super.writeObject(buffer, serializer);
+            serializer.writeObject(defaultValue, buffer);
+        }
+
+        @Override
+        public void readObject(BufferInput<?> buffer, Serializer serializer) {
+            super.readObject(buffer, serializer);
+            defaultValue = serializer.readObject(buffer);
+        }
+    }
+
+    /**
      * Is empty query.
      */
     @SuppressWarnings("serial")
@@ -630,6 +667,7 @@
             registry.register(ContainsKey.class, -1161);
             registry.register(ContainsValue.class, -1162);
             registry.register(Get.class, -1163);
+            registry.register(GetOrDefault.class, -1192);
             registry.register(EntrySet.class, -1164);
             registry.register(Values.class, -1165);
             registry.register(KeySet.class, -1166);
diff --git a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapState.java b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapState.java
index e70e0e6..e7c9118 100644
--- a/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapState.java
+++ b/core/store/primitives/src/main/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapState.java
@@ -55,6 +55,7 @@
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.FloorEntry;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.FloorKey;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.Get;
+import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.GetOrDefault;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.HigherEntry;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.HigherKey;
 import static org.onosproject.store.primitives.resources.impl.AtomixConsistentTreeMapCommands.IsEmpty;
@@ -133,6 +134,7 @@
         executor.register(ContainsValue.class, this::containsValue);
         executor.register(EntrySet.class, this::entrySet);
         executor.register(Get.class, this::get);
+        executor.register(GetOrDefault.class, this::getOrDefault);
         executor.register(IsEmpty.class, this::isEmpty);
         executor.register(KeySet.class, this::keySet);
         executor.register(Size.class, this::size);
@@ -193,6 +195,15 @@
         }
     }
 
+    protected Versioned<byte[]> getOrDefault(Commit<? extends GetOrDefault> commit) {
+        try {
+            Versioned<byte[]> value = toVersioned(tree.get(commit.operation().key()));
+            return value != null ? value : new Versioned<>(commit.operation().defaultValue(), 0);
+        } finally {
+            commit.close();
+        }
+    }
+
     protected int size(Commit<? extends Size> commit) {
         try {
             return tree.size();