]> git.basschouten.com Git - openhab-addons.git/blob
7e2fb4c7c4d5c9568b64374ef14389c04b2a40d4
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.webexteams.internal.api;
14
15 import static org.openhab.binding.webexteams.internal.WebexTeamsBindingConstants.*;
16
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;
23 import java.net.URI;
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;
29
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;
44
45 import com.google.gson.Gson;
46 import com.google.gson.JsonIOException;
47 import com.google.gson.JsonSyntaxException;
48
49 /**
50  * WebexTeamsApi implements API integration with Webex Teams.
51  * 
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..
54  * 
55  * @author Tom Deckers - Initial contribution
56  * 
57  */
58 @NonNullByDefault
59 public class WebexTeamsApi {
60
61     private final Logger logger = LoggerFactory.getLogger(WebexTeamsApi.class);
62
63     private final OAuthClientService authService;
64     private final HttpClient httpClient;
65
66     public WebexTeamsApi(OAuthClientService authService, HttpClient httpClient) {
67         this.authService = authService;
68         this.httpClient = httpClient;
69     }
70
71     /**
72      * Get a <code>Person</code> object for the account.
73      * 
74      * @return a <code>Person</code> object
75      * @throws WebexAuthenticationException when authentication fails
76      * @throws WebexTeamsApiException for other failures
77      */
78     public Person getPerson() throws WebexTeamsApiException, WebexAuthenticationException {
79         URI url = getUri(WEBEX_API_ENDPOINT + "/people/me");
80
81         Person person = request(url, HttpMethod.GET, Person.class, null);
82         return person;
83     }
84
85     private URI getUri(String url) throws WebexTeamsApiException {
86         URI uri;
87         try {
88             uri = new URI(url);
89         } catch (URISyntaxException e) {
90             throw new WebexTeamsApiException("bad url", e);
91         }
92         return uri;
93     }
94
95     private <I, O> O request(URI url, HttpMethod method, Class<O> clazz, I body)
96             throws WebexAuthenticationException, WebexTeamsApiException {
97         try {
98             // Refresh is handled automatically by this method
99             AccessTokenResponse response = this.authService.getAccessTokenResponse();
100
101             String authToken = response == null ? null : response.getAccessToken();
102             if (authToken == null) {
103                 throw new WebexAuthenticationException("Auth token is null");
104             } else {
105                 return doRequest(url, method, authToken, clazz, body);
106             }
107         } catch (OAuthException | IOException | OAuthResponseException e) {
108             throw new WebexAuthenticationException("Not authenticated", e);
109         }
110     }
111
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();
115         try {
116             Request req = httpClient.newRequest(url).method(method);
117             req.header("Authorization", "Bearer " + authToken);
118             logger.debug("Requesting {} with ({}, {})", url, clazz, body);
119
120             if (body != null) {
121                 String bodyString = gson.toJson(body, body.getClass());
122                 req.content(new StringContentProvider(bodyString));
123                 req.header("Content-type", "application/json");
124             }
125
126             ContentResponse response = req.send();
127
128             logger.debug("Response: {} - {}", response.getStatus(), response.getReason());
129
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);
137                     return entity;
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);
141                 }
142             } else {
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);
151                 }
152
153                 throw new WebexTeamsApiException(
154                         String.format("Unexpected response {} - {}", response.getStatus(), response.getReason()));
155             }
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);
166         }
167     }
168
169     // sendMessage
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());
174         return response;
175     }
176 }