2 * Copyright (c) 2010-2024 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.webthing.internal.client;
15 import java.io.IOException;
17 import java.time.Duration;
18 import java.util.Locale;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.TimeUnit;
21 import java.util.concurrent.TimeoutException;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jetty.client.HttpClient;
25 import org.openhab.binding.webthing.internal.client.dto.WebThingDescription;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 import com.google.gson.Gson;
30 import com.google.gson.JsonSyntaxException;
33 * Utility class to load the WebThing description (meta data). Refer https://iot.mozilla.org/wot/#web-thing-description
35 * @author Gregor Roth - Initial contribution
38 public class DescriptionLoader {
39 private final Logger logger = LoggerFactory.getLogger(DescriptionLoader.class);
40 private final Gson gson = new Gson();
41 private final HttpClient httpClient;
46 * @param httpClient the http client to use
48 public DescriptionLoader(HttpClient httpClient) {
49 this.httpClient = httpClient;
53 * loads the WebThing meta data
55 * @param webthingURI the WebThing URI
56 * @param timeout the timeout
57 * @return the Webthing description
58 * @throws IOException if the WebThing can not be connected
60 public WebThingDescription loadWebthingDescription(URI webthingURI, Duration timeout) throws IOException {
62 var response = httpClient.newRequest(webthingURI).timeout(30, TimeUnit.SECONDS).accept("application/json")
64 if (response.getStatus() < 200 || response.getStatus() >= 300) {
65 throw new IOException(
66 "could not read resource description " + webthingURI + ". Got " + response.getStatus());
68 var body = response.getContentAsString();
69 var description = gson.fromJson(body, WebThingDescription.class);
70 if ((description != null) && (description.properties != null) && (description.properties.size() > 0)) {
71 if ((description.contextKeyword == null) || description.contextKeyword.trim().length() == 0) {
72 description.contextKeyword = "https://webthings.io/schemas";
74 var schema = description.contextKeyword.replaceFirst("/$", "").toLowerCase(Locale.US).trim();
76 // currently, the old and new location of the WebThings schema are supported only.
77 // In the future, other schemas such as http://iotschema.org/docs/full.html may be supported
78 if ("https://webthings.io/schemas".equals(schema) || "https://iot.mozilla.org/schemas".equals(schema)) {
82 "WebThing {} detected with unsupported schema {} (Supported schemas are https://webthings.io/schemas and https://iot.mozilla.org/schemas)",
83 webthingURI, description.contextKeyword);
84 throw new IOException("unsupported schema (@context parameter) " + description.contextKeyword
85 + " (Supported schemas are https://webthings.io/schemas and https://iot.mozilla.org/schemas)");
87 throw new IOException("description does not include properties");
89 } catch (ExecutionException | TimeoutException e) {
90 throw new IOException("error occurred by calling WebThing", e);
91 } catch (JsonSyntaxException se) {
92 throw new IOException("resource seems not to be a WebThing. Typo?");
93 } catch (InterruptedException ie) {
94 throw new IOException("resource seems not to be reachable");