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 return request(url, HttpMethod.GET, Person.class, null);
84 private URI getUri(String url) throws WebexTeamsApiException {
88 } catch (URISyntaxException e) {
89 throw new WebexTeamsApiException("bad url", e);
94 private <I, O> O request(URI url, HttpMethod method, Class<O> clazz, I body)
95 throws WebexAuthenticationException, WebexTeamsApiException {
97 // Refresh is handled automatically by this method
98 AccessTokenResponse response = this.authService.getAccessTokenResponse();
100 String authToken = response == null ? null : response.getAccessToken();
101 if (authToken == null) {
102 throw new WebexAuthenticationException("Auth token is null");
104 return doRequest(url, method, authToken, clazz, body);
106 } catch (OAuthException | IOException | OAuthResponseException e) {
107 throw new WebexAuthenticationException("Not authenticated", e);
111 private <I, O> O doRequest(URI url, HttpMethod method, String authToken, Class<O> clazz, I body)
112 throws WebexAuthenticationException, WebexTeamsApiException {
113 Gson gson = new Gson();
115 Request req = httpClient.newRequest(url).method(method);
116 req.header("Authorization", "Bearer " + authToken);
117 logger.debug("Requesting {} with ({}, {})", url, clazz, body);
120 String bodyString = gson.toJson(body, body.getClass());
121 req.content(new StringContentProvider(bodyString));
122 req.header("Content-type", "application/json");
125 ContentResponse response = req.send();
127 logger.debug("Response: {} - {}", response.getStatus(), response.getReason());
129 if (response.getStatus() == HttpStatus.UNAUTHORIZED_401) {
130 throw new WebexAuthenticationException();
131 } else if (response.getStatus() == HttpStatus.OK_200) {
132 // Obtain the input stream on the response content
133 try (InputStream input = new ByteArrayInputStream(response.getContent())) {
134 Reader reader = new InputStreamReader(input);
135 return gson.fromJson(reader, clazz);
136 } catch (IOException | JsonIOException | JsonSyntaxException e) {
137 logger.warn("Exception while processing API response: {}", e.getMessage());
138 throw new WebexTeamsApiException("Exception while processing API response", e);
141 logger.warn("Unexpected response {} - {}", response.getStatus(), response.getReason());
142 try (InputStream input = new ByteArrayInputStream(response.getContent())) {
143 String text = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8)).lines()
144 .collect(Collectors.joining("\n"));
145 logger.warn("Content: {}", text);
146 } catch (IOException e) {
147 throw new WebexTeamsApiException(
148 String.format("Unexpected response code: {}", response.getStatus()), e);
151 throw new WebexTeamsApiException(
152 String.format("Unexpected response {} - {}", response.getStatus(), response.getReason()));
154 } catch (TimeoutException e) {
155 logger.warn("Request timeout", e);
156 throw new WebexTeamsApiException("Request timeout", e);
157 } catch (ExecutionException e) {
158 logger.warn("Request error", e);
159 throw new WebexTeamsApiException("Request error", e);
160 } catch (InterruptedException e) {
161 Thread.currentThread().interrupt();
162 logger.warn("Request interrupted", e);
163 throw new WebexTeamsApiException("Request interrupted", e);
168 public Message sendMessage(Message msg) throws WebexTeamsApiException, WebexAuthenticationException {
169 URI url = getUri(WEBEX_API_ENDPOINT + "/messages");
170 Message response = request(url, HttpMethod.POST, Message.class, msg);
171 logger.debug("Sent message, id: {}", response.getId());