2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.shelly.internal.api;
15 import static org.openhab.binding.shelly.internal.util.ShellyUtils.getString;
17 import java.net.ConnectException;
18 import java.net.MalformedURLException;
19 import java.net.NoRouteToHostException;
20 import java.net.PortUnreachableException;
21 import java.net.SocketException;
22 import java.net.SocketTimeoutException;
23 import java.net.UnknownHostException;
24 import java.text.MessageFormat;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.TimeoutException;
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.eclipse.jdt.annotation.Nullable;
31 import com.google.gson.JsonSyntaxException;
34 * The {@link CarNetException} implements an extension to the standard Exception class. This allows to keep also the
35 * result of the last API call (e.g. including the http status code in the message).
37 * @author Markus Michels - Initial contribution
40 public class ShellyApiException extends Exception {
41 private static final long serialVersionUID = -5809459454769761821L;
43 private ShellyApiResult apiResult = new ShellyApiResult();
44 private static final String NONE = "none";
46 public ShellyApiException(Exception exception) {
50 public ShellyApiException(String message) {
54 public ShellyApiException(ShellyApiResult res) {
59 public ShellyApiException(String message, Exception exception) {
60 super(message, exception);
63 public ShellyApiException(ShellyApiResult result, Exception exception) {
69 public @Nullable String getMessage() {
70 return isEmpty() ? "" : nonNullString(super.getMessage());
74 public String toString() {
75 String message = nonNullString(super.getMessage()).replace("java.util.concurrent.ExecutionException: ", "")
76 .replace("java.net.", "");
77 String cause = getCauseClass().toString();
78 String url = apiResult.getUrl();
80 if (isUnknownHost()) {
81 String[] string = message.split(": "); // java.net.UnknownHostException: api.rach.io
82 message = MessageFormat.format("Unable to connect to {0} (Unknown host / Network down / Low signal)",
84 } else if (isMalformedURL()) {
85 message = "Invalid URL: " + url;
86 } else if (isTimeout()) {
87 message = "API Timeout for " + url;
88 } else if (!isConnectionError()) {
89 message = message + "(" + cause + ")";
92 message = apiResult.toString();
97 public boolean isJsonError() {
98 return getString(getMessage()).startsWith("Unable to create object of type");
101 public boolean isApiException() {
102 return getCauseClass() == ShellyApiException.class;
105 public boolean isTimeout() {
106 Class<?> extype = !isEmpty() ? getCauseClass() : null;
107 return (extype != null) && ((extype == TimeoutException.class) || extype == InterruptedException.class
108 || extype == SocketTimeoutException.class
109 || nonNullString(getMessage()).toLowerCase().contains("timeout"));
112 public boolean isConnectionError() {
113 Class<?> exType = getCauseClass();
114 return isUnknownHost() || isMalformedURL() || exType == ConnectException.class
115 || exType == SocketException.class || exType == PortUnreachableException.class
116 || exType == NoRouteToHostException.class;
119 public boolean isUnknownHost() {
120 return getCauseClass() == UnknownHostException.class;
123 public boolean isMalformedURL() {
124 return getCauseClass() == MalformedURLException.class;
127 public boolean isHttpAccessUnauthorized() {
128 return apiResult.isHttpAccessUnauthorized();
131 public boolean isJSONException() {
132 return getCauseClass() == JsonSyntaxException.class;
135 public ShellyApiResult getApiResult() {
139 private boolean isEmpty() {
140 return NONE.equals(nonNullString(super.getMessage()));
143 private static String nonNullString(@Nullable String s) {
144 return s != null ? s : "";
147 private Class<?> getCauseClass() {
148 Throwable cause = getCause();
149 if (cause != null && cause.getClass() == ExecutionException.class) {
150 cause = cause.getCause();
153 return cause.getClass();
155 return ShellyApiException.class;