[bindings a-c] Fix exception handling (Jetty HTTP client) (#10467)

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo
2021-04-06 17:30:12 +02:00
committed by GitHub
parent a509c3b638
commit fed460218e
6 changed files with 148 additions and 114 deletions

View File

@@ -18,8 +18,10 @@ import java.util.Base64;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -190,88 +192,94 @@ public class AutelisHandler extends BaseThingHandler {
@Override @Override
public void handleCommand(ChannelUID channelUID, Command command) { public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("handleCommand channel: {} command: {}", channelUID.getId(), command); try {
if (AutelisBindingConstants.CMD_LIGHTS.equals(channelUID.getId())) { logger.debug("handleCommand channel: {} command: {}", channelUID.getId(), command);
/* if (AutelisBindingConstants.CMD_LIGHTS.equals(channelUID.getId())) {
* lighting command possible values, but we will let anything /*
* through. alloff, allon, csync, cset, cswim, party, romance, * lighting command possible values, but we will let anything
* caribbean, american, sunset, royalty, blue, green, red, white, * through. alloff, allon, csync, cset, cswim, party, romance,
* magenta, hold, recall * caribbean, american, sunset, royalty, blue, green, red, white,
*/ * magenta, hold, recall
getUrl(baseURL + "/lights.cgi?val=" + command.toString(), TIMEOUT_SECONDS); */
} else if (AutelisBindingConstants.CMD_REBOOT.equals(channelUID.getId()) && command == OnOffType.ON) { getUrl(baseURL + "/lights.cgi?val=" + command.toString(), TIMEOUT_SECONDS);
getUrl(baseURL + "/userreboot.cgi?do=true" + command.toString(), TIMEOUT_SECONDS); } else if (AutelisBindingConstants.CMD_REBOOT.equals(channelUID.getId()) && command == OnOffType.ON) {
updateState(channelUID, OnOffType.OFF); getUrl(baseURL + "/userreboot.cgi?do=true" + command.toString(), TIMEOUT_SECONDS);
} else { updateState(channelUID, OnOffType.OFF);
String[] args = channelUID.getId().split("-");
if (args.length < 2) {
logger.warn("Unown channel {} for command {}", channelUID, command);
return;
}
String type = args[0];
String name = args[1];
if (AutelisBindingConstants.CMD_EQUIPMENT.equals(type)) {
String cmd = "value";
int value;
if (command == OnOffType.OFF) {
value = 0;
} else if (command == OnOffType.ON) {
value = 1;
} else if (command instanceof DecimalType) {
value = ((DecimalType) command).intValue();
if (!isJandy() && value >= 3) {
// this is a autelis dim type. not sure what 2 does
cmd = "dim";
}
} else {
logger.error("command type {} is not supported", command);
return;
}
String response = getUrl(baseURL + "/set.cgi?name=" + name + "&" + cmd + "=" + value, TIMEOUT_SECONDS);
logger.debug("equipment set {} {} {} : result {}", name, cmd, value, response);
} else if (AutelisBindingConstants.CMD_TEMP.equals(type)) {
String value;
if (command == IncreaseDecreaseType.INCREASE) {
value = "up";
} else if (command == IncreaseDecreaseType.DECREASE) {
value = "down";
} else if (command == OnOffType.OFF) {
value = "0";
} else if (command == OnOffType.ON) {
value = "1";
} else {
value = command.toString();
}
String cmd;
// name ending in sp are setpoints, ht are heater?
if (name.endsWith("sp")) {
cmd = "temp";
} else if (name.endsWith("ht")) {
cmd = "hval";
} else {
logger.error("Unknown temp type {}", name);
return;
}
String response = getUrl(baseURL + "/set.cgi?wait=1&name=" + name + "&" + cmd + "=" + value,
TIMEOUT_SECONDS);
logger.debug("temp set name:{} cmd:{} value:{} : result {}", name, cmd, value, response);
} else if (AutelisBindingConstants.CMD_CHEM.equals(type)) {
String response = getUrl(baseURL + "/set.cgi?name=" + name + "&chem=" + command.toString(),
TIMEOUT_SECONDS);
logger.debug("chlrp {} {}: result {}", name, command, response);
} else if (AutelisBindingConstants.CMD_PUMPS.equals(type)) {
String response = getUrl(baseURL + "/set.cgi?name=" + name + "&speed=" + command.toString(),
TIMEOUT_SECONDS);
logger.debug("pumps {} {}: result {}", name, command, response);
} else { } else {
logger.error("Unsupported type {}", type); String[] args = channelUID.getId().split("-");
if (args.length < 2) {
logger.warn("Unown channel {} for command {}", channelUID, command);
return;
}
String type = args[0];
String name = args[1];
if (AutelisBindingConstants.CMD_EQUIPMENT.equals(type)) {
String cmd = "value";
int value;
if (command == OnOffType.OFF) {
value = 0;
} else if (command == OnOffType.ON) {
value = 1;
} else if (command instanceof DecimalType) {
value = ((DecimalType) command).intValue();
if (!isJandy() && value >= 3) {
// this is a autelis dim type. not sure what 2 does
cmd = "dim";
}
} else {
logger.error("command type {} is not supported", command);
return;
}
String response = getUrl(baseURL + "/set.cgi?name=" + name + "&" + cmd + "=" + value,
TIMEOUT_SECONDS);
logger.debug("equipment set {} {} {} : result {}", name, cmd, value, response);
} else if (AutelisBindingConstants.CMD_TEMP.equals(type)) {
String value;
if (command == IncreaseDecreaseType.INCREASE) {
value = "up";
} else if (command == IncreaseDecreaseType.DECREASE) {
value = "down";
} else if (command == OnOffType.OFF) {
value = "0";
} else if (command == OnOffType.ON) {
value = "1";
} else {
value = command.toString();
}
String cmd;
// name ending in sp are setpoints, ht are heater?
if (name.endsWith("sp")) {
cmd = "temp";
} else if (name.endsWith("ht")) {
cmd = "hval";
} else {
logger.error("Unknown temp type {}", name);
return;
}
String response = getUrl(baseURL + "/set.cgi?wait=1&name=" + name + "&" + cmd + "=" + value,
TIMEOUT_SECONDS);
logger.debug("temp set name:{} cmd:{} value:{} : result {}", name, cmd, value, response);
} else if (AutelisBindingConstants.CMD_CHEM.equals(type)) {
String response = getUrl(baseURL + "/set.cgi?name=" + name + "&chem=" + command.toString(),
TIMEOUT_SECONDS);
logger.debug("chlrp {} {}: result {}", name, command, response);
} else if (AutelisBindingConstants.CMD_PUMPS.equals(type)) {
String response = getUrl(baseURL + "/set.cgi?name=" + name + "&speed=" + command.toString(),
TIMEOUT_SECONDS);
logger.debug("pumps {} {}: result {}", name, command, response);
} else {
logger.error("Unsupported type {}", type);
}
} }
clearState(true);
// reset the schedule for our next poll which at that time will reflect if our command was successful or
// not.
initPolling(COMMAND_UPDATE_TIME_SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} }
clearState(true);
// reset the schedule for our next poll which at that time will reflect if our command was successful or not.
initPolling(COMMAND_UPDATE_TIME_SECONDS);
} }
/** /**
@@ -349,7 +357,7 @@ public class AutelisHandler extends BaseThingHandler {
* Poll the Autelis controller for updates. This will retrieve various xml documents and update channel states from * Poll the Autelis controller for updates. This will retrieve various xml documents and update channel states from
* its contents. * its contents.
*/ */
private void pollAutelisController() { private void pollAutelisController() throws InterruptedException {
logger.trace("Connecting to {}", baseURL); logger.trace("Connecting to {}", baseURL);
// clear our cached stated IF it is time. // clear our cached stated IF it is time.
@@ -466,16 +474,13 @@ public class AutelisHandler extends BaseThingHandler {
* @param timeout * @param timeout
* @return * @return
*/ */
private synchronized String getUrl(String url, int timeout) { private synchronized String getUrl(String url, int timeout) throws InterruptedException {
// throttle commands for a very short time to avoid 'loosing' them // throttle commands for a very short time to avoid 'loosing' them
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
long nextReq = lastRequestTime + THROTTLE_TIME_MILLISECONDS; long nextReq = lastRequestTime + THROTTLE_TIME_MILLISECONDS;
if (nextReq > now) { if (nextReq > now) {
try { logger.trace("Throttling request for {} mills", nextReq - now);
logger.trace("Throttling request for {} mills", nextReq - now); Thread.sleep(nextReq - now);
Thread.sleep(nextReq - now);
} catch (InterruptedException ignored) {
}
} }
String getURL = url + (url.contains("?") ? "&" : "?") + "timestamp=" + System.currentTimeMillis(); String getURL = url + (url.contains("?") ? "&" : "?") + "timestamp=" + System.currentTimeMillis();
logger.trace("Getting URL {} ", getURL); logger.trace("Getting URL {} ", getURL);
@@ -490,7 +495,7 @@ public class AutelisHandler extends BaseThingHandler {
} }
lastRequestTime = System.currentTimeMillis(); lastRequestTime = System.currentTimeMillis();
return response.getContentAsString(); return response.getContentAsString();
} catch (Exception e) { } catch (ExecutionException | TimeoutException e) {
logger.debug("Could not make http connection", e); logger.debug("Could not make http connection", e);
} }
return null; return null;

View File

@@ -90,7 +90,10 @@ public class AutomowerConnectApi extends HusqvarnaApi {
ContentResponse response; ContentResponse response;
try { try {
response = request.send(); response = request.send();
} catch (InterruptedException | TimeoutException | ExecutionException e) { } catch (TimeoutException | ExecutionException e) {
throw new AutomowerCommunicationException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new AutomowerCommunicationException(e); throw new AutomowerCommunicationException(e);
} }
return response; return response;

View File

@@ -242,9 +242,13 @@ public class FritzAhaWebInterface {
String content = contentResponse.getContentAsString(); String content = contentResponse.getContentAsString();
logger.debug("GET response complete: {}", content); logger.debug("GET response complete: {}", content);
return content; return content;
} catch (ExecutionException | InterruptedException | TimeoutException e) { } catch (ExecutionException | TimeoutException e) {
logger.debug("response failed: {}", e.getLocalizedMessage(), e); logger.debug("response failed: {}", e.getLocalizedMessage(), e);
return null; return null;
} catch (InterruptedException e) {
logger.debug("response interrupted: {}", e.getLocalizedMessage(), e);
Thread.currentThread().interrupt();
return null;
} }
} }

View File

@@ -56,7 +56,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
class DeviceService<TState extends BoschSHCServiceState> { class DeviceService<TState extends BoschSHCServiceState> {
/** /**
* Constructor. * Constructor.
* *
* @param service Service which belongs to the device. * @param service Service which belongs to the device.
* @param affectedChannels Channels which are affected by the state of this service. * @param affectedChannels Channels which are affected by the state of this service.
*/ */
@@ -99,7 +99,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
/** /**
* Returns the unique id of the Bosch device. * Returns the unique id of the Bosch device.
* *
* @return Unique id of the Bosch device. * @return Unique id of the Bosch device.
*/ */
public @Nullable String getBoschID() { public @Nullable String getBoschID() {
@@ -132,7 +132,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
/** /**
* Handles the refresh command of all registered services. Override it to handle custom commands (e.g. to update * Handles the refresh command of all registered services. Override it to handle custom commands (e.g. to update
* states of services). * states of services).
* *
* @param channelUID {@link ChannelUID} of the channel to which the command was sent * @param channelUID {@link ChannelUID} of the channel to which the command was sent
* @param command {@link Command} * @param command {@link Command}
*/ */
@@ -144,10 +144,15 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
if (deviceService.affectedChannels.contains(channelUID.getIdWithoutGroup())) { if (deviceService.affectedChannels.contains(channelUID.getIdWithoutGroup())) {
try { try {
deviceService.service.refreshState(); deviceService.service.refreshState();
} catch (InterruptedException | TimeoutException | ExecutionException | BoschSHCException e) { } catch (TimeoutException | ExecutionException | BoschSHCException e) {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
String.format("Error when trying to refresh state from service %s: %s", String.format("Error when trying to refresh state from service %s: %s",
deviceService.service.getServiceName(), e.getMessage())); deviceService.service.getServiceName(), e.getMessage()));
} catch (InterruptedException e) {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
String.format("Interrupted refresh state from service %s: %s",
deviceService.service.getServiceName(), e.getMessage()));
Thread.currentThread().interrupt();
} }
} }
} }
@@ -156,7 +161,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
/** /**
* Processes an update which is received from the bridge. * Processes an update which is received from the bridge.
* *
* @param serviceName Name of service the update came from. * @param serviceName Name of service the update came from.
* @param stateData Current state of device service. Serialized as JSON. * @param stateData Current state of device service. Serialized as JSON.
*/ */
@@ -178,7 +183,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
/** /**
* Returns the bridge handler for this thing handler. * Returns the bridge handler for this thing handler.
* *
* @return Bridge handler for this thing handler. Null if no or an invalid bridge was set in the configuration. * @return Bridge handler for this thing handler. Null if no or an invalid bridge was set in the configuration.
* @throws BoschSHCException If bridge for handler is not set or an invalid bridge is set. * @throws BoschSHCException If bridge for handler is not set or an invalid bridge is set.
*/ */
@@ -196,7 +201,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
/** /**
* Query the Bosch Smart Home Controller for the state of the service with the specified name. * Query the Bosch Smart Home Controller for the state of the service with the specified name.
* *
* @note Use services instead of directly requesting a state. * @note Use services instead of directly requesting a state.
* *
* @param stateName Name of the service to query * @param stateName Name of the service to query
@@ -210,16 +215,21 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
try { try {
BoschSHCBridgeHandler bridgeHandler = this.getBridgeHandler(); BoschSHCBridgeHandler bridgeHandler = this.getBridgeHandler();
return bridgeHandler.getState(deviceId, stateName, classOfT); return bridgeHandler.getState(deviceId, stateName, classOfT);
} catch (InterruptedException | TimeoutException | ExecutionException | BoschSHCException e) { } catch (TimeoutException | ExecutionException | BoschSHCException e) {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
String.format("Error when trying to refresh state from service %s: %s", stateName, e.getMessage())); String.format("Error when trying to refresh state from service %s: %s", stateName, e.getMessage()));
return null; return null;
} catch (InterruptedException e) {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
String.format("Interrupted refresh state from service %s: %s", stateName, e.getMessage()));
Thread.currentThread().interrupt();
return null;
} }
} }
/** /**
* Creates and registers a new service for this device. * Creates and registers a new service for this device.
* *
* @param <TService> Type of service. * @param <TService> Type of service.
* @param <TState> Type of service state. * @param <TState> Type of service state.
* @param newService Supplier function to create a new instance of the service. * @param newService Supplier function to create a new instance of the service.
@@ -240,7 +250,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
/** /**
* Registers a service for this device. * Registers a service for this device.
* *
* @param <TService> Type of service. * @param <TService> Type of service.
* @param <TState> Type of service state. * @param <TState> Type of service state.
* @param service Service to register. * @param service Service to register.
@@ -269,7 +279,7 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
/** /**
* Updates the state of a device service. * Updates the state of a device service.
* Sets the status of the device to offline if setting the state fails. * Sets the status of the device to offline if setting the state fails.
* *
* @param <TService> Type of service. * @param <TService> Type of service.
* @param <TState> Type of service state. * @param <TState> Type of service state.
* @param service Service to set state for. * @param service Service to set state for.
@@ -279,15 +289,19 @@ public abstract class BoschSHCHandler extends BaseThingHandler {
TService service, TState state) { TService service, TState state) {
try { try {
service.setState(state); service.setState(state);
} catch (InterruptedException | TimeoutException | ExecutionException e) { } catch (TimeoutException | ExecutionException e) {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, String.format( this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, String.format(
"Error when trying to update state for service %s: %s", service.getServiceName(), e.getMessage())); "Error when trying to update state for service %s: %s", service.getServiceName(), e.getMessage()));
} catch (InterruptedException e) {
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, String
.format("Interrupted update state for service %s: %s", service.getServiceName(), e.getMessage()));
Thread.currentThread().interrupt();
} }
} }
/** /**
* Registers a service of this device. * Registers a service of this device.
* *
* @param service Service which belongs to this device * @param service Service which belongs to this device
* @param affectedChannels Channels which are affected by the state of this * @param affectedChannels Channels which are affected by the state of this
* service * service

View File

@@ -12,8 +12,7 @@
*/ */
package org.openhab.binding.boschshc.internal.devices.bridge; package org.openhab.binding.boschshc.internal.devices.bridge;
import static org.eclipse.jetty.http.HttpMethod.GET; import static org.eclipse.jetty.http.HttpMethod.*;
import static org.eclipse.jetty.http.HttpMethod.PUT;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
@@ -30,7 +29,10 @@ import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.openhab.binding.boschshc.internal.devices.BoschSHCHandler; import org.openhab.binding.boschshc.internal.devices.BoschSHCHandler;
import org.openhab.binding.boschshc.internal.devices.bridge.dto.*; import org.openhab.binding.boschshc.internal.devices.bridge.dto.Device;
import org.openhab.binding.boschshc.internal.devices.bridge.dto.DeviceStatusUpdate;
import org.openhab.binding.boschshc.internal.devices.bridge.dto.LongPollResult;
import org.openhab.binding.boschshc.internal.devices.bridge.dto.Room;
import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException; import org.openhab.binding.boschshc.internal.exceptions.BoschSHCException;
import org.openhab.binding.boschshc.internal.exceptions.LongPollingFailedException; import org.openhab.binding.boschshc.internal.exceptions.LongPollingFailedException;
import org.openhab.binding.boschshc.internal.exceptions.PairingFailedException; import org.openhab.binding.boschshc.internal.exceptions.PairingFailedException;
@@ -233,12 +235,13 @@ public class BoschSHCBridgeHandler extends BaseBridgeHandler {
} catch (InterruptedException e) { } catch (InterruptedException e) {
this.updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.UNKNOWN.NONE, "@text/offline.interrupted"); this.updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.UNKNOWN.NONE, "@text/offline.interrupted");
Thread.currentThread().interrupt();
} }
} }
/** /**
* Get a list of connected devices from the Smart-Home Controller * Get a list of connected devices from the Smart-Home Controller
* *
* @throws InterruptedException in case bridge is stopped * @throws InterruptedException in case bridge is stopped
*/ */
private boolean getDevices() throws InterruptedException { private boolean getDevices() throws InterruptedException {
@@ -354,7 +357,7 @@ public class BoschSHCBridgeHandler extends BaseBridgeHandler {
/** /**
* Get a list of rooms from the Smart-Home controller * Get a list of rooms from the Smart-Home controller
* *
* @throws InterruptedException in case bridge is stopped * @throws InterruptedException in case bridge is stopped
*/ */
private boolean getRooms() throws InterruptedException { private boolean getRooms() throws InterruptedException {
@@ -451,11 +454,11 @@ public class BoschSHCBridgeHandler extends BaseBridgeHandler {
/** /**
* Sends a state change for a device to the controller * Sends a state change for a device to the controller
* *
* @param deviceId Id of device to change state for * @param deviceId Id of device to change state for
* @param serviceName Name of service of device to change state for * @param serviceName Name of service of device to change state for
* @param state New state data to set for service * @param state New state data to set for service
* *
* @return Response of request * @return Response of request
* @throws InterruptedException * @throws InterruptedException
* @throws ExecutionException * @throws ExecutionException

View File

@@ -37,7 +37,7 @@ import com.google.gson.Gson;
/** /**
* Handles the long polling to the Smart Home Controller. * Handles the long polling to the Smart Home Controller.
* *
* @author Christian Oeing - Initial contribution * @author Christian Oeing - Initial contribution
*/ */
@NonNullByDefault @NonNullByDefault
@@ -100,7 +100,7 @@ public class LongPolling {
/** /**
* Subscribe to events and store the subscription ID needed for long polling. * Subscribe to events and store the subscription ID needed for long polling.
* *
* @param httpClient Http client to use for sending subscription request * @param httpClient Http client to use for sending subscription request
* @return Subscription id * @return Subscription id
*/ */
@@ -116,16 +116,21 @@ public class LongPolling {
logger.debug("Subscribe: Got subscription ID: {} {}", response.getResult(), response.getJsonrpc()); logger.debug("Subscribe: Got subscription ID: {} {}", response.getResult(), response.getJsonrpc());
String subscriptionId = response.getResult(); String subscriptionId = response.getResult();
return subscriptionId; return subscriptionId;
} catch (TimeoutException | ExecutionException | InterruptedException e) { } catch (TimeoutException | ExecutionException e) {
throw new LongPollingFailedException( throw new LongPollingFailedException(
String.format("Error on subscribe (Http client: %s): %s", httpClient.toString(), e.getMessage()), String.format("Error on subscribe (Http client: %s): %s", httpClient.toString(), e.getMessage()),
e); e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new LongPollingFailedException(
String.format("Interrupted subscribe (Http client: %s): %s", httpClient.toString(), e.getMessage()),
e);
} }
} }
/** /**
* Create a new subscription for long polling. * Create a new subscription for long polling.
* *
* @param httpClient Http client to send requests to * @param httpClient Http client to send requests to
*/ */
private void resubscribe(BoschHttpClient httpClient) { private void resubscribe(BoschHttpClient httpClient) {
@@ -171,7 +176,7 @@ public class LongPolling {
/** /**
* This is the handler for responses of long poll requests. * This is the handler for responses of long poll requests.
* *
* @param httpClient HTTP client which received the response * @param httpClient HTTP client which received the response
* @param subscriptionId Id of subscription the response is for * @param subscriptionId Id of subscription the response is for
* @param result Complete result of the response * @param result Complete result of the response