ONOS-4919: Implement RESTCONF client

Adding code to support RESTCONF protocol as one of
the supported SBI protocols of ONOS. This RESTCONF SBI extends
the current REST SBI protocl and adds some new APIs/functinalities
so that a provider can subscribe/register to an external restconf
server to receive notification stream.

Change-Id: I21bf0d0f0394cf788e066d743b3ade04735fe07e
diff --git a/protocols/rest/api/src/main/java/org/onosproject/protocol/http/HttpSBController.java b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/HttpSBController.java
new file mode 100644
index 0000000..1694d2a
--- /dev/null
+++ b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/HttpSBController.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2016-present 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.protocol.http;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.protocol.rest.RestSBDevice;
+
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Abstraction of an HTTP controller. Serves as a one stop shop for obtaining
+ * HTTP southbound devices and (un)register listeners.
+ */
+public interface HttpSBController {
+
+    /**
+     * Returns all the devices known to this controller.
+     *
+     * @return map of devices
+     */
+    Map<DeviceId, RestSBDevice> getDevices();
+
+    /**
+     * Returns a device by node identifier.
+     *
+     * @param deviceInfo node identifier
+     * @return RestSBDevice rest device
+     */
+    RestSBDevice getDevice(DeviceId deviceInfo);
+
+    /**
+     * Returns a device by Ip and Port.
+     *
+     * @param ip   device ip
+     * @param port device port
+     * @return RestSBDevice rest device
+     */
+    RestSBDevice getDevice(IpAddress ip, int port);
+
+    /**
+     * Adds a device to the device map.
+     *
+     * @param device to be added
+     */
+    void addDevice(RestSBDevice device);
+
+    /**
+     * Removes the device from the devices map.
+     *
+     * @param deviceId to be removed
+     */
+    void removeDevice(DeviceId deviceId);
+
+    /**
+     * Does a HTTP POST request with specified parameters to the device.
+     *
+     * @param device    device to make the request to
+     * @param request   url of the request
+     * @param payload   payload of the request as an InputStream
+     * @param mediaType type of content in the payload i.e. application/json
+     * @return true if operation returned 200, 201, 202, false otherwise
+     */
+    boolean post(DeviceId device, String request, InputStream payload, String mediaType);
+
+    /**
+     * Does a HTTP POST request with specified parameters to the device.
+     *
+     * @param <T>           post return type
+     * @param device        device to make the request to
+     * @param request       url of the request
+     * @param payload       payload of the request as an InputStream
+     * @param mediaType     type of content in the payload i.e. application/json
+     * @param responseClass the type of response object we are interested in,
+     *                      such as String, InputStream.
+     * @return Object of type requested via responseClass.
+     */
+    <T> T post(DeviceId device, String request, InputStream payload,
+               String mediaType, Class<T> responseClass);
+
+    /**
+     * Does a HTTP PUT request with specified parameters to the device.
+     *
+     * @param device    device to make the request to
+     * @param request   resource path of the request
+     * @param payload   payload of the request as an InputStream
+     * @param mediaType type of content in the payload i.e. application/json
+     * @return true if operation returned 200, 201, 202, false otherwise
+     */
+    boolean put(DeviceId device, String request, InputStream payload, String mediaType);
+
+    /**
+     * Does a HTTP GET request with specified parameters to the device.
+     *
+     * @param device    device to make the request to
+     * @param request   url of the request
+     * @param mediaType format to retrieve the content in
+     * @return an inputstream of data from the reply.
+     */
+    InputStream get(DeviceId device, String request, String mediaType);
+
+    /**
+     * Does a HTTP PATCH request with specified parameters to the device.
+     *
+     * @param device    device to make the request to
+     * @param request   url of the request
+     * @param payload   payload of the request as an InputStream
+     * @param mediaType format to retrieve the content in
+     * @return true if operation returned 200, 201, 202, false otherwise
+     */
+    boolean patch(DeviceId device, String request, InputStream payload, String mediaType);
+
+    /**
+     * Does a HTTP DELETE request with specified parameters to the device.
+     *
+     * @param device    device to make the request to
+     * @param request   url of the request
+     * @param payload   payload of the request as an InputStream
+     * @param mediaType type of content in the payload i.e. application/json
+     * @return true if operation returned 200 false otherwise
+     */
+    boolean delete(DeviceId device, String request, InputStream payload, String mediaType);
+
+}
diff --git a/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/HttpSBControllerImpl.java b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/HttpSBControllerImpl.java
new file mode 100644
index 0000000..2c2d1a2
--- /dev/null
+++ b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/HttpSBControllerImpl.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2016-present 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.protocol.http.ctl;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.client.methods.HttpPatch;
+import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
+import org.onlab.packet.IpAddress;
+import org.onosproject.net.DeviceId;
+import org.onosproject.protocol.http.HttpSBController;
+import org.onosproject.protocol.rest.RestSBDevice;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The implementation of HttpSBController.
+ */
+public class HttpSBControllerImpl implements HttpSBController {
+
+    private static final Logger log =
+            LoggerFactory.getLogger(HttpSBControllerImpl.class);
+    private static final String XML = "xml";
+    private static final String JSON = "json";
+    private static final String DOUBLESLASH = "//";
+    private static final String COLON = ":";
+    private static final int STATUS_OK = Response.Status.OK.getStatusCode();
+    private static final int STATUS_CREATED = Response.Status.CREATED.getStatusCode();
+    private static final int STATUS_ACCEPTED = Response.Status.ACCEPTED.getStatusCode();
+    private static final String HTTPS = "https";
+    private static final String AUTHORIZATION_PROPERTY = "authorization";
+    private static final String BASIC_AUTH_PREFIX = "Basic ";
+
+    private final Map<DeviceId, RestSBDevice> deviceMap = new ConcurrentHashMap<>();
+    private final Map<DeviceId, Client> clientMap = new ConcurrentHashMap<>();
+
+    public Map<DeviceId, RestSBDevice> getDeviceMap() {
+        return deviceMap;
+    }
+
+    public Map<DeviceId, Client> getClientMap() {
+        return clientMap;
+    }
+
+    @Override
+    public Map<DeviceId, RestSBDevice> getDevices() {
+        return ImmutableMap.copyOf(deviceMap);
+    }
+
+    @Override
+    public RestSBDevice getDevice(DeviceId deviceInfo) {
+        return deviceMap.get(deviceInfo);
+    }
+
+    @Override
+    public RestSBDevice getDevice(IpAddress ip, int port) {
+        return deviceMap.values().stream().filter(v -> v.ip().equals(ip)
+                && v.port() == port).findFirst().get();
+    }
+
+    @Override
+    public void addDevice(RestSBDevice device) {
+        if (!deviceMap.containsKey(device.deviceId())) {
+            Client client = ignoreSslClient();
+            if (device.username() != null) {
+                String username = device.username();
+                String password = device.password() == null ? "" : device.password();
+                authenticate(client, username, password);
+            }
+            clientMap.put(device.deviceId(), client);
+            deviceMap.put(device.deviceId(), device);
+        } else {
+            log.warn("Trying to add a device that is already existing {}", device.deviceId());
+        }
+
+    }
+
+    @Override
+    public void removeDevice(DeviceId deviceId) {
+        clientMap.remove(deviceId);
+        deviceMap.remove(deviceId);
+    }
+
+    @Override
+    public boolean post(DeviceId device, String request, InputStream payload, String mediaType) {
+        Response response = getResponse(device, request, payload, mediaType);
+        return checkReply(response);
+    }
+
+    @Override
+    public <T> T post(DeviceId device, String request, InputStream payload,
+                      String mediaType, Class<T> responseClass) {
+        Response response = getResponse(device, request, payload, mediaType);
+        if (response.hasEntity()) {
+            return response.readEntity(responseClass);
+        }
+        log.error("Response from device {} for request {} contains no entity", device, request);
+        return null;
+    }
+
+    private Response getResponse(DeviceId device, String request, InputStream payload, String mediaType) {
+        String type = typeOfMediaType(mediaType);
+
+        WebTarget wt = getWebTarget(device, request);
+
+        Response response = null;
+        if (payload != null) {
+            try {
+                response = wt.request(type)
+                        .post(Entity.entity(IOUtils.toString(payload, StandardCharsets.UTF_8), type));
+            } catch (IOException e) {
+                log.error("Cannot do POST {} request on device {} because can't read payload",
+                          request, device);
+            }
+        } else {
+            response = wt.request(type).post(Entity.entity(null, type));
+        }
+        return response;
+    }
+
+    @Override
+    public boolean put(DeviceId device, String request, InputStream payload, String mediaType) {
+        String type = typeOfMediaType(mediaType);
+
+        WebTarget wt = getWebTarget(device, request);
+
+        Response response = null;
+        if (payload != null) {
+            try {
+                response = wt.request(type)
+                        .put(Entity.entity(IOUtils.toString(payload, StandardCharsets.UTF_8), type));
+            } catch (IOException e) {
+                log.error("Cannot do PUT {} request on device {} because can't read payload",
+                          request, device);
+            }
+        } else {
+            response = wt.request(type).put(Entity.entity(null, type));
+        }
+        return checkReply(response);
+    }
+
+    @Override
+    public InputStream get(DeviceId device, String request, String mediaType) {
+        String type = typeOfMediaType(mediaType);
+
+        WebTarget wt = getWebTarget(device, request);
+
+        Response s = wt.request(type).get();
+
+        if (checkReply(s)) {
+            return new ByteArrayInputStream(s.readEntity((String.class))
+                    .getBytes(StandardCharsets.UTF_8));
+        }
+        return null;
+    }
+
+    @Override
+    public boolean patch(DeviceId device, String request, InputStream payload, String mediaType) {
+        String type = typeOfMediaType(mediaType);
+
+        try {
+            log.debug("Url request {} ", getUrlString(device, request));
+            HttpPatch httprequest = new HttpPatch(getUrlString(device, request));
+            if (deviceMap.get(device).username() != null) {
+                String pwd = deviceMap.get(device).password() == null ? "" : COLON + deviceMap.get(device).password();
+                String userPassword = deviceMap.get(device).username() + pwd;
+                String base64string = Base64.getEncoder().encodeToString(userPassword.getBytes(StandardCharsets.UTF_8));
+                httprequest.addHeader(AUTHORIZATION_PROPERTY, BASIC_AUTH_PREFIX + base64string);
+            }
+            if (payload != null) {
+                StringEntity input = new StringEntity(IOUtils.toString(payload, StandardCharsets.UTF_8));
+                input.setContentType(type);
+                httprequest.setEntity(input);
+            }
+            CloseableHttpClient httpClient;
+            if (deviceMap.containsKey(device) && deviceMap.get(device).protocol().equals(HTTPS)) {
+                httpClient = getApacheSslBypassClient();
+            } else {
+                httpClient = HttpClients.createDefault();
+            }
+            int responseStatusCode = httpClient
+                    .execute(httprequest)
+                    .getStatusLine()
+                    .getStatusCode();
+            return checkStatusCode(responseStatusCode);
+        } catch (IOException | NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
+            log.error("Cannot do PATCH {} request on device {}",
+                      request, device, e);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean delete(DeviceId device, String request, InputStream payload, String mediaType) {
+        String type = typeOfMediaType(mediaType);
+
+        WebTarget wt = getWebTarget(device, request);
+
+        // FIXME: do we need to delete an entry by enclosing data in DELETE request?
+        // wouldn't it be nice to use PUT to implement the similar concept?
+        Response response = wt.request(type).delete();
+
+        return checkReply(response);
+    }
+
+    private String typeOfMediaType(String mediaType) {
+        String type;
+        switch (mediaType) {
+            case XML:
+                type = MediaType.APPLICATION_XML;
+                break;
+            case JSON:
+                type = MediaType.APPLICATION_JSON;
+                break;
+            default:
+                throw new IllegalArgumentException("Unsupported media type " + mediaType);
+
+        }
+        return type;
+    }
+
+    private void authenticate(Client client, String username, String password) {
+        client.register(HttpAuthenticationFeature.basic(username, password));
+    }
+
+    protected WebTarget getWebTarget(DeviceId device, String request) {
+        log.debug("Sending request to URL {} ", getUrlString(device, request));
+        return clientMap.get(device).target(getUrlString(device, request));
+    }
+
+    //FIXME security issue: this trusts every SSL certificate, even if is self-signed. Also deprecated methods.
+    private CloseableHttpClient getApacheSslBypassClient() throws NoSuchAlgorithmException,
+            KeyManagementException, KeyStoreException {
+        return HttpClients.custom().
+                setHostnameVerifier(new AllowAllHostnameVerifier()).
+                setSslcontext(new SSLContextBuilder()
+                                      .loadTrustMaterial(null, (arg0, arg1) -> true)
+                                      .build()).build();
+    }
+
+    private String getUrlString(DeviceId device, String request) {
+        if (deviceMap.get(device).url() != null) {
+            return deviceMap.get(device).protocol() + COLON + DOUBLESLASH
+                    + deviceMap.get(device).url() + request;
+        } else {
+            return deviceMap.get(device).protocol() + COLON +
+                    DOUBLESLASH +
+                    deviceMap.get(device).ip().toString() +
+                    COLON + deviceMap.get(device).port() + request;
+        }
+    }
+
+    private boolean checkReply(Response response) {
+        if (response != null) {
+            return checkStatusCode(response.getStatus());
+        }
+        log.error("Null reply from device");
+        return false;
+    }
+
+    private boolean checkStatusCode(int statusCode) {
+        if (statusCode == STATUS_OK ||
+                statusCode == STATUS_CREATED ||
+                statusCode == STATUS_ACCEPTED) {
+            return true;
+        } else {
+            log.error("Failed request, HTTP error code : "
+                              + statusCode);
+            return false;
+        }
+    }
+
+    private Client ignoreSslClient() {
+        SSLContext sslcontext = null;
+
+        try {
+            sslcontext = SSLContext.getInstance("TLS");
+            sslcontext.init(null, new TrustManager[]{new X509TrustManager() {
+                public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+                }
+
+                public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+                }
+
+                public X509Certificate[] getAcceptedIssuers() {
+                    return new X509Certificate[0];
+                }
+            } }, new java.security.SecureRandom());
+        } catch (NoSuchAlgorithmException | KeyManagementException e) {
+            e.printStackTrace();
+        }
+
+        return ClientBuilder.newBuilder().sslContext(sslcontext).hostnameVerifier((s1, s2) -> true).build();
+    }
+}
diff --git a/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/package-info.java b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/package-info.java
new file mode 100644
index 0000000..e6fe54d
--- /dev/null
+++ b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/ctl/package-info.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright 2016-present 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.
+ */
+/**
+ * @author onos
+ *
+ */
+package org.onosproject.protocol.http.ctl;
diff --git a/protocols/rest/api/src/main/java/org/onosproject/protocol/http/package-info.java b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/package-info.java
new file mode 100644
index 0000000..c54b035
--- /dev/null
+++ b/protocols/rest/api/src/main/java/org/onosproject/protocol/http/package-info.java
@@ -0,0 +1,20 @@
+/**
+ * Copyright 2016-present 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.
+ */
+/**
+ * @author onos
+ *
+ */
+package org.onosproject.protocol.http;
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 6a8e5a9..40816a4 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,15 +16,16 @@
 
 package org.onosproject.protocol.rest;
 
-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 org.apache.commons.lang3.StringUtils;
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
 
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Objects;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
 
 /**
  * Default implementation for Rest devices.
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 b51b12f..2fe3791 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,123 +16,11 @@
 
 package org.onosproject.protocol.rest;
 
-import org.onlab.packet.IpAddress;
-import org.onosproject.net.DeviceId;
-
-import java.io.InputStream;
-import java.util.Map;
+import org.onosproject.protocol.http.HttpSBController;
 
 /**
  * Abstraction of an REST controller. Serves as a one stop shop for obtaining
  * Rest southbound devices and (un)register listeners.
  */
-public interface RestSBController {
-
-    /**
-     * Returns all the devices known to this controller.
-     *
-     * @return map of devices
-     */
-    Map<DeviceId, RestSBDevice> getDevices();
-
-    /**
-     * Returns a device by node identifier.
-     *
-     * @param deviceInfo node identifier
-     * @return RestSBDevice rest device
-     */
-    RestSBDevice getDevice(DeviceId deviceInfo);
-
-    /**
-     * Returns a device by Ip and Port.
-     *
-     * @param ip   device ip
-     * @param port device port
-     * @return RestSBDevice rest device
-     */
-    RestSBDevice getDevice(IpAddress ip, int port);
-
-    /**
-     * Adds a device to the device map.
-     *
-     * @param device to be added
-     */
-    void addDevice(RestSBDevice device);
-
-    /**
-     * Removes the device from the devices map.
-     *
-     * @param deviceId to be removed
-     */
-    void removeDevice(DeviceId deviceId);
-
-    /**
-     * Does a REST POST request with specified parameters to the device.
-     *
-     * @param device    device to make the request to
-     * @param request   url of the request
-     * @param payload   payload of the request as an InputStream
-     * @param mediaType type of content in the payload i.e. application/json
-     * @return true if operation returned 200, 201, 202, false otherwise
-     */
-    boolean post(DeviceId device, String request, InputStream payload, String mediaType);
-
-    /**
-     * Does a REST POST request with specified parameters to the device.
-     *
-     * @param <T>           post return type
-     * @param device        device to make the request to
-     * @param request       url of the request
-     * @param payload       payload of the request as an InputStream
-     * @param mediaType     type of content in the payload i.e. application/json
-     * @param responseClass the type of response object we are interested in,
-     *                      such as String, InputStream.
-     * @return Object of type requested via responseClass.
-     */
-    <T> T post(DeviceId device, String request, InputStream payload,
-               String mediaType, Class<T> responseClass);
-
-    /**
-     * Does a REST PUT request with specified parameters to the device.
-     *
-     * @param device    device to make the request to
-     * @param request   resource path of the request
-     * @param payload   payload of the request as an InputStream
-     * @param mediaType type of content in the payload i.e. application/json
-     * @return true if operation returned 200, 201, 202, false otherwise
-     */
-    boolean put(DeviceId device, String request, InputStream payload, String mediaType);
-
-    /**
-     * Does a REST GET request with specified parameters to the device.
-     *
-     * @param device    device to make the request to
-     * @param request   url of the request
-     * @param mediaType format to retrieve the content in
-     * @return an inputstream of data from the reply.
-     */
-    InputStream get(DeviceId device, String request, String mediaType);
-
-    /**
-     * Does a REST PATCH request with specified parameters to the device.
-     *
-     * @param device    device to make the request to
-     * @param request   url of the request
-     * @param payload   payload of the request as an InputStream
-     * @param mediaType format to retrieve the content in
-     * @return true if operation returned 200, 201, 202, false otherwise
-     */
-    boolean patch(DeviceId device, String request, InputStream payload, String mediaType);
-
-    /**
-     * Does a REST DELETE request with specified parameters to the device.
-     *
-     * @param device    device to make the request to
-     * @param request   url of the request
-     * @param payload   payload of the request as an InputStream
-     * @param mediaType type of content in the payload i.e. application/json
-     * @return true if operation returned 200 false otherwise
-     */
-    boolean delete(DeviceId device, String request, InputStream payload, String mediaType);
-
+public interface RestSBController extends HttpSBController {
 }