[boschindego] Fix communication error when smart mowing is disabled (#13167)

* Fix communication error when no planned next cutting
* Provide targeted handling of missing cutting times

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
Jacob Laursen 2022-07-25 08:45:46 +02:00 committed by GitHub
parent f7a228e9e9
commit 60c13d7521
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 19 deletions

View File

@ -100,6 +100,7 @@ public class IndegoController {
* @throws IndegoException if any communication or parsing error occurred * @throws IndegoException if any communication or parsing error occurred
*/ */
private void authenticate() throws IndegoAuthenticationException, IndegoException { private void authenticate() throws IndegoAuthenticationException, IndegoException {
int status = 0;
try { try {
Request request = httpClient.newRequest(BASE_URL + "authenticate").method(HttpMethod.POST) Request request = httpClient.newRequest(BASE_URL + "authenticate").method(HttpMethod.POST)
.header(HttpHeader.AUTHORIZATION, basicAuthenticationHeader); .header(HttpHeader.AUTHORIZATION, basicAuthenticationHeader);
@ -119,7 +120,7 @@ public class IndegoController {
} }
ContentResponse response = sendRequest(request); ContentResponse response = sendRequest(request);
int status = response.getStatus(); status = response.getStatus();
if (status == HttpStatus.UNAUTHORIZED_401) { if (status == HttpStatus.UNAUTHORIZED_401) {
throw new IndegoAuthenticationException("Authentication was rejected"); throw new IndegoAuthenticationException("Authentication was rejected");
} }
@ -129,19 +130,20 @@ public class IndegoController {
String jsonResponse = response.getContentAsString(); String jsonResponse = response.getContentAsString();
if (jsonResponse.isEmpty()) { if (jsonResponse.isEmpty()) {
throw new IndegoInvalidResponseException("No content returned"); throw new IndegoInvalidResponseException("No content returned", status);
} }
logger.trace("JSON response: '{}'", jsonResponse); logger.trace("JSON response: '{}'", jsonResponse);
AuthenticationResponse authenticationResponse = gson.fromJson(jsonResponse, AuthenticationResponse.class); AuthenticationResponse authenticationResponse = gson.fromJson(jsonResponse, AuthenticationResponse.class);
if (authenticationResponse == null) { if (authenticationResponse == null) {
throw new IndegoInvalidResponseException("Response could not be parsed as AuthenticationResponse"); throw new IndegoInvalidResponseException("Response could not be parsed as AuthenticationResponse",
status);
} }
session = new IndegoSession(authenticationResponse.contextId, authenticationResponse.serialNumber, session = new IndegoSession(authenticationResponse.contextId, authenticationResponse.serialNumber,
getContextExpirationTimeFromCookie()); getContextExpirationTimeFromCookie());
logger.debug("Initialized session {}", session); logger.debug("Initialized session {}", session);
} catch (JsonParseException e) { } catch (JsonParseException e) {
throw new IndegoInvalidResponseException("Error parsing AuthenticationResponse", e); throw new IndegoInvalidResponseException("Error parsing AuthenticationResponse", e, status);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new IndegoException(e); throw new IndegoException(e);
@ -224,6 +226,7 @@ public class IndegoController {
*/ */
private <T> T getRequest(String path, Class<? extends T> dtoClass) private <T> T getRequest(String path, Class<? extends T> dtoClass)
throws IndegoAuthenticationException, IndegoUnreachableException, IndegoException { throws IndegoAuthenticationException, IndegoUnreachableException, IndegoException {
int status = 0;
try { try {
Request request = httpClient.newRequest(BASE_URL + path).method(HttpMethod.GET).header(CONTEXT_HEADER_NAME, Request request = httpClient.newRequest(BASE_URL + path).method(HttpMethod.GET).header(CONTEXT_HEADER_NAME,
session.getContextId()); session.getContextId());
@ -231,7 +234,7 @@ public class IndegoController {
logger.trace("GET request for {}", BASE_URL + path); logger.trace("GET request for {}", BASE_URL + path);
} }
ContentResponse response = sendRequest(request); ContentResponse response = sendRequest(request);
int status = response.getStatus(); status = response.getStatus();
if (status == HttpStatus.UNAUTHORIZED_401) { if (status == HttpStatus.UNAUTHORIZED_401) {
// This will currently not happen because "WWW-Authenticate" header is missing; see below. // This will currently not happen because "WWW-Authenticate" header is missing; see below.
throw new IndegoAuthenticationException("Context rejected"); throw new IndegoAuthenticationException("Context rejected");
@ -244,18 +247,18 @@ public class IndegoController {
} }
String jsonResponse = response.getContentAsString(); String jsonResponse = response.getContentAsString();
if (jsonResponse.isEmpty()) { if (jsonResponse.isEmpty()) {
throw new IndegoInvalidResponseException("No content returned"); throw new IndegoInvalidResponseException("No content returned", status);
} }
logger.trace("JSON response: '{}'", jsonResponse); logger.trace("JSON response: '{}'", jsonResponse);
@Nullable @Nullable
T result = gson.fromJson(jsonResponse, dtoClass); T result = gson.fromJson(jsonResponse, dtoClass);
if (result == null) { if (result == null) {
throw new IndegoInvalidResponseException("Parsed response is null"); throw new IndegoInvalidResponseException("Parsed response is null", status);
} }
return result; return result;
} catch (JsonParseException e) { } catch (JsonParseException e) {
throw new IndegoInvalidResponseException("Error parsing response", e); throw new IndegoInvalidResponseException("Error parsing response", e, status);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new IndegoException(e); throw new IndegoException(e);
@ -315,6 +318,7 @@ public class IndegoController {
* @throws IndegoException if any communication or parsing error occurred * @throws IndegoException if any communication or parsing error occurred
*/ */
private RawType getRawRequest(String path) throws IndegoAuthenticationException, IndegoException { private RawType getRawRequest(String path) throws IndegoAuthenticationException, IndegoException {
int status = 0;
try { try {
Request request = httpClient.newRequest(BASE_URL + path).method(HttpMethod.GET).header(CONTEXT_HEADER_NAME, Request request = httpClient.newRequest(BASE_URL + path).method(HttpMethod.GET).header(CONTEXT_HEADER_NAME,
session.getContextId()); session.getContextId());
@ -322,7 +326,7 @@ public class IndegoController {
logger.trace("GET request for {}", BASE_URL + path); logger.trace("GET request for {}", BASE_URL + path);
} }
ContentResponse response = sendRequest(request); ContentResponse response = sendRequest(request);
int status = response.getStatus(); status = response.getStatus();
if (status == HttpStatus.UNAUTHORIZED_401) { if (status == HttpStatus.UNAUTHORIZED_401) {
// This will currently not happen because "WWW-Authenticate" header is missing; see below. // This will currently not happen because "WWW-Authenticate" header is missing; see below.
throw new IndegoAuthenticationException("Context rejected"); throw new IndegoAuthenticationException("Context rejected");
@ -332,17 +336,17 @@ public class IndegoController {
} }
byte[] data = response.getContent(); byte[] data = response.getContent();
if (data == null) { if (data == null) {
throw new IndegoInvalidResponseException("No data returned"); throw new IndegoInvalidResponseException("No data returned", status);
} }
String contentType = response.getMediaType(); String contentType = response.getMediaType();
if (contentType == null || contentType.isEmpty()) { if (contentType == null || contentType.isEmpty()) {
throw new IndegoInvalidResponseException("No content-type returned"); throw new IndegoInvalidResponseException("No content-type returned", status);
} }
logger.debug("Media download response: type {}, length {}", contentType, data.length); logger.debug("Media download response: type {}, length {}", contentType, data.length);
return new RawType(data, contentType); return new RawType(data, contentType);
} catch (JsonParseException e) { } catch (JsonParseException e) {
throw new IndegoInvalidResponseException("Error parsing response", e); throw new IndegoInvalidResponseException("Error parsing response", e, status);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new IndegoException(e); throw new IndegoException(e);
@ -425,7 +429,7 @@ public class IndegoController {
throw new IndegoException("The request failed with error: " + status); throw new IndegoException("The request failed with error: " + status);
} }
} catch (JsonParseException e) { } catch (JsonParseException e) {
throw new IndegoInvalidResponseException("Error serializing request", e); throw new IndegoException("Error serializing request", e);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new IndegoException(e); throw new IndegoException(e);
@ -643,8 +647,16 @@ public class IndegoController {
* @throws IndegoException if any communication or parsing error occurred * @throws IndegoException if any communication or parsing error occurred
*/ */
public @Nullable Instant getPredictiveLastCutting() throws IndegoAuthenticationException, IndegoException { public @Nullable Instant getPredictiveLastCutting() throws IndegoAuthenticationException, IndegoException {
return getRequestWithAuthentication(SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive/lastcutting", try {
PredictiveLastCuttingResponse.class).getLastCutting(); return getRequestWithAuthentication(
SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive/lastcutting",
PredictiveLastCuttingResponse.class).getLastCutting();
} catch (IndegoInvalidResponseException e) {
if (e.getHttpStatusCode() == HttpStatus.NO_CONTENT_204) {
return null;
}
throw e;
}
} }
/** /**
@ -655,8 +667,16 @@ public class IndegoController {
* @throws IndegoException if any communication or parsing error occurred * @throws IndegoException if any communication or parsing error occurred
*/ */
public @Nullable Instant getPredictiveNextCutting() throws IndegoAuthenticationException, IndegoException { public @Nullable Instant getPredictiveNextCutting() throws IndegoAuthenticationException, IndegoException {
return getRequestWithAuthentication(SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive/nextcutting", try {
PredictiveNextCuttingResponse.class).getNextCutting(); return getRequestWithAuthentication(
SERIAL_NUMBER_SUBPATH + this.getSerialNumber() + "/predictive/nextcutting",
PredictiveNextCuttingResponse.class).getNextCutting();
} catch (IndegoInvalidResponseException e) {
if (e.getHttpStatusCode() == HttpStatus.NO_CONTENT_204) {
return null;
}
throw e;
}
} }
/** /**

View File

@ -24,12 +24,19 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
public class IndegoInvalidResponseException extends IndegoException { public class IndegoInvalidResponseException extends IndegoException {
private static final long serialVersionUID = -4236849226899489934L; private static final long serialVersionUID = -4236849226899489934L;
private int httpStatusCode = 0;
public IndegoInvalidResponseException(String message) { public IndegoInvalidResponseException(String message, int httpStatusCode) {
super(message); super(message);
this.httpStatusCode = httpStatusCode;
} }
public IndegoInvalidResponseException(String message, Throwable cause) { public IndegoInvalidResponseException(String message, Throwable cause, int httpStatusCode) {
super(message, cause); super(message, cause);
this.httpStatusCode = httpStatusCode;
}
public int getHttpStatusCode() {
return httpStatusCode;
} }
} }