Make resource retrieval more efficient when specifing resource type

This resolves ONOS-4666

Change-Id: I9d09b60531ca48b36fc20f43498cda62f1badb8b
diff --git a/core/api/src/main/java/org/onosproject/net/resource/ResourceStore.java b/core/api/src/main/java/org/onosproject/net/resource/ResourceStore.java
index b531d04..8456106 100644
--- a/core/api/src/main/java/org/onosproject/net/resource/ResourceStore.java
+++ b/core/api/src/main/java/org/onosproject/net/resource/ResourceStore.java
@@ -111,6 +111,18 @@
     Set<Resource> getChildResources(DiscreteResourceId parent);
 
     /**
+     * Returns a set of the child resources of the specified parent and whose type is
+     * the specified class.
+     *
+     * @param parent ID of the parent of the resources to be returned
+     * @param cls class instance of the children
+     * @param <T> type of the resource
+     * @return a set of the child resources of the specified parent and whose type is
+     * the specified class
+     */
+    <T> Set<Resource> getChildResources(DiscreteResourceId parent, Class<T> cls);
+
+    /**
      * Returns a collection of the resources which are children of the specified parent and
      * whose type is the specified class.
      *
diff --git a/core/net/src/main/java/org/onosproject/net/resource/impl/ResourceManager.java b/core/net/src/main/java/org/onosproject/net/resource/impl/ResourceManager.java
index 60a8516..52ea71d 100644
--- a/core/net/src/main/java/org/onosproject/net/resource/impl/ResourceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/resource/impl/ResourceManager.java
@@ -165,9 +165,9 @@
         checkNotNull(parent);
         checkNotNull(cls);
 
-        // naive implementation
-        return getAvailableResources(parent).stream()
-                .filter(resource -> resource.isTypeOf(cls))
+        return store.getChildResources(parent, cls).stream()
+                // We access store twice in this method, then the store may be updated by others
+                .filter(store::isAvailable)
                 .collect(Collectors.toSet());
     }
 
@@ -177,9 +177,11 @@
         checkNotNull(parent);
         checkNotNull(cls);
 
-        // naive implementation
-        return getAvailableResources(parent).stream()
-                .flatMap(resource -> Tools.stream(resource.valueAs(cls)))
+        return store.getChildResources(parent, cls).stream()
+                // We access store twice in this method, then the store may be updated by others
+                .filter(store::isAvailable)
+                .map(x -> x.valueAs(cls))
+                .flatMap(Tools::stream)
                 .collect(Collectors.toSet());
     }
 
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentContinuousResourceSubStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentContinuousResourceSubStore.java
index e9c9ad7..60eed40 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentContinuousResourceSubStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentContinuousResourceSubStore.java
@@ -32,6 +32,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import static org.onosproject.store.resource.impl.ConsistentResourceStore.SERIALIZER;
@@ -79,6 +80,13 @@
         return children.value();
     }
 
+    <T> Set<ContinuousResource> getChildResources(DiscreteResourceId parent, Class<T> cls) {
+        // naive implementation
+        return getChildResources(parent).stream()
+                .filter(x -> x.isTypeOf(cls))
+                .collect(Collectors.toCollection(LinkedHashSet::new));
+    }
+
     public boolean isAvailable(ContinuousResource resource) {
         // check if it's registered or not.
         Versioned<Set<ContinuousResource>> children = childMap.get(resource.parent().get().id());
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDiscreteResourceSubStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDiscreteResourceSubStore.java
index 5650585..d036c5f 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDiscreteResourceSubStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentDiscreteResourceSubStore.java
@@ -76,6 +76,16 @@
         return children.value().values();
     }
 
+    <T> Set<DiscreteResource> getChildResources(DiscreteResourceId parent, Class<T> cls) {
+        Versioned<DiscreteResources> children = childMap.get(parent);
+
+        if (children == null) {
+            return ImmutableSet.of();
+        }
+
+        return children.value().valuesOf(cls);
+    }
+
     boolean isAvailable(DiscreteResource resource) {
         return getResourceAllocations(resource.id()).isEmpty();
     }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentResourceStore.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentResourceStore.java
index 69645b1..0ecc108 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentResourceStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/ConsistentResourceStore.java
@@ -296,6 +296,17 @@
                 .build();
     }
 
+    @Override
+    public <T> Set<Resource> getChildResources(DiscreteResourceId parent, Class<T> cls) {
+        checkNotNull(parent);
+        checkNotNull(cls);
+
+        return ImmutableSet.<Resource>builder()
+                .addAll(discreteStore.getChildResources(parent, cls))
+                .addAll(continuousStore.getChildResources(parent, cls))
+                .build();
+    }
+
     // computational complexity: O(n) where n is the number of the children of the parent
     @Override
     public <T> Collection<Resource> getAllocatedResources(DiscreteResourceId parent, Class<T> cls) {
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DiscreteResources.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DiscreteResources.java
index b6acccc..3bb1f07 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DiscreteResources.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/DiscreteResources.java
@@ -91,4 +91,13 @@
      * @return all resources
      */
     Set<DiscreteResource> values();
+
+    /**
+     * Returns all of resources this instance holds and filtered by the specified type.
+     *
+     * @param cls class instance of the resource value
+     * @param <T> type of the resource value
+     * @return all of resources this instance holds and filtered by the specified type
+     */
+    <T> Set<DiscreteResource> valuesOf(Class<T> cls);
 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EmptyDiscreteResources.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EmptyDiscreteResources.java
index d7c0f24..55a0e94 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EmptyDiscreteResources.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EmptyDiscreteResources.java
@@ -68,4 +68,9 @@
                 .add("values", ImmutableSet.of())
                 .toString();
     }
+
+    @Override
+    public <T> Set<DiscreteResource> valuesOf(Class<T> cls) {
+        return ImmutableSet.of();
+    }
 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EncodableDiscreteResources.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EncodableDiscreteResources.java
index 25ec5a7..512b233 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EncodableDiscreteResources.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/EncodableDiscreteResources.java
@@ -16,6 +16,7 @@
 package org.onosproject.store.resource.impl;
 
 import com.google.common.base.MoreObjects;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import org.onosproject.net.resource.DiscreteResource;
 import org.onosproject.net.resource.DiscreteResourceCodec;
@@ -114,6 +115,13 @@
                 .collect(Collectors.toCollection(LinkedHashSet::new));
     }
 
+    @Override
+    public <T> Set<DiscreteResource> valuesOf(Class<T> cls) {
+        return Optional.ofNullable(values.get(cls))
+                .map(x -> x.values(parent.id()))
+                .orElse(ImmutableSet.of());
+    }
+
     DiscreteResource parent() {
         return parent;
     }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/GenericDiscreteResources.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/GenericDiscreteResources.java
index 79eb13d..1aa8bb9 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/GenericDiscreteResources.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/GenericDiscreteResources.java
@@ -25,6 +25,7 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 final class GenericDiscreteResources implements DiscreteResources {
     private final Set<DiscreteResource> values;
@@ -87,6 +88,13 @@
     }
 
     @Override
+    public <T> Set<DiscreteResource> valuesOf(Class<T> cls) {
+        return values.stream()
+                .filter(x -> x.isTypeOf(cls))
+                .collect(Collectors.toCollection(LinkedHashSet::new));
+    }
+
+    @Override
     public int hashCode() {
         return Objects.hash(values);
     }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/UnifiedDiscreteResources.java b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/UnifiedDiscreteResources.java
index 0bd1fca..56e6b87 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/resource/impl/UnifiedDiscreteResources.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/resource/impl/UnifiedDiscreteResources.java
@@ -93,6 +93,11 @@
                 .collect(Collectors.toCollection(LinkedHashSet::new));
     }
 
+    public <T> Set<DiscreteResource> valuesOf(Class<T> cls) {
+        return Stream.concat(encodables.valuesOf(cls).stream(), generics.valuesOf(cls).stream())
+                .collect(Collectors.toCollection(LinkedHashSet::new));
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(generics, encodables);