[ONOS-6324] Add getOrDefault method to ConsistentMap.

Change-Id: Ice7ad6260c6eb8076320ef469874c0c4ceeadc19
diff --git a/core/api/src/main/java/org/onosproject/store/primitives/DefaultConsistentMap.java b/core/api/src/main/java/org/onosproject/store/primitives/DefaultConsistentMap.java
index 4b7b1a8..db6f548 100644
--- a/core/api/src/main/java/org/onosproject/store/primitives/DefaultConsistentMap.java
+++ b/core/api/src/main/java/org/onosproject/store/primitives/DefaultConsistentMap.java
@@ -86,6 +86,11 @@
     }
 
     @Override
+    public Versioned<V> getOrDefault(K key, V defaultValue) {
+        return complete(asyncMap.getOrDefault(key, defaultValue));
+    }
+
+    @Override
     public Versioned<V> computeIfAbsent(K key,
             Function<? super K, ? extends V> mappingFunction) {
         return computeIf(key, Objects::isNull, (k, v) -> mappingFunction.apply(k));
diff --git a/core/api/src/main/java/org/onosproject/store/primitives/DefaultConsistentTreeMap.java b/core/api/src/main/java/org/onosproject/store/primitives/DefaultConsistentTreeMap.java
index a38da9e..d98eb17 100644
--- a/core/api/src/main/java/org/onosproject/store/primitives/DefaultConsistentTreeMap.java
+++ b/core/api/src/main/java/org/onosproject/store/primitives/DefaultConsistentTreeMap.java
@@ -176,6 +176,11 @@
     }
 
     @Override
+    public Versioned<V> getOrDefault(String key, V defaultValue) {
+        return complete(treeMap.getOrDefault(key, defaultValue));
+    }
+
+    @Override
     public Versioned<V> computeIfAbsent(String key,
                                         Function<? super String,
                                                 ? extends V> mappingFunction) {
diff --git a/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java b/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java
index f25fadc..8bfd952 100644
--- a/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java
+++ b/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java
@@ -110,6 +110,17 @@
     CompletableFuture<Versioned<V>> get(K key);
 
     /**
+     * Returns the value (and version) to which the specified key is mapped, or the provided
+     * default value if this map contains no mapping for the key.
+     *
+     * @param key the key whose associated value (and version) is to be returned
+     * @param defaultValue the default value to return if the key is not set
+     * @return a future value (and version) to which the specified key is mapped, or null if
+     * this map contains no mapping for the key
+     */
+    CompletableFuture<Versioned<V>> getOrDefault(K key, V defaultValue);
+
+    /**
      * If the specified key is not already associated with a value (or is mapped to null),
      * attempts to compute its value using the given mapping function and enters it into
      * this map unless null.
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
index f5e8c13..3d14a68 100644
--- a/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java
+++ b/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java
@@ -77,6 +77,20 @@
     Versioned<V> get(K key);
 
     /**
+     * Returns the value (and version) to which the specified key is mapped, or the provided
+     * default value if this map contains no mapping for the key.
+     * <p>
+     * Note: a non-null {@link Versioned} value will be returned even if the {@code defaultValue}
+     * is {@code null}.
+     *
+     * @param key the key whose associated value (and version) is to be returned
+     * @param defaultValue the default value to return if the key is not set
+     * @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> getOrDefault(K key, V defaultValue);
+
+    /**
      * If the specified key is not already associated with a value (or is mapped to null),
      * attempts to compute its value using the given mapping function and enters it into
      * this map unless null.
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
index 6c6834e..7de5be7 100644
--- a/core/api/src/main/java/org/onosproject/store/service/Versioned.java
+++ b/core/api/src/main/java/org/onosproject/store/service/Versioned.java
@@ -97,7 +97,7 @@
      * @return mapped instance
      */
     public synchronized <U> Versioned<U> map(Function<V, U> transformer) {
-        return new Versioned<>(transformer.apply(value), version, creationTime);
+        return new Versioned<>(value != null ? transformer.apply(value) : null, version, creationTime);
     }
 
     /**
diff --git a/core/api/src/test/java/org/onosproject/store/service/AsyncConsistentMapAdapter.java b/core/api/src/test/java/org/onosproject/store/service/AsyncConsistentMapAdapter.java
index 4013458..c9161a3 100644
--- a/core/api/src/test/java/org/onosproject/store/service/AsyncConsistentMapAdapter.java
+++ b/core/api/src/test/java/org/onosproject/store/service/AsyncConsistentMapAdapter.java
@@ -56,6 +56,11 @@
     }
 
     @Override
+    public CompletableFuture<Versioned<V>> getOrDefault(K key, V defaultValue) {
+        return null;
+    }
+
+    @Override
     public CompletableFuture<Versioned<V>>
     computeIf(K key, Predicate<? super V> condition,
               BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
diff --git a/core/api/src/test/java/org/onosproject/store/service/ConsistentMapAdapter.java b/core/api/src/test/java/org/onosproject/store/service/ConsistentMapAdapter.java
index e6e71c2..4494db2 100644
--- a/core/api/src/test/java/org/onosproject/store/service/ConsistentMapAdapter.java
+++ b/core/api/src/test/java/org/onosproject/store/service/ConsistentMapAdapter.java
@@ -64,6 +64,11 @@
     }
 
     @Override
+    public Versioned<V> getOrDefault(K key, V defaultValue) {
+        return null;
+    }
+
+    @Override
     public Versioned<V> computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
         return null;
     }
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();
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapTest.java
index 5d4ef11..23d528b 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentMapTest.java
@@ -41,6 +41,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
@@ -117,6 +118,16 @@
             assertTrue(result);
         }).join();
 
+        map.getOrDefault("nothing", null).thenAccept(result -> {
+            assertEquals(0, result.version());
+            assertNull(result.value());
+        }).join();
+
+        map.getOrDefault("foo", "bar".getBytes()).thenAccept(result -> {
+            assertEquals(0, result.version());
+            assertArrayEquals("bar".getBytes(), result.value());
+        }).join();
+
         map.put("foo", rawFooValue).thenAccept(result -> {
             assertNull(result);
         }).join();
@@ -164,6 +175,11 @@
             assertTrue(Arrays.equals(Versioned.valueOrElse(result, null), rawFooValue));
         }).join();
 
+        map.getOrDefault("foo", "bar".getBytes()).thenAccept(result -> {
+            assertNotEquals(0, result.version());
+            assertArrayEquals(rawFooValue, result.value());
+        }).join();
+
         map.remove("foo").thenAccept(result -> {
             assertTrue(Arrays.equals(Versioned.valueOrElse(result, null), rawFooValue));
         }).join();
diff --git a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapTest.java b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapTest.java
index f27148e..bbaaf57 100644
--- a/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapTest.java
+++ b/core/store/primitives/src/test/java/org/onosproject/store/primitives/resources/impl/AtomixConsistentTreeMapTest.java
@@ -36,6 +36,7 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -89,115 +90,122 @@
         //test size
         map.size().thenAccept(result -> assertEquals(0, (int) result)).join();
         map.isEmpty().thenAccept(result -> assertTrue(result)).join();
+
         //test contains key
         allKeys.forEach(key -> map.containsKey(key).
                 thenAccept(result -> assertFalse(result)).join());
+
         //test contains value
         allValues.forEach(value -> map.containsValue(value)
                 .thenAccept(result -> assertFalse(result)).join());
+
         //test get
         allKeys.forEach(key -> map.get(key).
                 thenAccept(result -> assertNull(result)).join());
 
+        //test getOrDefault
+        allKeys.forEach(key -> map.getOrDefault(key, null).thenAccept(result -> {
+            assertEquals(0, result.version());
+            assertNull(result.value());
+        }).join());
+
+        allKeys.forEach(key -> map.getOrDefault(key, "bar".getBytes()).thenAccept(result -> {
+            assertEquals(0, result.version());
+            assertArrayEquals("bar".getBytes(), result.value());
+        }).join());
+
         //populate and redo prior three tests
-        allKeys.forEach(key -> map.put(key, allValues
-                .get(allKeys.indexOf(key))).thenAccept(
-                result -> assertNull(result)).join());
+        allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key)))
+                .thenAccept(result -> assertNull(result)).join());
+
         //test contains key
-        allKeys.forEach(key -> map.containsKey(key).
-                thenAccept(result -> assertTrue(result)).join());
+        allKeys.forEach(key -> map.containsKey(key)
+                .thenAccept(result -> assertTrue(result)).join());
+
         //test contains value
         allValues.forEach(value -> map.containsValue(value)
                 .thenAccept(result -> assertTrue(result)).join());
+
         //test get
-        allKeys.forEach(key -> map.get(key).
-                thenAccept(
-                        result -> assertArrayEquals(
-                                allValues.get(allKeys.indexOf(key)),
-                                result.value())).join());
+        allKeys.forEach(key -> map.get(key).thenAccept(result -> {
+            assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
+        }).join());
+
+        allKeys.forEach(key -> map.getOrDefault(key, null).thenAccept(result -> {
+            assertNotEquals(0, result.version());
+            assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
+        }).join());
+
         //test all compute methods in this section
-        allKeys.forEach(key -> map.computeIfAbsent(
-                key, v -> allValues.get(allKeys.indexOf(key)
-                )).thenAccept(result ->
-                                assertArrayEquals(
-                                        allValues.get(allKeys.indexOf(key)),
-                                        result.value())).join());
+        allKeys.forEach(key -> map.computeIfAbsent(key, v -> allValues.get(allKeys.indexOf(key)))
+                .thenAccept(result -> {
+                    assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
+                }).join());
+
         map.size().thenAccept(result -> assertEquals(4, (int) result)).join();
         map.isEmpty().thenAccept(result -> assertFalse(result)).join();
+
         allKeys.forEach(key -> map.computeIfPresent(key, (k, v) -> null).
                 thenAccept(result -> assertNull(result)).join());
+
         map.isEmpty().thenAccept(result -> assertTrue(result)).join();
-        allKeys.forEach(key -> map.compute(key, (k, v) ->
-                            allValues.get(allKeys.indexOf(key))).
-                            thenAccept(result -> assertArrayEquals(
-                                    allValues.get(allKeys.indexOf(key)),
-                                    result.value())).join());
+
+        allKeys.forEach(key -> map.compute(key, (k, v) -> allValues.get(allKeys.indexOf(key)))
+                .thenAccept(result -> assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value())).join());
+
         map.size().thenAccept(result -> assertEquals(4, (int) result)).join();
         map.isEmpty().thenAccept(result -> assertFalse(result)).join();
+
         allKeys.forEach(key -> map.computeIf(key,
-                                         (k) -> allKeys.indexOf(key) < 2,
-                                         (k, v) -> null).thenAccept(result -> {
-            if (allKeys.indexOf(key) < 2) {
-                assertNull(result);
-            } else {
-                assertArrayEquals(allValues.get(allKeys.indexOf(key)),
-                                  result.value());
-            }
-        }).join());
-        map.size().thenAccept(result -> assertEquals(2, (int) result)).join();
-        map.isEmpty().thenAccept(result -> assertFalse(result)).join();
-        //test simple put
-        allKeys.forEach(
-                key -> map.put(key, allValues.get(allKeys.indexOf(key)))
-                .thenAccept(result -> {
+                (k) -> allKeys.indexOf(key) < 2, (k, v) -> null).thenAccept(result -> {
                     if (allKeys.indexOf(key) < 2) {
                         assertNull(result);
                     } else {
-                        assertArrayEquals(
-                                allValues.get(allKeys.indexOf(key)),
-                                result.value());
+                        assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
                     }
-                }).join());
+        }).join());
+
+        map.size().thenAccept(result -> assertEquals(2, (int) result)).join();
+        map.isEmpty().thenAccept(result -> assertFalse(result)).join();
+
+        //test simple put
+        allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key))).thenAccept(result -> {
+            if (allKeys.indexOf(key) < 2) {
+                assertNull(result);
+            } else {
+                assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value());
+            }
+        }).join());
+
         map.size().thenAccept(result -> assertEquals(4, (int) result)).join();
         map.isEmpty().thenAccept(result -> assertFalse(result)).join();
+
         //test put and get for version retrieval
-        allKeys.forEach(
-                key -> map.putAndGet(key, allValues.get(allKeys.indexOf(key))).
-            thenAccept(firstResult -> {
-                map.putAndGet(key, allValues.get(allKeys.indexOf(key))).
-                    thenAccept(secondResult -> {
-                    assertArrayEquals(allValues.get(allKeys.indexOf(key)),
-                                      firstResult.value());
-                    assertArrayEquals(allValues.get(allKeys.indexOf(key)),
-                                      secondResult.value());
-                    assertTrue((firstResult.version() + 1) ==
-                                       secondResult.version());
-                });
-            }).join());
+        allKeys.forEach(key -> map.putAndGet(key, allValues.get(allKeys.indexOf(key))).thenAccept(firstResult -> {
+            map.putAndGet(key, allValues.get(allKeys.indexOf(key))).thenAccept(secondResult -> {
+                assertArrayEquals(allValues.get(allKeys.indexOf(key)), firstResult.value());
+                assertArrayEquals(allValues.get(allKeys.indexOf(key)), secondResult.value());
+                assertTrue((firstResult.version() + 1) == secondResult.version());
+            });
+        }).join());
+
         //test removal
         allKeys.forEach(key -> map.remove(key).thenAccept(
                 result -> assertArrayEquals(
                         allValues.get(allKeys.indexOf(key)), result.value()))
                 .join());
         map.isEmpty().thenAccept(result -> assertTrue(result));
+
         //repopulating, this is not mainly for testing
-        allKeys.forEach(key -> map.put(
-                key, allValues.get(allKeys.indexOf(key)))
-                .thenAccept(result -> {
-                        assertNull(result);
-                }).join());
+        allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key))).thenAccept(result -> {
+            assertNull(result);
+        }).join());
 
         //Test various collections of keys, values and entries
-        map.keySet().thenAccept(
-                keys -> assertTrue(
-                        stringArrayCollectionIsEqual(keys, allKeys)))
-                .join();
-        map.values().thenAccept(
-                values -> assertTrue(
-                        byteArrayCollectionIsEqual(values.stream().map(
-                                v -> v.value()).collect(
-                                Collectors.toSet()), allValues)))
-                .join();
+        map.keySet().thenAccept(keys -> assertTrue(stringArrayCollectionIsEqual(keys, allKeys))).join();
+        map.values().thenAccept(values -> assertTrue(
+                byteArrayCollectionIsEqual(values.stream().map(v -> v.value())
+                        .collect(Collectors.toSet()), allValues))).join();
         map.entrySet().thenAccept(entrySet -> {
             entrySet.forEach(entry -> {
                 assertTrue(allKeys.contains(entry.getKey()));
@@ -209,72 +217,49 @@
         map.isEmpty().thenAccept(result -> assertTrue(result)).join();
 
         //test conditional put
-        allKeys.forEach(
-                key -> map.putIfAbsent(
-                        key, allValues.get(allKeys.indexOf(key))).
-                        thenAccept(result -> assertNull(result)).join());
-        allKeys.forEach(
-                key -> map.putIfAbsent(
-                        key, null).
-                        thenAccept(result ->
-                                   assertArrayEquals(result.value(),
-                                        allValues.get(allKeys.indexOf(key))))
-                        .join());
+        allKeys.forEach(key -> map.putIfAbsent(key, allValues.get(allKeys.indexOf(key)))
+                .thenAccept(result -> assertNull(result)).join());
+        allKeys.forEach(key -> map.putIfAbsent(key, null).thenAccept(result ->
+                assertArrayEquals(result.value(), allValues.get(allKeys.indexOf(key)))
+        ).join());
+
         // test alternate removes that specify value or version
-        allKeys.forEach(
-                key -> map.remove(key, spareValue).thenAccept(
-                        result -> assertFalse(result)).join());
-        allKeys.forEach(
-                key -> map.remove(key, allValues.get(allKeys.indexOf(key)))
-                        .thenAccept(result -> assertTrue(result)).join());
+        allKeys.forEach(key -> map.remove(key, spareValue).thenAccept(result -> assertFalse(result)).join());
+        allKeys.forEach(key -> map.remove(key, allValues.get(allKeys.indexOf(key)))
+                .thenAccept(result -> assertTrue(result)).join());
         map.isEmpty().thenAccept(result -> assertTrue(result)).join();
         List<Long> versions = Lists.newArrayList();
 
         //repopulating set for version based removal
-        allKeys.forEach(
-                key -> map.putAndGet(key, allValues.get(allKeys.indexOf(key)))
+        allKeys.forEach(key -> map.putAndGet(key, allValues.get(allKeys.indexOf(key)))
                 .thenAccept(result -> versions.add(result.version())).join());
-        allKeys.forEach(
-                key -> map.remove(key, versions.get(0)).thenAccept(
-                        result -> {
-                            assertTrue(result);
-                            versions.remove(0);
-                        }).join());
+        allKeys.forEach(key -> map.remove(key, versions.get(0)).thenAccept(result -> {
+            assertTrue(result);
+            versions.remove(0);
+        }).join());
         map.isEmpty().thenAccept(result -> assertTrue(result)).join();
+
         //Testing all replace both simple (k, v), and complex that consider
         // previous mapping or version.
-        allKeys.forEach(
-                key -> map.put(key, allValues.get(allKeys.indexOf(key)))
+        allKeys.forEach(key -> map.put(key, allValues.get(allKeys.indexOf(key)))
                 .thenAccept(result -> assertNull(result)).join());
-        allKeys.forEach(key -> map.replace(
-                key, allValues.get(3 - allKeys.indexOf(key)))
-                .thenAccept(result -> assertArrayEquals(
-                        allValues.get(allKeys.indexOf(key)), result.value()))
+        allKeys.forEach(key -> map.replace(key, allValues.get(3 - allKeys.indexOf(key)))
+                .thenAccept(result -> assertArrayEquals(allValues.get(allKeys.indexOf(key)), result.value()))
                 .join());
-        allKeys.forEach(key -> map.replace(key,
-                                           spareValue,
-                                           allValues.get(allKeys.indexOf(key)))
-                .thenAccept(result -> assertFalse(result))
-                .join());
-        allKeys.forEach(key -> map.replace(
-                key, allValues.get(3 - allKeys.indexOf(key)),
-                allValues.get(allKeys.indexOf(key)))
-                .thenAccept(result -> assertTrue(result)).join());
+        allKeys.forEach(key -> map.replace(key, spareValue, allValues.get(allKeys.indexOf(key)))
+                .thenAccept(result -> assertFalse(result)).join());
+        allKeys.forEach(key -> map.replace(key, allValues.get(3 - allKeys.indexOf(key)),
+                allValues.get(allKeys.indexOf(key))).thenAccept(result -> assertTrue(result)).join());
         map.clear().join();
         map.isEmpty().thenAccept(result -> assertTrue(result)).join();
         versions.clear();
+
         //populate for version based replacement
-        allKeys.forEach(
-                key -> map.putAndGet(
-                        key, allValues.get(3 - allKeys.indexOf(key)))
-                        .thenAccept(result ->
-                            versions.add(result.version())).join());
-        allKeys.forEach(key -> map.replace(
-                key, 0, allValues.get(allKeys.indexOf(key)))
-                .thenAccept(result -> assertFalse(result))
-                .join());
-        allKeys.forEach(key -> map.replace(
-                key, versions.get(0), allValues.get(allKeys.indexOf(key)))
+        allKeys.forEach(key -> map.putAndGet(key, allValues.get(3 - allKeys.indexOf(key)))
+                .thenAccept(result -> versions.add(result.version())).join());
+        allKeys.forEach(key -> map.replace(key, 0, allValues.get(allKeys.indexOf(key)))
+                .thenAccept(result -> assertFalse(result)).join());
+        allKeys.forEach(key -> map.replace(key, versions.get(0), allValues.get(allKeys.indexOf(key)))
                 .thenAccept(result -> {
                     assertTrue(result);
                     versions.remove(0);
diff --git a/protocols/pcep/ctl/src/test/java/org/onosproject/pcelabelstore/util/ConsistentMapAdapter.java b/protocols/pcep/ctl/src/test/java/org/onosproject/pcelabelstore/util/ConsistentMapAdapter.java
index 56b2952..5dc06a4 100644
--- a/protocols/pcep/ctl/src/test/java/org/onosproject/pcelabelstore/util/ConsistentMapAdapter.java
+++ b/protocols/pcep/ctl/src/test/java/org/onosproject/pcelabelstore/util/ConsistentMapAdapter.java
@@ -69,6 +69,11 @@
     }
 
     @Override
+    public Versioned<V> getOrDefault(K key, V defaultValue) {
+        return null;
+    }
+
+    @Override
     public Versioned<V> computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
         return null;
     }