ONOS-2445: Implement API to declare resource boundary

Change-Id: I91cd59a068a1ec2624089c3a60eb21e0bf7e12c7
diff --git a/core/api/src/main/java/org/onosproject/net/newresource/ResourceAdminService.java b/core/api/src/main/java/org/onosproject/net/newresource/ResourceAdminService.java
new file mode 100644
index 0000000..5fcb132
--- /dev/null
+++ b/core/api/src/main/java/org/onosproject/net/newresource/ResourceAdminService.java
@@ -0,0 +1,37 @@
+/*
+ * 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.net.newresource;
+
+import com.google.common.annotations.Beta;
+
+import java.util.function.Predicate;
+
+/**
+ * Service for administering resource service behavior.
+ */
+@Beta
+public interface ResourceAdminService {
+    /**
+     * Define a boundary of the resource specified by the class.
+     * The specified predicate is expected to return true if the supplied value is
+     * in the resource boundary and return false if it is out of the boundary.
+     *
+     * @param cls class of the resource type
+     * @param predicate predicate returning true if the value is in the boundary
+     * @param <T> type of the resource
+     */
+    <T> void defineResourceBoundary(Class<T> cls, Predicate<T> predicate);
+}
diff --git a/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java b/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java
index 3ebbdc0..785613c 100644
--- a/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java
+++ b/core/net/src/main/java/org/onosproject/net/newresource/impl/ResourceManager.java
@@ -24,6 +24,7 @@
 import org.onosproject.net.newresource.DefaultResource;
 import org.onosproject.net.newresource.DefaultResourceAllocation;
 import org.onosproject.net.newresource.Resource;
+import org.onosproject.net.newresource.ResourceAdminService;
 import org.onosproject.net.newresource.ResourceAllocation;
 import org.onosproject.net.newresource.ResourceConsumer;
 import org.onosproject.net.newresource.ResourceService;
@@ -34,6 +35,9 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -44,7 +48,9 @@
 @Component(immediate = true, enabled = false)
 @Service
 @Beta
-public final class ResourceManager implements ResourceService {
+public final class ResourceManager implements ResourceService, ResourceAdminService {
+
+    private final ConcurrentMap<Class<?>, Predicate<?>> boundaries = new ConcurrentHashMap<>();
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ResourceStore store;
@@ -175,6 +181,24 @@
         return !consumer.isPresent();
     }
 
+    @Override
+    public <T> void defineResourceBoundary(Class<T> cls, Predicate<T> predicate) {
+        boundaries.put(cls, predicate);
+    }
+
+    /**
+     * Returns the predicate associated with the specified resource.
+     *
+     * @param resource resource whose associated predicate is to be returned
+     * @param <T> type of the resource
+     * @return predicate associated with the resource
+     * Null if the resource doesn't have an associated predicate.
+     */
+    @SuppressWarnings("unchecked")
+    private <T> Predicate<T> lookupPredicate(T resource) {
+        return (Predicate<T>) boundaries.get(resource.getClass());
+    }
+
     /**
      * Returns if the specified resource is in the resource range.
      * E.g. VLAN ID against a link must be within 12 bit address space.
@@ -184,8 +208,12 @@
      * @param <T> type of the resource
      * @return true if the resource within the range, false otherwise
      */
-    private <S, T> boolean isValid(Resource<S, T> resource) {
-        // TODO: implement
-        return true;
+    <S, T> boolean isValid(Resource<S, T> resource) {
+        Predicate<T> predicate = lookupPredicate(resource.resource());
+        if (predicate == null) {
+            return true;
+        }
+
+        return predicate.test(resource.resource());
     }
 }
diff --git a/core/net/src/test/java/org/onosproject/net/newresource/impl/ResourceManagerTest.java b/core/net/src/test/java/org/onosproject/net/newresource/impl/ResourceManagerTest.java
new file mode 100644
index 0000000..f3b61fc
--- /dev/null
+++ b/core/net/src/test/java/org/onosproject/net/newresource/impl/ResourceManagerTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.net.newresource.impl;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.LinkKey;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.newresource.DefaultResource;
+
+import java.util.function.Predicate;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.*;
+
+/**
+ * Unit tests for ResourceManager.
+ */
+public class ResourceManagerTest {
+
+    private static final DeviceId D1 = DeviceId.deviceId("of:001");
+    private static final DeviceId D2 = DeviceId.deviceId("of:002");
+    private static final PortNumber P1 = PortNumber.portNumber(1);
+    private static final ConnectPoint CP1_1 = new ConnectPoint(D1, P1);
+    private static final ConnectPoint CP2_1 = new ConnectPoint(D2, P1);
+    private static final short VLAN_LOWER_LIMIT = 0;
+    private static final short VLAN_UPPER_LIMIT = 1024;
+
+    private final Predicate<VlanId> vlanPredicate =
+            x -> x.toShort() >= VLAN_LOWER_LIMIT && x.toShort() < VLAN_UPPER_LIMIT;
+    private ResourceManager manager;
+
+    @Before
+    public void setUp() {
+        manager = new ResourceManager();
+    }
+
+    /**
+     * Tests resource boundaries.
+     */
+    @Test
+    public void testBoundary() {
+        manager.defineResourceBoundary(VlanId.class, vlanPredicate);
+
+        LinkKey linkKey = LinkKey.linkKey(CP1_1, CP2_1);
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId((short) (VLAN_LOWER_LIMIT - 1)))),
+                is(false));
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId(VLAN_LOWER_LIMIT))),
+                is(true));
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId((short) 100))),
+                is(true));
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId((short) (VLAN_UPPER_LIMIT - 1)))),
+                is(true));
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId(VLAN_UPPER_LIMIT))),
+                is(false));
+    }
+
+    /**
+     * Tests the case that a boundary is not set.
+     */
+    @Test
+    public void testWhenBoundaryNotSet() {
+        LinkKey linkKey = LinkKey.linkKey(CP1_1, CP2_1);
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId((short) (VLAN_LOWER_LIMIT - 1)))),
+                is(true));
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId(VLAN_LOWER_LIMIT))),
+                is(true));
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId((short) 100))),
+                is(true));
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId((short) (VLAN_UPPER_LIMIT - 1)))),
+                is(true));
+
+        assertThat(manager.isValid(new DefaultResource<>(linkKey, VlanId.vlanId(VLAN_UPPER_LIMIT))),
+                is(true));
+    }
+}