Enable REST to manage devices under a proxy

This commit integrates the REST proxy within the standard REST
protocol and provider, supporting multiple devices managed by
a single REST end point (e.g. a REST-based second level controller).

It introduces the concept of RestSBServer, that represents
the REST service exposed by a single or a set of devices.

Change-Id: I0b187151848c20bc1fd8c39a33d57a500f667533
diff --git a/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/DefaultRestSBDevice.java b/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/DefaultRestSBDevice.java
index 40816a4..53ae0dc 100644
--- a/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/DefaultRestSBDevice.java
+++ b/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/DefaultRestSBDevice.java
@@ -16,16 +16,16 @@
 
 package org.onosproject.protocol.rest;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Objects;
-
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
 import org.apache.commons.lang3.StringUtils;
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
 
-import com.google.common.base.MoreObjects;
-import com.google.common.base.Preconditions;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Objects;
+import java.util.Optional;
 
 /**
  * Default implementation for Rest devices.
@@ -40,9 +40,21 @@
     private boolean isActive;
     private String protocol;
     private String url;
+    private boolean isProxy;
+    private final Optional<String> testUrl;
+    private final Optional<String> manufacturer;
+    private final Optional<String> hwVersion;
+    private final Optional<String> swVersion;
 
     public DefaultRestSBDevice(IpAddress ip, int port, String name, String password,
                                String protocol, String url, boolean isActive) {
+        this(ip, port, name, password, protocol, url, isActive, "", "", "", "");
+    }
+
+    public DefaultRestSBDevice(IpAddress ip, int port, String name, String password,
+                               String protocol, String url, boolean isActive, String testUrl, String manufacturer,
+                               String hwVersion,
+                               String swVersion) {
         Preconditions.checkNotNull(ip, "IP address cannot be null");
         Preconditions.checkArgument(port > 0, "Port address cannot be negative");
         Preconditions.checkNotNull(protocol, "protocol address cannot be null");
@@ -53,6 +65,21 @@
         this.isActive = isActive;
         this.protocol = protocol;
         this.url = StringUtils.isEmpty(url) ? null : url;
+        this.manufacturer = StringUtils.isEmpty(manufacturer) ?
+                Optional.empty() : Optional.ofNullable(manufacturer);
+        this.hwVersion = StringUtils.isEmpty(hwVersion) ?
+                Optional.empty() : Optional.ofNullable(hwVersion);
+        this.swVersion = StringUtils.isEmpty(swVersion) ?
+                Optional.empty() : Optional.ofNullable(swVersion);
+        this.testUrl = StringUtils.isEmpty(testUrl) ?
+                Optional.empty() : Optional.ofNullable(testUrl);
+        if (this.manufacturer.isPresent()
+                && this.hwVersion.isPresent()
+                && this.swVersion.isPresent()) {
+            this.isProxy = true;
+        } else {
+            this.isProxy = false;
+        }
     }
 
     @Override
@@ -107,14 +134,45 @@
     }
 
     @Override
+    public boolean isProxy() {
+        return isProxy;
+    }
+
+    @Override
+    public Optional<String> testUrl() {
+        return testUrl;
+    }
+
+    @Override
+    public Optional<String> manufacturer() {
+        return manufacturer;
+    }
+
+    @Override
+    public Optional<String> hwVersion() {
+        return hwVersion;
+    }
+
+    @Override
+    public Optional<String> swVersion() {
+        return swVersion;
+    }
+
+    @Override
     public String toString() {
         return MoreObjects.toStringHelper(this)
+                .omitNullValues()
                 .add("url", url)
+                .add("testUrl", testUrl)
                 .add("protocol", protocol)
                 .add("username", username)
                 .add("port", port)
                 .add("ip", ip)
+                .add("manufacturer", manufacturer.orElse(null))
+                .add("hwVersion", hwVersion.orElse(null))
+                .add("swVersion", swVersion.orElse(null))
                 .toString();
+
     }
 
     @Override
diff --git a/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/RestSBController.java b/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/RestSBController.java
index 2fe3791..bca4a6c 100644
--- a/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/RestSBController.java
+++ b/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/RestSBController.java
@@ -16,11 +16,44 @@
 
 package org.onosproject.protocol.rest;
 
+import org.onosproject.net.DeviceId;
 import org.onosproject.protocol.http.HttpSBController;
 
+import java.util.Set;
+
 /**
  * Abstraction of an REST controller. Serves as a one stop shop for obtaining
- * Rest southbound devices and (un)register listeners.
+ * Rest southbound devices.
  */
 public interface RestSBController extends HttpSBController {
+
+    /**
+     * Add a new association between a proxied device exposed to ONOS and
+     * a REST proxy server.
+     * @param deviceId REST device identifier
+     * @param proxy REST proxy device
+     */
+    void addProxiedDevice(DeviceId deviceId, RestSBDevice proxy);
+
+    /**
+     * Remove the association between a proxied device exposed to ONOS
+     * and a REST proxy server.
+     * @param deviceId REST device identifier
+     */
+    void removeProxiedDevice(DeviceId deviceId);
+
+    /**
+     * Get all the proxied device exposed to ONOS ids under the same
+     * REST proxy server.
+     * @param proxyId REST proxy device identifier
+     * @return set of device ids under same proxy
+     */
+    Set<DeviceId> getProxiedDevices(DeviceId proxyId);
+
+    /**
+     * Get a REST proxied server given a device id.
+     * @param deviceId the id of proxied device exposed to ONOS
+     * @return the corresponding REST proxied device
+     */
+    RestSBDevice getProxySBDevice(DeviceId deviceId);
 }
diff --git a/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/RestSBDevice.java b/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/RestSBDevice.java
index b1f61ac..bacbbfe 100644
--- a/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/RestSBDevice.java
+++ b/protocols/rest/api/src/main/java/org/onosproject/protocol/rest/RestSBDevice.java
@@ -19,6 +19,8 @@
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
 
+import java.util.Optional;
+
 /**
  * Represents an abstraction of a Rest Device in ONOS.
  */
@@ -85,4 +87,39 @@
      * @return url
      */
     String url();
+
+    /**
+     * Returns the proxy state of this device
+     * (if true, the device is proxying multiple ONOS devices).
+     * @return proxy state
+     */
+    boolean isProxy();
+
+    /**
+     * Returns the url for the REST TEST requests.
+     *
+     * @return testUrl
+     */
+    Optional<String> testUrl();
+
+    /**
+     * The manufacturer of the rest device.
+     *
+     * @return the name of the manufacturer
+     */
+    Optional<String> manufacturer();
+
+    /**
+     * The hardware version of the rest device.
+     *
+     * @return the hardware version
+     */
+    Optional<String> hwVersion();
+
+    /**
+     * The software version of rest device.
+     *
+     * @return the software version.
+     */
+    Optional<String> swVersion();
 }