a77b4d3e983192ed69ade7214bf54fc032a8c9b6
[ccsdk/sli/adaptors.git] / netbox-client / provider / src / main / java / org / onap / ccsdk / sli / adaptors / netbox / impl / NetboxHttpClient.java
1 /*
2  * Copyright (C) 2018 Bell Canada.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.onap.ccsdk.sli.adaptors.netbox.impl;
17
18 import static org.apache.http.HttpHeaders.ACCEPT;
19 import static org.apache.http.HttpHeaders.AUTHORIZATION;
20 import static org.apache.http.HttpHeaders.CONTENT_TYPE;
21
22 import java.io.IOException;
23 import java.nio.charset.Charset;
24 import java.security.KeyManagementException;
25 import java.security.KeyStoreException;
26 import java.security.NoSuchAlgorithmException;
27 import java.util.Scanner;
28 import java.util.concurrent.CompletableFuture;
29 import java.util.concurrent.CompletionStage;
30 import java.util.function.Function;
31 import javax.net.ssl.SSLContext;
32 import org.apache.http.HttpEntityEnclosingRequest;
33 import org.apache.http.HttpResponse;
34 import org.apache.http.client.methods.HttpDelete;
35 import org.apache.http.client.methods.HttpPost;
36 import org.apache.http.client.methods.HttpUriRequest;
37 import org.apache.http.concurrent.FutureCallback;
38 import org.apache.http.conn.ssl.NoopHostnameVerifier;
39 import org.apache.http.entity.StringEntity;
40 import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
41 import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
42 import org.apache.http.ssl.SSLContexts;
43 import org.apache.http.ssl.TrustStrategy;
44 import org.onap.ccsdk.sli.adaptors.netbox.api.IpamException;
45 import org.onap.ccsdk.sli.adaptors.netbox.property.NetboxProperties;
46
47 public class NetboxHttpClient implements AutoCloseable {
48
49     private static final String APPLICATION_JSON = "application/json";
50
51     private final CloseableHttpAsyncClient client;
52     private final String url;
53     private final String token;
54
55     // Used by the blueprint container
56     public NetboxHttpClient(NetboxProperties properties) {
57         this(properties.getHost(), properties.getApiKey());
58     }
59
60     NetboxHttpClient(final String url, final String token) {
61         this.url = url;
62         this.token = token;
63
64         final TrustStrategy acceptingTrustStrategy = (certificate, authType) -> true;
65         final SSLContext sslContext;
66         try {
67             sslContext = SSLContexts.custom()
68                 .loadTrustMaterial(null, acceptingTrustStrategy).build();
69         } catch (final NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
70             throw new IllegalStateException("Can't create http client", e);
71         }
72         client = HttpAsyncClientBuilder.create()
73             .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
74             .setSSLContext(sslContext)
75             .build();
76
77     }
78
79     // Has to be public for blueprint container to access it
80     public void init() {
81         client.start();
82     }
83
84     @Override
85     public void close() throws IOException {
86         client.close();
87     }
88
89     CompletionStage<HttpResponse> post(final String uri, final String requestBody) {
90         return sendRequest(uri, requestBody, HttpPost::new);
91     }
92
93     CompletionStage<HttpResponse> delete(final String uri) {
94         return sendRequest(uri, HttpDelete::new);
95     }
96
97     static String getBodyAsString(final HttpResponse response) {
98         final String body;
99         if (response.getEntity() != null) {
100             try (final Scanner s = new java.util.Scanner(response.getEntity().getContent()).useDelimiter("\\A")) {
101                 body = s.hasNext() ? s.next() : "";
102             } catch (final IOException e) {
103                 throw new IllegalStateException(e);
104             }
105         } else {
106             body = "";
107         }
108         return response.toString() + "\n" + body;
109     }
110
111     private <T extends HttpUriRequest> CompletionStage<HttpResponse> sendRequest(final String uri,
112         final Function<String, T> supplier) {
113         final T request = supplier.apply(url + uri);
114         request.addHeader(ACCEPT, APPLICATION_JSON);
115         request.addHeader(CONTENT_TYPE, APPLICATION_JSON);
116         request.addHeader(AUTHORIZATION, "Token " + token);
117         return sendRequest(request);
118     }
119
120     private <T extends HttpEntityEnclosingRequest & HttpUriRequest>
121     CompletionStage<HttpResponse> sendRequest(final String uri, final String body,
122         final Function<String, T> supplier) {
123         final T request = supplier.apply(url + uri);
124         request.addHeader(ACCEPT, APPLICATION_JSON);
125         request.addHeader(CONTENT_TYPE, APPLICATION_JSON);
126         request.addHeader(AUTHORIZATION, "Token " + token);
127         request.setEntity(new StringEntity(body, Charset.forName("UTF-8")));
128         return sendRequest(request);
129     }
130
131     private CompletionStage<HttpResponse> sendRequest(final HttpUriRequest request) {
132         final CompletableFuture<HttpResponse> future = new CompletableFuture<>();
133         client.execute(request, new FutureCallback<HttpResponse>() {
134             @Override
135             public void completed(final HttpResponse httpResponse) {
136                 future.complete(httpResponse);
137             }
138
139             @Override
140             public void failed(final Exception e) {
141                 future.completeExceptionally(new IpamException("Netbox request failed", e));
142             }
143
144             @Override
145             public void cancelled() {
146                 future.cancel(false);
147             }
148         });
149         return future;
150     }
151 }