Introduce two specific types of ResourceId for Discrete and Continuous
Change-Id: I4a29beaabe32ba78fb03336192095edadc63e3c9
diff --git a/core/api/src/main/java/org/onosproject/net/newresource/Resource.java b/core/api/src/main/java/org/onosproject/net/newresource/Resource.java
index 15e4626..1b05d94 100644
--- a/core/api/src/main/java/org/onosproject/net/newresource/Resource.java
+++ b/core/api/src/main/java/org/onosproject/net/newresource/Resource.java
@@ -53,7 +53,7 @@
public static final Discrete ROOT = new Discrete();
public static Resource discrete(DeviceId device) {
- return new Discrete(ResourceId.of(device));
+ return new Discrete(ResourceId.discrete(device));
}
/**
@@ -64,7 +64,7 @@
* @return resource path instance
*/
public static Resource discrete(DeviceId device, Object... components) {
- return new Discrete(ResourceId.of(device, components));
+ return new Discrete(ResourceId.discrete(device, components));
}
/**
@@ -76,7 +76,7 @@
* @return resource path instance
*/
public static Resource discrete(DeviceId device, PortNumber port, Object... components) {
- return new Discrete(ResourceId.of(device, port, components));
+ return new Discrete(ResourceId.discrete(device, port, components));
}
/**
@@ -85,13 +85,15 @@
* @param value amount of the resource
* @param device device ID which is the first component of the path
* @param components following components of the path. The order represents hierarchical structure of the resource.
+ * The last element of this list must be an {@link Class} instance. Otherwise, this method throws
+ * an IllegalArgumentException.
* @return resource path instance
*/
public static Resource continuous(double value, DeviceId device, Object... components) {
checkArgument(components.length > 0,
"Length of components must be greater thant 0, but " + components.length);
- return new Continuous(ResourceId.of(device, components), value);
+ return new Continuous(ResourceId.continuous(device, components), value);
}
/**
@@ -101,10 +103,12 @@
* @param device device ID which is the first component of the path.
* @param port port number which is the second component of the path.
* @param components following components of the path. The order represents hierarchical structure of the resource.
+ * The last element of this list must be an {@link Class} instance. Otherwise, this method throws
+ * an IllegalArgumentException.
* @return resource path instance
*/
public static Resource continuous(double value, DeviceId device, PortNumber port, Object... components) {
- return new Continuous(ResourceId.of(device, port, components), value);
+ return new Continuous(ResourceId.continuous(device, port, components), value);
}
/**
@@ -139,6 +143,14 @@
}
/**
+ * Returns the volume of this resource.
+ *
+ * @return the volume of this resource
+ */
+ // TODO: think about other naming possibilities. amount? quantity?
+ public abstract <T> T volume();
+
+ /**
* Returns the parent resource path of this instance.
* E.g. if this path is Link:1/VLAN ID:100, the return value is the resource path for Link:1.
*
@@ -199,30 +211,10 @@
}
@Override
- public int hashCode() {
- return id.hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
-
- if (obj == null) {
- return false;
- }
- if (this.getClass() != obj.getClass()) {
- return false;
- }
- final Resource that = (Resource) obj;
- return Objects.equals(this.id, that.id);
- }
-
- @Override
public String toString() {
return MoreObjects.toStringHelper(this)
- .add("id", id)
+ .add("id", id())
+ .add("volume", volume())
.toString();
}
@@ -243,6 +235,39 @@
private Discrete(ResourceId id) {
super(id);
}
+
+ /**
+ * The user of this methods must receive the return value as the correct type.
+ * Otherwise, this methods throws an exception.
+ *
+ * @param <T> type of the return value
+ * @return the volume of this resource
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ // TODO: consider receiving Class<T> as an argument. Which approach is convenient?
+ public <T> T volume() {
+ return (T) last();
+ }
+
+ @Override
+ public int hashCode() {
+ // the value returing from volume() is excluded due to optimization
+ return id().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Discrete other = (Discrete) obj;
+ // the value returing from volume() is excluded due to optimization
+ return Objects.equals(this.id(), other.id());
+ }
}
/**
@@ -261,16 +286,35 @@
this.value = value;
}
+ /**
+ * The user of this methods must receive the return value as Double or double.
+ * Otherwise, this methods throws an exception.
+ *
+ * @param <T> type of the return value
+ * @return the volume of this resource
+ */
+ @SuppressWarnings("unchecked")
@Override
- public int hashCode() {
- return super.hashCode();
+ public <T> T volume() {
+ return (T) Double.valueOf(value);
}
- // explicitly overriding to express that we intentionally ignore
- // `value` in equality comparison
+ @Override
+ public int hashCode() {
+ return Objects.hash(id(), value);
+ }
+
@Override
public boolean equals(Object obj) {
- return super.equals(obj);
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final Continuous other = (Continuous) obj;
+ return Objects.equals(this.id(), other.id())
+ && Objects.equals(this.value, other.value);
}
/**
@@ -278,17 +322,10 @@
*
* @return the value of the resource amount
*/
+ // FIXME: overlapping a purpose with volume()
public double value() {
return value;
}
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("id", id())
- .add("value", value)
- .toString();
- }
}
}
diff --git a/core/api/src/main/java/org/onosproject/net/newresource/ResourceId.java b/core/api/src/main/java/org/onosproject/net/newresource/ResourceId.java
index 6bfc3cc..1be737e 100644
--- a/core/api/src/main/java/org/onosproject/net/newresource/ResourceId.java
+++ b/core/api/src/main/java/org/onosproject/net/newresource/ResourceId.java
@@ -20,35 +20,63 @@
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
+import java.util.Arrays;
import java.util.Objects;
+import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
/**
* Represents identifier of resource.
* This class is exposed to public, but intended to use only in ResourceStore implementations.
*/
@Beta
-public final class ResourceId {
- static final ResourceId ROOT = new ResourceId();
+public abstract class ResourceId {
+ static final ResourceId ROOT = new Discrete();
final ImmutableList<Object> components;
- static ResourceId of(DeviceId device, Object... components) {
- return new ResourceId(ImmutableList.builder()
+ static ResourceId discrete(DeviceId device, Object... components) {
+ return new Discrete(ImmutableList.builder()
.add(device)
.add(components)
.build());
}
- static ResourceId of(DeviceId device, PortNumber port, Object... components) {
- return new ResourceId(ImmutableList.builder()
+ static ResourceId discrete(DeviceId device, PortNumber port, Object... components) {
+ return new Discrete(ImmutableList.builder()
.add(device)
.add(port)
.add(components)
.build());
}
+ static ResourceId continuous(DeviceId device, Object... components) {
+ Object last = components[components.length - 1];
+ checkArgument(last instanceof Class<?>);
+
+ return continuous(ImmutableList.builder()
+ .add(device)
+ .add(Arrays.copyOfRange(components, 0, components.length - 1)), (Class<?>) last);
+ }
+
+ static ResourceId continuous(DeviceId device, PortNumber port, Object... components) {
+ Object last = components[components.length - 1];
+ checkArgument(last instanceof Class<?>);
+
+ return continuous(ImmutableList.builder()
+ .add(device)
+ .add(port)
+ .add(Arrays.copyOfRange(components, 0, components.length - 1)), (Class<?>) last);
+ }
+
+ private static ResourceId continuous(ImmutableList.Builder<Object> parentComponents, Class<?> last) {
+ return new Continuous(parentComponents
+ .add(last.getCanonicalName())
+ .build(), last.getSimpleName());
+ }
+
private ResourceId(ImmutableList<Object> components) {
this.components = checkNotNull(components);
}
@@ -63,15 +91,31 @@
if (components.size() == 1) {
return ROOT;
} else {
- return new ResourceId(components.subList(0, components.size() - 1));
+ return new Discrete(components.subList(0, components.size() - 1));
}
}
- ResourceId child(Object child) {
- return new ResourceId(ImmutableList.builder()
- .addAll(components)
- .add(child)
- .build());
+ /**
+ * Returns a resource ID of a child of this resource based on the specified object.
+ * If the argument is an instance of {@link Class}, this method returns an instance of
+ * {@link Continuous}. Otherwise, it returns an instance of {@link Discrete}
+ * This method only work when the receiver is {@link Discrete}. Otherwise,
+ * this method throws an exception.
+ *
+ * @param child the last component of the child
+ * @return a child resource ID
+ */
+ public ResourceId child(Object child) {
+ checkState(this instanceof Discrete);
+
+ if (child instanceof Class<?>) {
+ return continuous(ImmutableList.builder().addAll(components), (Class<?>) child);
+ } else {
+ return new Discrete(ImmutableList.builder()
+ .addAll(components)
+ .add(child)
+ .build());
+ }
}
@Override
@@ -84,11 +128,10 @@
if (this == obj) {
return true;
}
- if (!(obj instanceof ResourceId)) {
+ if (obj == null || getClass() != obj.getClass()) {
return false;
}
-
- ResourceId other = (ResourceId) obj;
+ final ResourceId other = (ResourceId) obj;
return Objects.equals(this.components, other.components);
}
@@ -96,4 +139,45 @@
public String toString() {
return components.toString();
}
+
+ /**
+ * ResourceId for {@link Resource.Discrete}.
+ *
+ * Note: This class is exposed to the public, but intended to be used in the resource API
+ * implementation only. It is not for resource API user.
+ */
+ public static final class Discrete extends ResourceId {
+ private Discrete(ImmutableList<Object> components) {
+ super(components);
+ }
+
+ private Discrete() {
+ super();
+ }
+ }
+
+ /**
+ * ResourceId for {@link Resource.Continuous}
+ *
+ * Note: This class is exposed to the public, but intended to be used in the resource API
+ * implementation only. It is not for resource API user.
+ */
+ public static final class Continuous extends ResourceId {
+ // for printing purpose only (used in toString() implementation)
+ private final String name;
+
+ private Continuous(ImmutableList<Object> components, String name) {
+ super(components);
+ this.name = checkNotNull(name);
+ }
+
+ @Override
+ public String toString() {
+ // due to performance consideration, the value might need to be stored in a field
+ return ImmutableList.builder()
+ .addAll(components.subList(0, components.size() - 1))
+ .add(name)
+ .build().toString();
+ }
+ }
}
diff --git a/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java b/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java
index 974fe5e..124205d 100644
--- a/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java
+++ b/core/api/src/main/java/org/onosproject/net/newresource/ResourceService.java
@@ -132,6 +132,7 @@
* @return list of allocation information.
* If the resource is not allocated, the return value is an empty list.
*/
+ // TODO: need to change the argument type to ResourceId
List<ResourceAllocation> getResourceAllocation(Resource resource);
/**
@@ -143,6 +144,7 @@
* @return non-empty collection of resource allocations if resources are allocated with the subject and type,
* empty collection if no resource is allocated with the subject and type
*/
+ // TODO: might need to change the first argument type to ResourceId or ResourceId.Discrete
<T> Collection<ResourceAllocation> getResourceAllocations(Resource parent, Class<T> cls);
/**
@@ -159,6 +161,7 @@
* @param parent parent resource
* @return available resources under the specified resource
*/
+ // TODO: need to change the argument type to ResourceId or ResourceId.Discrete
Collection<Resource> getAvailableResources(Resource parent);
/**
@@ -167,6 +170,7 @@
* @param parent parent resource
* @return registered resources under the specified resource
*/
+ // TODO: need to change the argument type to ResourceId or ResourceId.Discrete
Collection<Resource> getRegisteredResources(Resource parent);
diff --git a/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java b/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java
index ac30548..321c861 100644
--- a/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java
+++ b/core/api/src/main/java/org/onosproject/net/newresource/ResourceStore.java
@@ -84,6 +84,7 @@
* @return resource consumers who are allocated the resource.
* Returns empty list if there is no such consumer.
*/
+ // TODO: need to change the argument type to ResourceId
List<ResourceConsumer> getConsumers(Resource resource);
/**
@@ -108,6 +109,7 @@
* @param parent parent of the resource to be returned
* @return a collection of the child resources of the specified resource
*/
+ // TODO: need to change the argument type to ResourceId or ResourceId.Discrete
Collection<Resource> getChildResources(Resource parent);
/**
@@ -120,5 +122,6 @@
* @return a collection of the resources which belongs to the specified subject and
* whose type is the specified class.
*/
+ // TODO: need to change the argument type to ResourceId or ResourceId.Discrete
<T> Collection<Resource> getAllocatedResources(Resource parent, Class<T> cls);
}