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.webexteams.internal.api;
15 import static org.openhab.binding.webexteams.internal.WebexTeamsBindingConstants.*;
17 import java.io.BufferedReader;
18 import java.io.ByteArrayInputStream;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.io.InputStreamReader;
22 import java.io.Reader;
24 import java.net.URISyntaxException;
25 import java.nio.charset.StandardCharsets;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.TimeoutException;
28 import java.util.stream.Collectors;
30 import org.eclipse.jdt.annotation.NonNullByDefault;
31 import org.eclipse.jetty.client.HttpClient;
32 import org.eclipse.jetty.client.api.ContentResponse;
33 import org.eclipse.jetty.client.api.Request;
34 import org.eclipse.jetty.client.util.StringContentProvider;
35 import org.eclipse.jetty.http.HttpMethod;
36 import org.eclipse.jetty.http.HttpStatus;
37 import org.openhab.binding.webexteams.internal.WebexAuthenticationException;
38 import org.openhab.core.auth.client.oauth2.AccessTokenResponse;
39 import org.openhab.core.auth.client.oauth2.OAuthClientService;
40 import org.openhab.core.auth.client.oauth2.OAuthException;
41 import org.openhab.core.auth.client.oauth2.OAuthResponseException;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
45 import com.google.gson.Gson;
46 import com.google.gson.JsonIOException;
47 import com.google.gson.JsonSyntaxException;
50 * WebexTeamsApi implements API integration with Webex Teams.
52 * Not using webex-java-sdk since it's not in a public maven repo, and it doesn't easily
53 * support caching refresh tokens between openhab restarts, etc..
55 * @author Tom Deckers - Initial contribution
59 public class WebexTeamsApi {
61 private final Logger logger = LoggerFactory.getLogger(WebexTeamsApi.class);
63 private final OAuthClientService authService;
64 private final HttpClient httpClient;
66 public WebexTeamsApi(OAuthClientService authService, HttpClient httpClient) {
67 this.authService = authService;
68 this.httpClient = httpClient;
72 * Get a <code>Person</code> object for the account.
74 * @return a <code>Person</code> object
75 * @throws WebexAuthenticationException when authentication fails
76 * @throws WebexTeamsApiException for other failures
78 public Person getPerson() throws WebexTeamsApiException, WebexAuthenticationException {
79 URI url = getUri(WEBEX_API_ENDPOINT + "/people/me");
81 Person person = request(url, HttpMethod.GET, Person.class, null);
85 private URI getUri(String url) throws WebexTeamsApiException {
89 } catch (URISyntaxException e) {
90 throw new WebexTeamsApiException("bad url", e);
95 private <I, O> O request(URI url, HttpMethod method, Class<O> clazz, I body)
96 throws WebexAuthenticationException, WebexTeamsApiException {
98 // Refresh is handled automatically by this method
99 AccessTokenResponse response = this.authService.getAccessTokenResponse();
101 String authToken = response == null ? null : response.getAccessToken();
102 if (authToken == null) {
103 throw new WebexAuthenticationException("Auth token is null");
105 return doRequest(url, method, authToken, clazz, body);
107 } catch (OAuthException | IOException | OAuthResponseException e) {
108 throw new WebexAuthenticationException("Not authenticated", e);
112 private <I, O> O doRequest(URI url, HttpMethod method, String authToken, Class<O> clazz, I body)
113 throws WebexAuthenticationException, WebexTeamsApiException {
114 Gson gson = new Gson();
116 Request req = httpClient.newRequest(url).method(method);
117 req.header("Authorization", "Bearer " + authToken);
118 logger.debug("Requesting {} with ({}, {})", url, clazz, body);
121 String bodyString = gson.toJson(body, body.getClass());
122 req.content(new StringContentProvider(bodyString));
123 req.header("Content-type", "application/json");
126 ContentResponse response = req.send();
128 logger.debug("Response: {} - {}", response.getStatus(), response.getReason());
130 if (response.getStatus() == HttpStatus.UNAUTHORIZED_401) {
131 throw new WebexAuthenticationException();
132 } else if (response.getStatus() == HttpStatus.OK_200) {
133 // Obtain the input stream on the response content
134 try (InputStream input = new ByteArrayInputStream(response.getContent())) {
135 Reader reader = new InputStreamReader(input);
136 O entity = gson.fromJson(reader, clazz);
138 } catch (IOException | JsonIOException | JsonSyntaxException e) {
139 logger.warn("Exception while processing API response: {}", e.getMessage());
140 throw new WebexTeamsApiException("Exception while processing API response", e);
143 logger.warn("Unexpected response {} - {}", response.getStatus(), response.getReason());
144 try (InputStream input = new ByteArrayInputStream(response.getContent())) {
145 String text = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).lines()
146 .collect(Collectors.joining("\n"));
147 logger.warn("Content: {}", text);
148 } catch (IOException e) {
149 throw new WebexTeamsApiException(
150 String.format("Unexpected response code: {}", response.getStatus()), e);
153 throw new WebexTeamsApiException(
154 String.format("Unexpected response {} - {}", response.getStatus(), response.getReason()));
156 } catch (TimeoutException e) {
157 logger.warn("Request timeout", e);
158 throw new WebexTeamsApiException("Request timeout", e);
159 } catch (ExecutionException e) {
160 logger.warn("Request error", e);
161 throw new WebexTeamsApiException("Request error", e);
162 } catch (InterruptedException e) {
163 Thread.currentThread().interrupt();
164 logger.warn("Request interrupted", e);
165 throw new WebexTeamsApiException("Request interrupted", e);
170 public Message sendMessage(Message msg) throws WebexTeamsApiException, WebexAuthenticationException {
171 URI url = getUri(WEBEX_API_ENDPOINT + "/messages");
172 Message response = request(url, HttpMethod.POST, Message.class, msg);
173 logger.debug("Sent message, id: {}", response.getId());