2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.openecomp.mso.rest;
24 import java.io.Closeable;
25 import java.io.IOException;
26 import java.io.UnsupportedEncodingException;
28 import java.net.URLEncoder;
29 import java.util.ArrayList;
30 import java.util.Iterator;
31 import java.util.LinkedHashMap;
32 import java.util.List;
35 import javax.net.ssl.SSLSocketFactory;
37 import org.apache.http.HttpEntity;
38 import org.apache.http.HttpHost;
39 import org.apache.http.HttpResponse;
40 import org.apache.http.client.HttpClient;
41 import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
42 import org.apache.http.client.methods.HttpGet;
43 import org.apache.http.client.methods.HttpPatch;
44 import org.apache.http.client.methods.HttpPost;
45 import org.apache.http.client.methods.HttpPut;
46 import org.apache.http.config.Registry;
47 import org.apache.http.config.RegistryBuilder;
48 import org.apache.http.conn.socket.ConnectionSocketFactory;
49 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
50 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
51 import org.apache.http.entity.StringEntity;
52 import org.apache.http.impl.client.CloseableHttpClient;
53 import org.apache.http.impl.client.HttpClientBuilder;
54 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
55 import org.apache.http.message.AbstractHttpMessage;
56 import org.apache.http.util.EntityUtils;
58 import org.openecomp.mso.logger.MsoLogger;
60 * Client used to send RESTFul requests.
62 * Many of the methods return a reference to the 'this,' thereby allowing
65 * An example of usage can be found below:
69 * client = new RESTClient("http://www.openecomp.org");
70 * APIResponse response = client
71 * .setHeader("Accept", "application/json")
72 * .setHeader("Clientid", "clientid")
73 * .setHeader("header", "value")
74 * .httpPost("postbody");
75 * if (response.getStatusCode() == 200) {
76 * System.out.println("Success!");
78 * } catch (RESTException re) {
86 public class RESTClient {
88 private static final MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
89 private final String proxyHost;
90 private final int proxyPort;
92 private final String URL;
94 private final LinkedHashMap<String, List<String>> headers;
95 private final LinkedHashMap<String, List<String>> parameters;
97 private HttpEntity httpEntity;
100 * Internal method used to build an APIResponse using the specified
101 * HttpResponse object.
103 * @param response response wrapped inside an APIResponse object
104 * @return api response
106 private APIResponse buildResponse(HttpResponse response)
107 throws RESTException {
109 return new APIResponse(response);
113 * Used to release any resources used by the connection.
114 * @param response HttpResponse object used for releasing the connection
115 * @throws RESTException if unable to release connection
118 private void releaseConnection(HttpResponse response) throws RESTException {
120 EntityUtils.consume(response.getEntity());
121 } catch (IOException ioe) {
122 throw new RESTException(ioe);
127 * Sets headers to the http message.
129 * @param httpMsg http message to set headers for
131 private void addInternalHeaders(AbstractHttpMessage httpMsg) {
132 if (headers.isEmpty()) {
136 final Set<String> keySet = headers.keySet();
137 for (final String key : keySet) {
138 final List<String> values = headers.get(key);
139 for (final String value : values) {
140 httpMsg.addHeader(key, value);
146 * Builds the query part of a URL.
150 private String buildQuery() {
151 if (this.parameters.size() == 0) {
155 StringBuilder sb = new StringBuilder();
156 String charSet = "UTF-8";
158 Iterator<String> keyitr = this.parameters.keySet().iterator();
159 for (int i = 0; keyitr.hasNext(); ++i) {
164 final String name = keyitr.next();
165 final List<String> values = this.parameters.get(name);
166 for(final String value : values) {
167 sb.append(URLEncoder.encode(name, charSet));
169 sb.append(URLEncoder.encode(value, charSet));
172 } catch (UnsupportedEncodingException e) {
173 LOGGER.debug("Exception :", e);
175 return sb.toString();
179 * Creates an http client that can be used for sending http requests.
181 * @return created http client
183 * @throws RESTException if unable to create http client.
185 private CloseableHttpClient createClient() throws RESTException {
186 //TODO - we may want to trust self signed certificate at some point - add implementation here
187 HttpClientBuilder clientBuilder;
190 SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
191 (SSLSocketFactory) SSLSocketFactory.getDefault(),
192 new HostNameVerifier());
193 Registry<ConnectionSocketFactory> registry = RegistryBuilder
194 .<ConnectionSocketFactory> create()
196 PlainConnectionSocketFactory.getSocketFactory())
197 .register("https", sslSocketFactory).build();
198 PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(
200 clientBuilder = HttpClientBuilder.create().setConnectionManager(
202 } catch (Exception ex) {
203 LOGGER.debug("Exception :", ex);
204 throw new RESTException(ex.getMessage());
206 clientBuilder.disableRedirectHandling();
208 if ((this.proxyHost != null) && (this.proxyPort != -1)) {
209 HttpHost proxy = new HttpHost(this.proxyHost, this.proxyPort);
210 clientBuilder.setProxy(proxy);
213 return clientBuilder.build();
217 * Creates a RESTClient with the specified URL, proxy host, and proxy port.
219 * @param URL URL to send request to
220 * @param proxyHost proxy host to use for sending request
221 * @param proxyPort proxy port to use for sendin request
223 * @throws RESTException if unable to create a RESTClient
225 public RESTClient(String URL, String proxyHost, int proxyPort)
226 throws RESTException {
227 this(new RESTConfig(URL, proxyHost, proxyPort));
231 * Creates a RESTClient with the specified URL. No proxy host nor port will
234 * @param URL URL to send request to
236 * @throws RESTException if unable to create a RESTClient
238 public RESTClient(String URL) throws RESTException {
239 this(new RESTConfig(URL));
243 * Creates a RESTClient with the RESTConfig object.
245 * @param RESTConfig config to use for sending request
247 * @throws RESTException if unable to create a RESTClient
249 public RESTClient(RESTConfig cfg) throws RESTException {
250 this.headers = new LinkedHashMap<String, List<String>>();
251 this.parameters = new LinkedHashMap<String, List<String>>();
252 this.URL = cfg.getURL();
253 this.proxyHost = cfg.getProxyHost();
254 this.proxyPort = cfg.getProxyPort();
258 * Adds parameter to be sent during http request.
260 * Does not remove any parameters with the same name, thus allowing
263 * @param name name of parameter
264 * @param value value of parametr
265 * @return a reference to 'this', which can be used for method chaining
267 public RESTClient addParameter(String name, String value) {
268 if (!parameters.containsKey(name)) {
269 parameters.put(name, new ArrayList<String>());
272 List<String> values = parameters.get(name);
279 * Sets parameter to be sent during http request.
281 * Removes any parameters with the same name, thus disallowing duplicates.
283 * @param name name of parameter
284 * @param value value of parametr
285 * @return a reference to 'this', which can be used for method chaining
287 public RESTClient setParameter(String name, String value) {
288 if (parameters.containsKey(name)) {
289 parameters.get(name).clear();
292 addParameter(name, value);
298 * Adds http header to be sent during http request.
300 * Does not remove any headers with the same name, thus allowing
303 * @param name name of header
304 * @param value value of header
305 * @return a reference to 'this', which can be used for method chaining
307 public RESTClient addHeader(String name, String value) {
308 if (!headers.containsKey(name)) {
309 headers.put(name, new ArrayList<String>());
312 List<String> values = headers.get(name);
319 * Sets http header to be sent during http request.
321 * Does not remove any headers with the same name, thus allowing
324 * @param name name of header
325 * @param value value of header
326 * @return a reference to 'this', which can be used for method chaining
328 public RESTClient setHeader(String name, String value) {
329 if (headers.containsKey(name)) {
330 headers.get(name).clear();
333 addHeader(name, value);
339 * Convenience method for adding the authorization header using the
340 * specified OAuthToken object.
342 * @param token token to use for setting authorization
343 * @return a reference to 'this,' which can be used for method chaining
345 public RESTClient addAuthorizationHeader(String token) {
346 this.addHeader("Authorization", token);
351 * Alias for httpGet().
353 * @see RESTClient#httpGet()
355 public APIResponse get() throws RESTException {
360 * Sends an http GET request using the parameters and headers previously
363 * @return api response
365 * @throws RESTException if request was unsuccessful
367 public APIResponse httpGet() throws RESTException {
368 HttpResponse response = null;
370 try (CloseableHttpClient httpClient = createClient()) {
372 if (!buildQuery().equals("")) {
373 query = "?" + buildQuery();
375 HttpGet httpGet = new HttpGet(this.getURL() + query);
376 addInternalHeaders(httpGet);
378 response = httpClient.execute(httpGet);
380 APIResponse apiResponse = buildResponse(response);
382 } catch (IOException ioe) {
383 throw new RESTException(ioe);
385 if (response != null) {
386 this.releaseConnection(response);
392 * Alias for httpPost()
394 * @see RESTClient#httpPost()
396 public APIResponse post() throws RESTException {
401 * Sends an http POST request.
403 * POST body will be set to the values set using add/setParameter()
405 * @return api response
407 * @throws RESTException if POST was unsuccessful
409 public APIResponse httpPost() throws RESTException {
410 APIResponse response = httpPost(buildQuery());
415 * Sends an http POST request using the specified body.
417 * @return api response
419 * @throws RESTException if POST was unsuccessful
421 public APIResponse httpPost(String body) throws RESTException {
422 HttpResponse response = null;
423 try (CloseableHttpClient httpClient = createClient()) {
424 HttpPost httpPost = new HttpPost(this.getURL());
425 addInternalHeaders(httpPost);
426 if (body != null && !body.equals("")) {
427 httpEntity = new StringEntity(body);
428 httpPost.setEntity(new StringEntity(body));
431 response = httpClient.execute(httpPost);
433 return buildResponse(response);
434 } catch (IOException e) {
435 throw new RESTException(e);
437 if (response != null) {
438 this.releaseConnection(response);
445 * @param body Data to PUT
446 * @return API response
447 * @throws RESTException
449 public APIResponse httpPut(String body) throws RESTException {
450 HttpResponse response = null;
451 try (CloseableHttpClient httpClient = createClient()) {
454 if (!buildQuery().equals("")) {
455 query = "?" + buildQuery();
457 HttpPut httpPut = new HttpPut(this.getURL() + query);
458 addInternalHeaders(httpPut);
459 if (body != null && !body.equals("")) {
460 httpEntity = new StringEntity(body);
461 httpPut.setEntity(httpEntity);
464 response = httpClient.execute(httpPut);
466 return buildResponse(response);
467 } catch (IOException e) {
468 throw new RESTException(e);
470 if (response != null) {
471 this.releaseConnection(response);
477 * Alias for httpPatch().
479 * @see RESTClient#httpPatch()
481 public APIResponse patch(String body) throws RESTException {
482 return httpPatch(body);
487 * @param body Data to PATCH
488 * @return API response
489 * @throws RESTException
491 public APIResponse httpPatch(String body) throws RESTException {
492 HttpResponse response = null;
493 try (CloseableHttpClient httpClient = createClient()) {
495 if (!buildQuery().equals("")) {
496 query = "?" + buildQuery();
498 HttpPatch httpPatch = new HttpPatch(this.getURL() + query);
499 addInternalHeaders(httpPatch);
500 if (body != null && !body.equals("")) {
501 httpEntity = new StringEntity(body);
502 httpPatch.setEntity(httpEntity);
505 response = httpClient.execute(httpPatch);
507 return buildResponse(response);
508 } catch (IOException e) {
509 throw new RESTException(e);
511 if (response != null) {
512 this.releaseConnection(response);
518 * Alias for httpDelete().
520 * @see RESTClient#httpDelete()
522 public APIResponse delete() throws RESTException {
527 * Sends an http DELETE request using the parameters and headers previously
530 * @return api response
532 * @throws RESTException if request was unsuccessful
534 public APIResponse httpDelete() throws RESTException {
535 return httpDelete(null);
539 * Sends an http DELETE request with a body, using the parameters and headers
542 * @return api response
544 * @throws RESTException if request was unsuccessful
546 public APIResponse httpDelete(String body) throws RESTException {
547 HttpResponse response = null;
549 try (CloseableHttpClient httpClient = createClient()){
552 if (!buildQuery().equals("")) {
553 query = "?" + buildQuery();
555 HttpDeleteWithBody httpDelete = new HttpDeleteWithBody(this.getURL() + query);
556 addInternalHeaders(httpDelete);
558 if (body != null && !body.equals("")) {
559 httpEntity = new StringEntity(body);
560 httpDelete.setEntity(httpEntity);
563 response = httpClient.execute(httpDelete);
565 APIResponse apiResponse = buildResponse(response);
567 } catch (IOException ioe) {
568 throw new RESTException(ioe);
570 if (response != null) {
571 this.releaseConnection(response);
576 public String getURL() {
579 public LinkedHashMap<String,List<String>> getHeaders() {
582 public LinkedHashMap<String,List<String>> getParameters() {
585 public HttpEntity getHttpEntity() {
591 * Allows inclusion of a request body with DELETE.
593 private class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase {
594 public static final String METHOD_NAME = "DELETE";
596 public String getMethod() {
600 public HttpDeleteWithBody(final String uri) {
602 setURI(URI.create(uri));
605 public HttpDeleteWithBody(final URI uri) {
610 public HttpDeleteWithBody() {