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