]> git.basschouten.com Git - openhab-addons.git/blob
b3e195ddc225f43ab06fcd3f02986425cf4d15d7
[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         return request(url, HttpMethod.GET, Person.class, null);
82     }
83
84     private URI getUri(String url) throws WebexTeamsApiException {
85         URI uri;
86         try {
87             uri = new URI(url);
88         } catch (URISyntaxException e) {
89             throw new WebexTeamsApiException("bad url", e);
90         }
91         return uri;
92     }
93
94     private <I, O> O request(URI url, HttpMethod method, Class<O> clazz, I body)
95             throws WebexAuthenticationException, WebexTeamsApiException {
96         try {
97             // Refresh is handled automatically by this method
98             AccessTokenResponse response = this.authService.getAccessTokenResponse();
99
100             String authToken = response == null ? null : response.getAccessToken();
101             if (authToken == null) {
102                 throw new WebexAuthenticationException("Auth token is null");
103             } else {
104                 return doRequest(url, method, authToken, clazz, body);
105             }
106         } catch (OAuthException | IOException | OAuthResponseException e) {
107             throw new WebexAuthenticationException("Not authenticated", e);
108         }
109     }
110
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();
114         try {
115             Request req = httpClient.newRequest(url).method(method);
116             req.header("Authorization", "Bearer " + authToken);
117             logger.debug("Requesting {} with ({}, {})", url, clazz, body);
118
119             if (body != null) {
120                 String bodyString = gson.toJson(body, body.getClass());
121                 req.content(new StringContentProvider(bodyString));
122                 req.header("Content-type", "application/json");
123             }
124
125             ContentResponse response = req.send();
126
127             logger.debug("Response: {} - {}", response.getStatus(), response.getReason());
128
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);
139                 }
140             } else {
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);
149                 }
150
151                 throw new WebexTeamsApiException(
152                         String.format("Unexpected response {} - {}", response.getStatus(), response.getReason()));
153             }
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);
164         }
165     }
166
167     // sendMessage
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());
172         return response;
173     }
174 }