c6a4fa41d06820c452e202612e85724a7141393f
[policy/common.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2017-2020 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2018 Samsung Electronics Co., Ltd.
7  * Modifications Copyright (C) 2019 Nordix Foundation.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.common.endpoints.http.client.internal;
24
25 import com.fasterxml.jackson.annotation.JsonIgnore;
26 import java.security.KeyManagementException;
27 import java.security.NoSuchAlgorithmException;
28 import java.security.SecureRandom;
29 import java.util.Collections;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.concurrent.Future;
33 import javax.net.ssl.SSLContext;
34 import javax.ws.rs.client.Client;
35 import javax.ws.rs.client.ClientBuilder;
36 import javax.ws.rs.client.Entity;
37 import javax.ws.rs.client.Invocation.Builder;
38 import javax.ws.rs.client.InvocationCallback;
39 import javax.ws.rs.client.WebTarget;
40 import javax.ws.rs.core.Response;
41 import org.apache.commons.lang3.StringUtils;
42 import org.glassfish.jersey.client.ClientProperties;
43 import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
44 import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
45 import org.onap.policy.common.endpoints.http.client.HttpClient;
46 import org.onap.policy.common.gson.annotation.GsonJsonIgnore;
47 import org.onap.policy.common.utils.network.NetworkUtil;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 /**
52  * Http Client implementation using a Jersey Client.
53  */
54 public class JerseyClient implements HttpClient {
55
56     /**
57      * Logger.
58      */
59     private static Logger logger = LoggerFactory.getLogger(JerseyClient.class);
60
61     protected static final String JERSEY_DEFAULT_SERIALIZATION_PROVIDER =
62                     "org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJsonProvider";
63
64     protected final String name;
65     protected final boolean https;
66     protected final boolean selfSignedCerts;
67     protected final String hostname;
68     protected final int port;
69     protected final String basePath;
70     protected final String userName;
71     protected final String password;
72
73     protected final Client client;
74     protected final String baseUrl;
75
76     protected boolean alive = true;
77
78     /**
79      * Constructor.
80      *
81      * <p>name the name https is it https or not selfSignedCerts are there self signed certs
82      * hostname the hostname port port being used basePath base context userName user
83      * password password
84      *
85      * @param busTopicParams Input parameters object
86      * @throws KeyManagementException key exception
87      * @throws NoSuchAlgorithmException no algorithm exception
88      * @throws ClassNotFoundException if the serialization provider cannot be found
89      */
90     public JerseyClient(BusTopicParams busTopicParams)
91                     throws KeyManagementException, NoSuchAlgorithmException, ClassNotFoundException {
92
93         if (busTopicParams.isClientNameInvalid()) {
94             throw new IllegalArgumentException("Name must be provided");
95         }
96
97         if (busTopicParams.isHostnameInvalid()) {
98             throw new IllegalArgumentException("Hostname must be provided");
99         }
100
101         if (busTopicParams.isPortInvalid()) {
102             throw new IllegalArgumentException("Invalid Port provided: " + busTopicParams.getPort());
103         }
104
105         this.name = busTopicParams.getClientName();
106         this.https = busTopicParams.isUseHttps();
107         this.hostname = busTopicParams.getHostname();
108         this.port = busTopicParams.getPort();
109         this.basePath = busTopicParams.getBasePath();
110         this.userName = busTopicParams.getUserName();
111         this.password = busTopicParams.getPassword();
112         this.selfSignedCerts = busTopicParams.isAllowSelfSignedCerts();
113         this.client = detmClient();
114
115         if (!StringUtils.isBlank(this.userName) && !StringUtils.isBlank(this.password)) {
116             HttpAuthenticationFeature authFeature = HttpAuthenticationFeature.basic(userName, password);
117             this.client.register(authFeature);
118         }
119
120         this.client.property(ClientProperties.METAINF_SERVICES_LOOKUP_DISABLE, "true");
121
122         registerSerProviders(busTopicParams.getSerializationProvider());
123
124         this.baseUrl = (this.https ? "https://" : "http://") + this.hostname + ":" + this.port + "/"
125                         + (this.basePath == null ? "" : this.basePath);
126     }
127
128     private Client detmClient() throws NoSuchAlgorithmException, KeyManagementException {
129         if (this.https) {
130             ClientBuilder clientBuilder;
131             SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
132             if (this.selfSignedCerts) {
133                 sslContext.init(null, NetworkUtil.getAlwaysTrustingManager(), new SecureRandom());
134                 clientBuilder =
135                         ClientBuilder.newBuilder().sslContext(sslContext).hostnameVerifier((host, session) -> true);
136             } else {
137                 sslContext.init(null, null, null);
138                 clientBuilder = ClientBuilder.newBuilder().sslContext(sslContext);
139             }
140             return clientBuilder.build();
141
142         } else {
143             return ClientBuilder.newClient();
144         }
145     }
146
147     /**
148      * Registers the serialization provider(s) with the client.
149      *
150      * @param serializationProvider comma-separated list of serialization providers
151      * @throws ClassNotFoundException if the serialization provider cannot be found
152      */
153     private void registerSerProviders(String serializationProvider) throws ClassNotFoundException {
154         String providers = (StringUtils.isBlank(serializationProvider)
155                         ? JERSEY_DEFAULT_SERIALIZATION_PROVIDER : serializationProvider);
156         for (String prov : providers.split(",")) {
157             this.client.register(Class.forName(prov));
158         }
159     }
160
161     @Override
162     public WebTarget getWebTarget() {
163         return this.client.target(this.baseUrl);
164     }
165
166     @Override
167     public Response get(String path) {
168         if (!StringUtils.isBlank(path)) {
169             return getWebTarget().path(path).request().get();
170         } else {
171             return getWebTarget().request().get();
172         }
173     }
174
175     @Override
176     public Response get() {
177         return getWebTarget().request().get();
178     }
179
180     @Override
181     public Future<Response> get(InvocationCallback<Response> callback, String path, Map<String, Object> headers) {
182         Map<String, Object> headers2 = (headers != null ? headers : Collections.emptyMap());
183
184         if (!StringUtils.isBlank(path)) {
185             return getBuilder(path, headers2).async().get(callback);
186         } else {
187             return get(callback, headers2);
188         }
189     }
190
191     @Override
192     public Future<Response> get(InvocationCallback<Response> callback, Map<String, Object> headers) {
193         Builder builder = getWebTarget().request();
194         if (headers != null) {
195             headers.forEach(builder::header);
196         }
197         return builder.async().get(callback);
198     }
199
200     @Override
201     public Response put(String path, Entity<?> entity, Map<String, Object> headers) {
202         return getBuilder(path, headers).put(entity);
203     }
204
205     @Override
206     public Future<Response> put(InvocationCallback<Response> callback, String path, Entity<?> entity,
207                     Map<String, Object> headers) {
208         return getBuilder(path, headers).async().put(entity, callback);
209     }
210
211     @Override
212     public Response post(String path, Entity<?> entity, Map<String, Object> headers) {
213         return getBuilder(path, headers).post(entity);
214     }
215
216     @Override
217     public Future<Response> post(InvocationCallback<Response> callback, String path, Entity<?> entity,
218                     Map<String, Object> headers) {
219         return getBuilder(path, headers).async().post(entity, callback);
220     }
221
222     @Override
223     public Response delete(String path, Map<String, Object> headers) {
224         return getBuilder(path, headers).delete();
225     }
226
227     @Override
228     public Future<Response> delete(InvocationCallback<Response> callback, String path, Map<String, Object> headers) {
229         return getBuilder(path, headers).async().delete(callback);
230     }
231
232     @Override
233     public boolean start() {
234         return alive;
235     }
236
237     @Override
238     public boolean stop() {
239         return !alive;
240     }
241
242     @Override
243     public void shutdown() {
244         synchronized (this) {
245             alive = false;
246         }
247
248         try {
249             this.client.close();
250         } catch (Exception e) {
251             logger.warn("{}: cannot close because of {}", this, e.getMessage(), e);
252         }
253     }
254
255     @Override
256     public synchronized boolean isAlive() {
257         return this.alive;
258     }
259
260     @Override
261     public String getName() {
262         return name;
263     }
264
265     @Override
266     public boolean isHttps() {
267         return https;
268     }
269
270     @Override
271     public boolean isSelfSignedCerts() {
272         return selfSignedCerts;
273     }
274
275     @Override
276     public String getHostname() {
277         return hostname;
278     }
279
280     @Override
281     public int getPort() {
282         return port;
283     }
284
285     @Override
286     public String getBasePath() {
287         return basePath;
288     }
289
290     @Override
291     public String getUserName() {
292         return userName;
293     }
294
295     @JsonIgnore
296     @GsonJsonIgnore
297     @Override
298     public String getPassword() {
299         return password;
300     }
301
302     @Override
303     public String getBaseUrl() {
304         return baseUrl;
305     }
306
307     @Override
308     public String toString() {
309         StringBuilder builder = new StringBuilder();
310         builder.append("JerseyClient [name=");
311         builder.append(name);
312         builder.append(", https=");
313         builder.append(https);
314         builder.append(", selfSignedCerts=");
315         builder.append(selfSignedCerts);
316         builder.append(", hostname=");
317         builder.append(hostname);
318         builder.append(", port=");
319         builder.append(port);
320         builder.append(", basePath=");
321         builder.append(basePath);
322         builder.append(", userName=");
323         builder.append(userName);
324         builder.append(", password=");
325         builder.append(password);
326         builder.append(", client=");
327         builder.append(client);
328         builder.append(", baseUrl=");
329         builder.append(baseUrl);
330         builder.append(", alive=");
331         builder.append(alive);
332         builder.append("]");
333         return builder.toString();
334     }
335
336     private Builder getBuilder(String path, Map<String, Object> headers) {
337         Builder builder = getWebTarget().path(path).request();
338         for (Entry<String, Object> header : headers.entrySet()) {
339             builder.header(header.getKey(), header.getValue());
340         }
341         return builder;
342     }
343
344
345 }