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/ctl/src/main/java/org/onosproject/protocol/rest/ctl/RestSBControllerImpl.java b/protocols/rest/ctl/src/main/java/org/onosproject/protocol/rest/ctl/RestSBControllerImpl.java
index 37dfc85..86f8020 100644
--- a/protocols/rest/ctl/src/main/java/org/onosproject/protocol/rest/ctl/RestSBControllerImpl.java
+++ b/protocols/rest/ctl/src/main/java/org/onosproject/protocol/rest/ctl/RestSBControllerImpl.java
@@ -16,15 +16,24 @@
 
 package org.onosproject.protocol.rest.ctl;
 
+import com.google.common.collect.ImmutableSet;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Service;
+import org.onosproject.net.DeviceId;
 import org.onosproject.protocol.http.ctl.HttpSBControllerImpl;
 import org.onosproject.protocol.rest.RestSBController;
+import org.onosproject.protocol.rest.RestSBDevice;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.ws.rs.client.WebTarget;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
 /**
  * The implementation of RestSBController.
  */
@@ -35,6 +44,8 @@
     private static final Logger log =
             LoggerFactory.getLogger(RestSBControllerImpl.class);
 
+    private final Map<DeviceId, RestSBDevice> proxiedDeviceMap = new ConcurrentHashMap<>();
+
     @Activate
     public void activate() {
         log.info("Started");
@@ -47,4 +58,64 @@
         log.info("Stopped");
     }
 
+
+    @Override
+    public void addProxiedDevice(DeviceId deviceId, RestSBDevice proxy) {
+        proxiedDeviceMap.put(deviceId, proxy);
+        log.debug("Added device: {} to proxy {}", deviceId, proxy.deviceId());
+    }
+
+    @Override
+    public void removeProxiedDevice(DeviceId deviceId) {
+        log.debug("Removed device: {} from proxy {}", deviceId, proxiedDeviceMap.get(deviceId).deviceId());
+        proxiedDeviceMap.remove(deviceId);
+    }
+
+
+    @Override
+    public Set<DeviceId> getProxiedDevices(DeviceId proxyId) {
+        return ImmutableSet.copyOf(
+                proxiedDeviceMap.keySet().stream().filter(
+                        v -> proxiedDeviceMap.get(v).deviceId().equals(proxyId)
+                ).collect(Collectors.toSet()));
+    }
+
+    @Override
+    public RestSBDevice getProxySBDevice(DeviceId deviceId) {
+        return proxiedDeviceMap.get(deviceId);
+    }
+
+    @Override
+    protected WebTarget getWebTarget(DeviceId device, String request) {
+        DeviceId deviceId = device;
+        if (proxiedDeviceMap.containsKey(device)) {
+            deviceId = proxiedDeviceMap.get(device).deviceId();
+        }
+        return super.getWebTarget(deviceId, request);
+    }
+
+    @Override
+    protected String getUrlString(DeviceId id, String request) {
+        DeviceId deviceId = id;
+        if (proxiedDeviceMap.containsKey(id)) {
+            deviceId = proxiedDeviceMap.get(id).deviceId();
+        }
+
+        RestSBDevice device = super.getDeviceMap().get(deviceId);
+        if (device != null) {
+            if (device.url() != null && !device.url().isEmpty()) {
+                return device.protocol() + super.COLON + super.DOUBLESLASH + device.ip().toString() +
+                        super.COLON + device.port()
+                        + device.url() + request;
+            } else {
+                return device.protocol() + super.COLON +
+                        super.DOUBLESLASH +
+                        device.ip().toString() +
+                        super.COLON + device.port() + request;
+            }
+        } else {
+            return super.getUrlString(deviceId, request);
+        }
+
+    }
 }