[hue] Handle unexpected empty response from API (#14297)

Fix #14218

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2023-02-01 20:55:54 +01:00 committed by Jacob Laursen
parent b3b7be63b1
commit 551cd8f41d
3 changed files with 105 additions and 0 deletions

View File

@ -72,6 +72,7 @@ import org.openhab.binding.hue.internal.dto.SuccessResponse;
import org.openhab.binding.hue.internal.dto.Util;
import org.openhab.binding.hue.internal.exceptions.ApiException;
import org.openhab.binding.hue.internal.exceptions.DeviceOffException;
import org.openhab.binding.hue.internal.exceptions.EmptyResponseException;
import org.openhab.binding.hue.internal.exceptions.EntityNotAvailableException;
import org.openhab.binding.hue.internal.exceptions.GroupTableFullException;
import org.openhab.binding.hue.internal.exceptions.InvalidCommandException;
@ -252,6 +253,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("GET request 'lights' returned an unexpected empty reponse");
}
Map<String, T> lightMap = safeFromJson(result.body, gsonType);
List<T> lights = new ArrayList<>();
lightMap.forEach((id, light) -> {
@ -275,6 +280,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("GET request 'sensors' returned an unexpected empty reponse");
}
Map<String, FullSensor> sensorMap = safeFromJson(result.body, FullSensor.GSON_TYPE);
List<FullSensor> sensors = new ArrayList<>();
sensorMap.forEach((id, sensor) -> {
@ -300,6 +309,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("GET request 'lights/new' returned an unexpected empty reponse");
}
String lastScan = safeFromJson(result.body, NewLightsResponse.class).lastscan;
switch (lastScan) {
@ -362,6 +375,11 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException(
"GET request 'lights/" + enc(light.getId()) + "' returned an unexpected empty reponse");
}
FullHueObject fullLight = safeFromJson(result.body, FullLight.class);
fullLight.setId(light.getId());
return fullLight;
@ -386,6 +404,11 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException(
"PUT request 'lights/" + enc(light.getId()) + "' returned an unexpected empty reponse");
}
List<SuccessResponse> entries = safeFromJson(result.body, SuccessResponse.GSON_TYPE);
SuccessResponse response = entries.get(0);
@ -469,6 +492,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("GET request 'groups' returned an unexpected empty reponse");
}
Map<String, FullGroup> groupMap = safeFromJson(result.body, FullGroup.GSON_TYPE);
List<FullGroup> groups = new ArrayList<>();
if (groupMap.get("0") == null) {
@ -510,6 +537,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("POST request 'groups' returned an unexpected empty reponse");
}
List<SuccessResponse> entries = safeFromJson(result.body, SuccessResponse.GSON_TYPE);
SuccessResponse response = entries.get(0);
@ -540,6 +571,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("POST request 'groups' returned an unexpected empty reponse");
}
List<SuccessResponse> entries = safeFromJson(result.body, SuccessResponse.GSON_TYPE);
SuccessResponse response = entries.get(0);
@ -565,6 +600,11 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException(
"GET request 'groups/" + enc(group.getId()) + "' returned an unexpected empty reponse");
}
FullGroup fullGroup = safeFromJson(result.body, FullGroup.class);
fullGroup.setId(group.getId());
return fullGroup;
@ -593,6 +633,11 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException(
"PUT request 'groups/" + enc(group.getId()) + "' returned an unexpected empty reponse");
}
List<SuccessResponse> entries = safeFromJson(result.body, SuccessResponse.GSON_TYPE);
SuccessResponse response = entries.get(0);
@ -648,6 +693,11 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException(
"PUT request 'groups/" + enc(group.getId()) + "' returned an unexpected empty reponse");
}
List<SuccessResponse> entries = safeFromJson(result.body, SuccessResponse.GSON_TYPE);
SuccessResponse response = entries.get(0);
@ -707,6 +757,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("GET request 'schedules' returned an unexpected empty reponse");
}
Map<String, Schedule> scheduleMap = safeFromJson(result.body, Schedule.GSON_TYPE);
List<Schedule> schedules = new ArrayList<>();
scheduleMap.forEach((id, schedule) -> {
@ -761,6 +815,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("GET request 'scenes' returned an unexpected empty reponse");
}
Map<String, Scene> sceneMap = safeFromJson(result.body, Scene.GSON_TYPE);
return sceneMap.entrySet().stream()//
.map(e -> {
@ -841,6 +899,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("POST request (link) returned an unexpected empty reponse");
}
List<SuccessResponse> entries = safeFromJson(result.body, SuccessResponse.GSON_TYPE);
SuccessResponse response = entries.get(0);
@ -865,6 +927,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("GET request 'config' returned an unexpected empty reponse");
}
return safeFromJson(result.body, Config.class);
}
@ -912,6 +978,10 @@ public class HueBridge {
handleErrors(result);
if (result.body.isBlank()) {
throw new EmptyResponseException("GET request (getFullConfig) returned an unexpected empty reponse");
}
FullConfig fullConfig = gson.fromJson(result.body, FullConfig.class);
return Objects.requireNonNull(fullConfig);
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.hue.internal.exceptions;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* Thrown when API is returning an unexpected empty response.
*
* @author Laurent Garnier - Initial contribution
*/
@SuppressWarnings("serial")
@NonNullByDefault
public class EmptyResponseException extends ApiException {
public EmptyResponseException() {
}
public EmptyResponseException(String message) {
super(message);
}
}

View File

@ -49,6 +49,7 @@ import org.openhab.binding.hue.internal.dto.State;
import org.openhab.binding.hue.internal.dto.StateUpdate;
import org.openhab.binding.hue.internal.exceptions.ApiException;
import org.openhab.binding.hue.internal.exceptions.DeviceOffException;
import org.openhab.binding.hue.internal.exceptions.EmptyResponseException;
import org.openhab.binding.hue.internal.exceptions.EntityNotAvailableException;
import org.openhab.binding.hue.internal.exceptions.LinkButtonException;
import org.openhab.binding.hue.internal.exceptions.UnauthorizedException;
@ -150,6 +151,9 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
lastBridgeConnectionState = false;
onConnectionLost();
}
} catch (EmptyResponseException e) {
// Unexpected empty response is ignored
logger.debug("{}", e.getMessage());
} catch (ApiException | CommunicationException | IOException e) {
if (hueBridge != null && lastBridgeConnectionState) {
logger.debug("Connection to Hue Bridge {} lost: {}", hueBridge.getIPAddress(), e.getMessage(), e);