* accessing the session while it is being recreated.
*
* @param resource the resource to put.
+ * @return the resource, which may contain errors.
* @throws ApiException if something fails.
* @throws InterruptedException
*/
- public void putResource(Resource resource) throws ApiException, InterruptedException {
+ public Resources putResource(Resource resource) throws ApiException, InterruptedException {
Stream stream = null;
try (Throttler throttler = new Throttler(MAX_CONCURRENT_STREAMS);
SessionSynchronizer sessionSynchronizer = new SessionSynchronizer(false)) {
String contentType = contentStreamListener.getContentType();
int status = contentStreamListener.getStatus();
LOGGER.trace("HTTP/2 {} (Content-Type: {}) << {}", status, contentType, contentJson);
- if (status != HttpStatus.OK_200) {
+ if (!HttpStatus.isSuccess(status)) {
throw new ApiException(String.format("Unexpected HTTP status '%d'", status));
}
if (!MediaType.APPLICATION_JSON.equals(contentType)) {
throw new ApiException("Unexpected Content-Type: " + contentType);
}
+ if (contentJson.isEmpty()) {
+ throw new ApiException("Response payload is empty");
+ }
try {
- Resources resources = Objects.requireNonNull(jsonParser.fromJson(contentJson, Resources.class));
- if (LOGGER.isDebugEnabled()) {
- resources.getErrors().forEach(error -> LOGGER.debug("putResource() resources error:{}", error));
- }
+ return Objects.requireNonNull(jsonParser.fromJson(contentJson, Resources.class));
} catch (JsonParseException e) {
LOGGER.debug("putResource() parsing error json:{}", contentJson, e);
throw new ApiException("Parsing error", e);
private synchronized void checkConnection() {
logger.debug("checkConnection()");
- // check connection to the hub
- ThingStatusDetail thingStatus;
+ boolean retryApplicationKey = false;
+ boolean retryConnection = false;
+
try {
checkAssetsLoaded();
getClip2Bridge().testConnectionState();
- thingStatus = ThingStatusDetail.NONE;
- } catch (HttpUnauthorizedException e) {
- logger.debug("checkConnection() {}", e.getMessage(), e);
- thingStatus = ThingStatusDetail.CONFIGURATION_ERROR;
+ updateSelf(); // go online
+ } catch (HttpUnauthorizedException unauthorizedException) {
+ logger.debug("checkConnection() {}", unauthorizedException.getMessage(), unauthorizedException);
+ if (applKeyRetriesRemaining > 0) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "@text/offline.api2.conf-error.press-pairing-button");
+ try {
+ registerApplicationKey();
+ retryApplicationKey = true;
+ } catch (HttpUnauthorizedException e) {
+ retryApplicationKey = true;
+ } catch (ApiException e) {
+ setStatusOfflineWithCommunicationError(e);
+ } catch (IllegalStateException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "@text/offline.api2.conf-error.read-only");
+ } catch (AssetNotLoadedException e) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "@text/offline.api2.conf-error.assets-not-loaded");
+ } catch (InterruptedException e) {
+ return;
+ }
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
+ "@text/offline.api2.conf-error.not-authorized");
+ }
} catch (ApiException e) {
logger.debug("checkConnection() {}", e.getMessage(), e);
- thingStatus = ThingStatusDetail.COMMUNICATION_ERROR;
+ setStatusOfflineWithCommunicationError(e);
+ retryConnection = connectRetriesRemaining > 0;
} catch (AssetNotLoadedException e) {
logger.debug("checkConnection() {}", e.getMessage(), e);
- thingStatus = ThingStatusDetail.HANDLER_INITIALIZING_ERROR;
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "@text/offline.api2.conf-error.assets-not-loaded");
} catch (InterruptedException e) {
return;
}
- // update the thing status
- boolean retryApplicationKey = false;
- boolean retryConnection = false;
- switch (thingStatus) {
- case CONFIGURATION_ERROR:
- if (applKeyRetriesRemaining > 0) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
- "@text/offline.api2.conf-error.press-pairing-button");
- try {
- registerApplicationKey();
- retryApplicationKey = true;
- } catch (HttpUnauthorizedException e) {
- retryApplicationKey = true;
- } catch (ApiException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.communication-error");
- } catch (IllegalStateException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
- "@text/offline.api2.conf-error.read-only");
- } catch (AssetNotLoadedException e) {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.api2.conf-error.assets-not-loaded");
- } catch (InterruptedException e) {
- return;
- }
- } else {
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
- "@text/offline.api2.conf-error.not-authorized");
- }
- break;
-
- case COMMUNICATION_ERROR:
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.communication-error");
- retryConnection = connectRetriesRemaining > 0;
- break;
-
- case HANDLER_INITIALIZING_ERROR:
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.api2.conf-error.assets-not-loaded");
- break;
-
- case NONE:
- default:
- updateSelf(); // go online
- break;
- }
-
int milliSeconds;
if (retryApplicationKey) {
// short delay used during attempts to create or validate an application key
checkConnectionTask = scheduler.schedule(() -> checkConnection(), milliSeconds, TimeUnit.MILLISECONDS);
}
+ private void setStatusOfflineWithCommunicationError(Exception e) {
+ Throwable cause = e.getCause();
+ String causeMessage = cause == null ? null : cause.getMessage();
+ if (causeMessage == null || causeMessage.isEmpty()) {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "@text/offline.api2.comm-error.exception [\"" + e.getMessage() + "\"]");
+ } else {
+ updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
+ "@text/offline.api2.comm-error.exception [\"" + e.getMessage() + " -> " + causeMessage + "\"]");
+ }
+ }
+
/**
* If a child thing has been added, and the bridge is online, update the child's data.
*/
}
} catch (IOException e) {
logger.trace("initializeAssets() communication error on '{}'", ipAddress, e);
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.api2.comm-error.exception [\"" + e.getMessage() + "\"]");
+ setStatusOfflineWithCommunicationError(e);
return;
}
clip2Bridge = new Clip2Bridge(httpClientFactory, this, ipAddress, applicationKey);
} catch (ApiException e) {
logger.trace("initializeAssets() communication error on '{}'", ipAddress, e);
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.api2.comm-error.exception [\"" + e.getMessage() + "\"]");
+ setStatusOfflineWithCommunicationError(e);
return;
}
* Execute an HTTP PUT to send a Resource object to the server.
*
* @param resource the resource to put.
+ * @return the resource, which may contain errors.
* @throws ApiException if a communication error occurred.
* @throws AssetNotLoadedException if one of the assets is not loaded.
* @throws InterruptedException
*/
- public void putResource(Resource resource) throws ApiException, AssetNotLoadedException, InterruptedException {
+ public Resources putResource(Resource resource) throws ApiException, AssetNotLoadedException, InterruptedException {
logger.debug("putResource() {}", resource);
checkAssetsLoaded();
- getClip2Bridge().putResource(resource);
+ return getClip2Bridge().putResource(resource);
}
/**
getClip2Bridge().open();
} catch (ApiException e) {
logger.trace("updateSelf() {}", e.getMessage(), e);
- updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
- "@text/offline.api2.comm-error.exception [\"" + e.getMessage() + "\"]");
+ setStatusOfflineWithCommunicationError(e);
onConnectionOffline();
} catch (AssetNotLoadedException e) {
logger.trace("updateSelf() {}", e.getMessage(), e);