7868d8c8c16d7d19ba2dc9460e507d2260ba7f2c
[ui/dmaapbc.git] /
1 /*-
2  * ================================================================================
3  * DCAE DMaaP Bus Controller REST Client
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ================================================================================
19  */
20 package org.openecomp.dcae.dmaapbc.client;
21
22 import java.io.IOException;
23 import java.net.URI;
24
25 import org.apache.http.Consts;
26 import org.apache.http.HttpEntity;
27 import org.apache.http.HttpHost;
28 import org.apache.http.auth.AuthScope;
29 import org.apache.http.auth.UsernamePasswordCredentials;
30 import org.apache.http.client.AuthCache;
31 import org.apache.http.client.ClientProtocolException;
32 import org.apache.http.client.CredentialsProvider;
33 import org.apache.http.client.config.RequestConfig;
34 import org.apache.http.client.config.RequestConfig.Builder;
35 import org.apache.http.client.methods.CloseableHttpResponse;
36 import org.apache.http.client.methods.HttpDelete;
37 import org.apache.http.client.methods.HttpGet;
38 import org.apache.http.client.methods.HttpPost;
39 import org.apache.http.client.methods.HttpPut;
40 import org.apache.http.client.methods.HttpRequestBase;
41 import org.apache.http.client.protocol.HttpClientContext;
42 import org.apache.http.client.utils.URIBuilder;
43 import org.apache.http.entity.ContentType;
44 import org.apache.http.entity.StringEntity;
45 import org.apache.http.impl.auth.BasicScheme;
46 import org.apache.http.impl.client.BasicAuthCache;
47 import org.apache.http.impl.client.BasicCredentialsProvider;
48 import org.apache.http.impl.client.CloseableHttpClient;
49 import org.apache.http.impl.client.HttpClients;
50 import org.apache.http.util.EntityUtils;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 /**
55  * Provides a basic client to access a REST endpoint, optionally using HTTP
56  * basic authentication.
57  * 
58  * Caveat: If HTTPS access is used and the server uses a self-signed
59  * certificate, the local trust store must be extended appropriately. The client
60  * throws exceptions if the JVM cannot validate the server certificate.
61  */
62 public class SimpleRestClientBase {
63
64         private static Logger logger = LoggerFactory.getLogger(SimpleRestClientBase.class);
65
66         /**
67          * Credentials for HTTP basic authentication (optional).
68          */
69         private final String username;
70         private final String password;
71
72         /**
73          * Timeouts (optional)
74          */
75         private Integer connectTimeoutMs = null;
76         private Integer connectionRequestTimeoutMs = null;
77         private Integer socketTimeoutMs = null;
78
79         /**
80          * Constructs a client that does not use any authentication and uses Apache
81          * HTTPD client default values for timeouts.
82          */
83         public SimpleRestClientBase() {
84                 this(null, null, null, null, null);
85         }
86
87         /**
88          * Convenience constructor to build a client that uses the specified
89          * username and password for basic HTTP authentication on all requests. In
90          * other words, this client pre-emptively sends the "Basic" header instead
91          * of first trying the request without, failing, negotiating, then sending
92          * with credentials.
93          * 
94          * @param username
95          *            User name for basic HTTP authentication.
96          * @param password
97          *            Password for basic HTTP authentication.
98          */
99         public SimpleRestClientBase(final String username, final String password) {
100                 this(username, password, null, null, null);
101         }
102
103         /**
104          * Convenience constructor to build a client that uses the specified
105          * timeouts on all requests.
106          *
107          * @param connectTimeoutMs
108          *            Connection timeout, in milliseconds
109          * @param connectionRequestTimeoutMs
110          *            Connection request timeout, in milliseconds
111          * @param socketTimeoutMs
112          *            Socket timeout, in milliseconds
113          */
114         public SimpleRestClientBase(final Integer connectTimeoutMs, final Integer connectionRequestTimeoutMs,
115                         final Integer socketTimeoutMs) {
116                 this(null, null, connectTimeoutMs, connectionRequestTimeoutMs, socketTimeoutMs);
117         }
118
119         /**
120          * Constructs a client with the specified credentials and timeout values.
121          * 
122          * @param username
123          *            User name for basic HTTP authentication; ignored if null
124          * @param password
125          *            Password for basic HTTP authentication; ignored if null
126          * @param connectTimeoutMs
127          *            ignored if null
128          * @param connectionRequestTimeoutMs
129          *            ignored if null
130          * @param socketTimeoutMs
131          *            ignored if null
132          */
133         public SimpleRestClientBase(final String username, final String password, final Integer connectTimeoutMs,
134                         final Integer connectionRequestTimeoutMs, final Integer socketTimeoutMs) {
135                 this.username = username;
136                 this.password = password;
137                 this.connectTimeoutMs = null;
138                 this.connectionRequestTimeoutMs = null;
139                 this.socketTimeoutMs = null;
140         }
141
142         /**
143          * Constructs and sends a GET request for the URI.
144          * 
145          * @param uri
146          *            REST endpoint
147          * @return Result of the get
148          * @throws Exception
149          *             On any error
150          */
151         public HttpStatusAndResponse<String> getRestContent(final URI uri) throws Exception {
152                 HttpGet httpGet = new HttpGet(uri);
153                 return doRestRequest(httpGet);
154         }
155
156         /**
157          * Constructs and sends a POST request using the specified body.
158          * 
159          * @param uri
160          *            REST endpoint
161          * @param json
162          *            Content to post
163          * @return Result of the post; null if an error happens
164          * @throws Exception
165          *             On any error
166          */
167         public HttpStatusAndResponse<String> postRestContent(final URI uri, final String json) throws Exception {
168                 HttpPost httpPost = new HttpPost(uri);
169                 StringEntity postEntity = new StringEntity(json, ContentType.create("application/json", Consts.UTF_8));
170                 httpPost.setEntity(postEntity);
171                 return doRestRequest(httpPost);
172         }
173
174         /**
175          * Constructs and sends a PUT request using the specified body.
176          * 
177          * @param uri
178          *            REST endpoint
179          * @param json
180          *            Content to put
181          * @return Result of the put; null if an error happens
182          * @throws Exception
183          *             On any error
184          */
185         public HttpStatusAndResponse<String> putRestContent(final URI uri, final String json) throws Exception {
186                 HttpPut httpPut = new HttpPut(uri);
187                 StringEntity postEntity = new StringEntity(json, ContentType.create("application/json", Consts.UTF_8));
188                 httpPut.setEntity(postEntity);
189                 return doRestRequest(httpPut);
190         }
191
192         /**
193          * Constructs and sends a DELETE request for the URI.
194          * 
195          * @param uri
196          *            REST endpoint
197          * @return Result of the get
198          * @throws Exception
199          *             On any error
200          */
201         public HttpStatusAndResponse<String> deleteRestContent(final URI uri) throws Exception {
202                 HttpDelete httpDel = new HttpDelete(uri);
203                 return doRestRequest(httpDel);
204         }
205
206         /**
207          * Executes the specified request and gathers the response.
208          * 
209          * @param request
210          *            HttpGet, HttpPost, etc.
211          * @return Status code and response body
212          * @throws ClientProtocolException
213          *             On HTTP protocol error
214          * @throws IOException
215          *             On read/write error
216          */
217         private HttpStatusAndResponse<String> doRestRequest(final HttpRequestBase request)
218                         throws ClientProtocolException, IOException {
219
220                 // Set up authentication if needed
221                 final HttpClientContext context = HttpClientContext.create();
222                 if (this.username != null || this.password != null) {
223                         UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(this.username, this.password);
224                         CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
225                         credentialsProvider.setCredentials(AuthScope.ANY, credentials);
226                         context.setCredentialsProvider(credentialsProvider);
227
228                         HttpHost host = new HttpHost(request.getURI().getHost(), request.getURI().getPort(),
229                                         request.getURI().getScheme());
230                         AuthCache authCache = new BasicAuthCache();
231                         authCache.put(host, new BasicScheme());
232                         context.setAuthCache(authCache);
233                 }
234                 final Builder requestConfigBuilder = RequestConfig.custom();
235                 if (connectionRequestTimeoutMs != null)
236                         requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeoutMs);
237                 if (connectTimeoutMs != null)
238                         requestConfigBuilder.setConnectTimeout(connectTimeoutMs);
239                 if (socketTimeoutMs != null)
240                         requestConfigBuilder.setSocketTimeout(socketTimeoutMs);
241                 RequestConfig requestConfig = requestConfigBuilder.build();
242                 final CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build();
243                 CloseableHttpResponse response = null;
244                 String responseJson = null;
245                 try {
246                         response = httpClient.execute(request, context);
247                         // Some methods return non-200 on success
248                         logger.debug("doRestRequest: status is {}", response.getStatusLine());
249                         HttpEntity entity = response.getEntity();
250                         // This is common; don't warn
251                         if (entity == null) {
252                                 logger.debug("doRestRequest: Entity is null");
253                         } else {
254                                 // entity content length is never set;
255                                 // this naively tries to read everything.
256                                 responseJson = EntityUtils.toString(entity);
257                                 EntityUtils.consume(entity);
258                                 // Don't give back empty string;
259                                 // it has no more meaning than null.
260                                 if (responseJson.length() == 0)
261                                         responseJson = null;
262                         }
263                 } finally {
264                         if (response != null)
265                                 response.close();
266                 }
267                 if (response == null)
268                         return null;
269                 return new HttpStatusAndResponse<String>(response.getStatusLine().getStatusCode(), responseJson);
270         }
271
272         /**
273          * Basic test invocation.
274          * 
275          * @param args
276          *            Expect 1 argument, the URL of a REST endpoint.
277          * @throws Exception
278          *             if anything goes wrong
279          */
280         public static void main(String[] args) throws Exception {
281                 if (args.length != 1)
282                         throw new IllegalArgumentException("Expect 1 argument: REST URL for GET");
283                 SimpleRestClientBase client = new SimpleRestClientBase();
284                 URIBuilder uriBuilder = new URIBuilder(args[0]);
285                 URI uri = uriBuilder.build();
286                 HttpStatusAndResponse<String> hsr = client.getRestContent(uri);
287                 System.out.println("Response code is " + hsr.getStatusCode());
288                 System.out.println(hsr.getResponseString());
289                 System.out.println("main ends.");
290         }
291 }