Merge "send INVOCATION_ID header via RestMsoImplementation"
[vid.git] / vid-app-common / src / main / java / org / onap / vid / mso / RestMsoImplementation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
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  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.vid.mso;
22
23 import static org.onap.vid.logging.Headers.INVOCATION_ID;
24 import static org.onap.vid.logging.Headers.PARTNER_NAME;
25 import static org.onap.vid.utils.Logging.ONAP_REQUEST_ID_HEADER_KEY;
26 import static org.onap.vid.utils.Logging.REQUEST_ID_HEADER_KEY;
27 import static org.onap.vid.utils.Logging.getMethodCallerName;
28 import static org.onap.vid.utils.Logging.getMethodName;
29
30 import com.att.eelf.configuration.EELFLogger;
31 import com.fasterxml.jackson.databind.ObjectMapper;
32 import java.util.Collections;
33 import java.util.Optional;
34 import javax.ws.rs.client.Client;
35 import javax.ws.rs.client.Entity;
36 import javax.ws.rs.client.Invocation;
37 import javax.ws.rs.core.MediaType;
38 import javax.ws.rs.core.MultivaluedHashMap;
39 import javax.ws.rs.core.Response;
40 import org.apache.commons.codec.binary.Base64;
41 import org.apache.http.HttpException;
42 import org.eclipse.jetty.util.security.Password;
43 import org.glassfish.jersey.client.ClientProperties;
44 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
45 import org.onap.vid.aai.ExceptionWithRequestInfo;
46 import org.onap.vid.aai.util.HttpClientMode;
47 import org.onap.vid.aai.util.HttpsAuthClient;
48 import org.onap.vid.client.HttpBasicClient;
49 import org.onap.vid.exceptions.GenericUncheckedException;
50 import org.onap.vid.mso.rest.RestInterface;
51 import org.onap.vid.utils.Logging;
52 import org.onap.vid.utils.SystemPropertiesWrapper;
53 import org.springframework.beans.factory.annotation.Autowired;
54 import org.springframework.http.HttpMethod;
55
56 /**
57  * Created by pickjonathan on 26/06/2017.
58  */
59 public class RestMsoImplementation implements RestInterface {
60
61     
62     /**
63      * The logger.
64      */
65     protected EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(RestMsoImplementation.class);
66     private final EELFLogger outgoingRequestsLogger = Logging.getRequestsLogger("mso");
67
68     /** The client. */
69     private Client client = null;
70
71
72     protected HttpsAuthClient httpsAuthClient;
73     protected SystemPropertiesWrapper systemProperties;
74     protected final Logging loggingService;
75
76     private static final String START_LOG = " start";
77     private static final String APPLICATION_JSON = "application/json";
78     private static final String WITH_STATUS = " with status=";
79     private static final String URL_LOG = ", url=";
80     private static final String NO_RESPONSE_ENTITY_LOG = " No response entity, this is probably ok, e=";
81     private static final String WITH_URL_LOG = " with url=";
82     private static final String EXCEPTION_LOG = ", Exception: ";
83     private static final String REST_API_SUCCESSFULL_LOG = " REST api was successfull!";
84     private static final String REST_MSG_TEMPLATE = "start {}->{}({}, {}, {})";
85     /** The common headers. */
86     /**
87      * Instantiates a new mso rest interface.
88      */
89
90     @Autowired
91     public RestMsoImplementation(HttpsAuthClient httpsAuthClient, SystemPropertiesWrapper systemProperties, Logging loggingService){
92         this.httpsAuthClient=httpsAuthClient;
93         this.systemProperties = systemProperties;
94         this.loggingService = loggingService;
95     }
96
97     @SuppressWarnings("Duplicates")
98     protected MultivaluedHashMap<String, Object> initMsoClient()
99     {
100         final String methodname = "initRestClient()";
101
102         final String username = systemProperties.getProperty(MsoProperties.MSO_USER_NAME);
103         final String password = systemProperties.getProperty(MsoProperties.MSO_PASSWORD);
104         final String mso_url = systemProperties.getProperty(MsoProperties.MSO_SERVER_URL);
105         final String decrypted_password = Password.deobfuscate(password);
106
107         String authString = username + ":" + decrypted_password;
108
109         byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
110         String authStringEnc = new String(authEncBytes);
111
112         MultivaluedHashMap<String, Object> commonHeaders = new MultivaluedHashMap();
113         commonHeaders.put("Authorization",  Collections.singletonList(("Basic " + authStringEnc)));
114         commonHeaders.put(PARTNER_NAME.getHeaderName(), Collections.singletonList(PARTNER_NAME.getHeaderValue()));
115
116         String requestIdValue = Logging.extractOrGenerateRequestId();
117         commonHeaders.put(REQUEST_ID_HEADER_KEY, Collections.singletonList(requestIdValue));
118         commonHeaders.put(ONAP_REQUEST_ID_HEADER_KEY, Collections.singletonList(requestIdValue));
119         commonHeaders.put(INVOCATION_ID.getHeaderName(), Collections.singletonList(INVOCATION_ID.getHeaderValue()));
120
121         boolean useSsl = true;
122         if ( (mso_url != null) && ( !(mso_url.isEmpty()) ) ) {
123             useSsl = mso_url.startsWith("https");
124         }
125         if (client == null) {
126
127             try {
128                 if ( useSsl ) {
129                     client = httpsAuthClient.getClient(HttpClientMode.WITHOUT_KEYSTORE);
130                 }
131                 else {
132                     client = HttpBasicClient.getClient();
133                 }
134             } catch (Exception e) {
135                 logger.info(EELFLoggerDelegate.errorLogger,methodname + " Unable to get the SSL client");
136             }
137         }
138
139         return commonHeaders;
140     }
141
142     public <T> RestObjectWithRequestInfo<T> Get(T t, String path, RestObject<T> restObject, boolean warpException) {
143         String methodName = "Get";
144
145         logger.debug(EELFLoggerDelegate.debugLogger, methodName + START_LOG);
146
147         String url = null;
148         String rawData = null;
149         Integer status = null;
150
151         try {
152             restObject.set(t);
153             url = systemProperties.getProperty(MsoProperties.MSO_SERVER_URL) + path;
154
155             MultivaluedHashMap<String, Object> commonHeaders = initMsoClient();
156             loggingService.logRequest(outgoingRequestsLogger, HttpMethod.GET, url);
157                 final Response cres = client.target(url)
158                     .request()
159                     .accept(APPLICATION_JSON)
160                     .headers(commonHeaders)
161                     .get();
162             loggingService.logResponse(outgoingRequestsLogger, HttpMethod.GET, url, cres);
163
164             cres.bufferEntity();
165             status = cres.getStatus();
166             rawData = cres.readEntity(String.class);
167
168             restObject.setStatusCode(status);
169
170             if (status == 200 || status == 202) {
171                 t = (T) cres.readEntity(t.getClass());
172                 restObject.set(t);
173                 logger.debug(EELFLoggerDelegate.debugLogger, methodName + REST_API_SUCCESSFULL_LOG);
174
175             } else {
176                 throw new GenericUncheckedException(new HttpException(methodName + WITH_STATUS + status + " (200 or 202 expected), url= " + url));
177             }
178
179             logger.debug(EELFLoggerDelegate.debugLogger, methodName + " received status=" + status);
180
181             return new RestObjectWithRequestInfo<>(HttpMethod.GET, url, restObject, status, rawData);
182         } catch (RuntimeException e) {
183             throw warpException ? new ExceptionWithRequestInfo(HttpMethod.GET, url, rawData, status, e) : e;
184         }
185     }
186
187     @Override
188     public <T> RestObject<T> GetForObject(String path, Class<T> clazz) {
189         final String methodName = getMethodName();
190         logger.debug(EELFLoggerDelegate.debugLogger, "start {}->{}({}, {})", getMethodCallerName(), methodName, path, clazz);
191
192         String url = systemProperties.getProperty(MsoProperties.MSO_SERVER_URL) + path;
193         logger.debug(EELFLoggerDelegate.debugLogger, "<== " +  methodName + " sending request to url= " + url);
194
195         MultivaluedHashMap<String, Object> commonHeaders = initMsoClient();
196         loggingService.logRequest(outgoingRequestsLogger, HttpMethod.GET, url);
197         final Response cres = client.target(url)
198                 .request()
199                 .accept(APPLICATION_JSON)
200                 .headers(commonHeaders)
201                 .get();
202         loggingService.logResponse(outgoingRequestsLogger, HttpMethod.GET, url, cres);
203         final RestObject<T> restObject = cresToRestObject(cres, clazz);
204         int status = cres.getStatus();
205
206         if (status == 200 || status == 202) {
207             logger.debug(EELFLoggerDelegate.debugLogger, methodName + REST_API_SUCCESSFULL_LOG);
208         } else {
209             logger.debug(EELFLoggerDelegate.debugLogger,"<== " + methodName + WITH_STATUS +status+ URL_LOG +url);
210         }
211
212         logger.debug(EELFLoggerDelegate.debugLogger,methodName + " received status=" + status );
213
214         return restObject;
215     }
216
217     public <T> RestObject<T> PostForObject(Object requestDetails, String path, Class<T> clazz) {
218         logger.debug(EELFLoggerDelegate.debugLogger, REST_MSG_TEMPLATE, getMethodCallerName(), getMethodName(), requestDetails, path, clazz);
219         return restCall(HttpMethod.POST, clazz, requestDetails, path);
220     }
221
222     public <T> RestObject<T> DeleteForObject(Object requestDetails, String path, Class<T> clazz) {
223         logger.debug(EELFLoggerDelegate.debugLogger, REST_MSG_TEMPLATE, getMethodCallerName(), getMethodName(), requestDetails, path, clazz);
224         return restCall(HttpMethod.DELETE, clazz, requestDetails, path);
225     }
226
227     @Override
228     public void Post(String t, Object r, String path, RestObject<String> restObject) {
229         logger.debug(EELFLoggerDelegate.debugLogger, REST_MSG_TEMPLATE, getMethodCallerName(), getMethodName(), t.getClass(), r, path);
230         restObject.copyFrom(restCall(HttpMethod.POST, String.class, r, path));
231     }
232
233     public Invocation.Builder prepareClient(String path, String methodName) {
234         MultivaluedHashMap<String, Object> commonHeaders = initMsoClient();
235
236         String url = systemProperties.getProperty(MsoProperties.MSO_SERVER_URL) + path;
237         logger.debug(EELFLoggerDelegate.debugLogger,"<== " +  methodName + " sending request to url= " + url);
238         // Change the content length
239         return client.target(url)
240                 .request()
241                 .accept(APPLICATION_JSON)
242                 .headers(commonHeaders);
243     }
244
245     public <T> RestObject<T> restCall(HttpMethod httpMethod, Class<T> tClass, Object payload, String path) {
246         return restCall(httpMethod, tClass, payload, path, Optional.empty());
247     }
248
249
250     /*
251     user id is needed to be pass as X-RequestorID in new MSO flows like Delete instanceGroup
252      */
253     public <T> RestObject<T> restCall(HttpMethod httpMethod, Class<T> tClass, Object payload, String path, Optional<String> userId)  {
254         String methodName = httpMethod.name();
255         String url="";
256
257         try {
258
259             MultivaluedHashMap<String, Object> commonHeaders = initMsoClient();
260             userId.ifPresent(id->commonHeaders.put("X-RequestorID", Collections.singletonList(id)));
261
262             url = systemProperties.getProperty(MsoProperties.MSO_SERVER_URL) + path;
263             loggingService.logRequest(outgoingRequestsLogger, httpMethod, url, payload);
264             // Change the content length
265             final Invocation.Builder restBuilder = client.target(url)
266                     .request()
267                     .accept(APPLICATION_JSON)
268                     .headers(commonHeaders)
269                     .property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true)
270                 ;
271
272             Invocation restInvocation = payload==null ?
273                     restBuilder.build(httpMethod.name()) :
274                     restBuilder.build(httpMethod.name(), Entity.entity(payload, MediaType.APPLICATION_JSON));
275             final Response cres = restInvocation.invoke();
276
277             loggingService.logResponse(outgoingRequestsLogger, httpMethod, url, cres);
278             return cresToRestObject(cres, tClass);
279         }
280         catch (Exception e) {
281             logger.debug(EELFLoggerDelegate.debugLogger,"<== " + methodName + WITH_URL_LOG +url+ EXCEPTION_LOG + e.toString());
282             throw e;
283         }
284
285     }
286
287     private <T> RestObject<T> cresToRestObject(Response cres, Class<?> tClass) {
288         RestObject<T> restObject = new RestObject<>();
289
290         String rawEntity = null;
291         try {
292             cres.bufferEntity();
293             rawEntity = cres.readEntity(String.class);
294             restObject.setRaw(rawEntity);
295             T t = (T) new ObjectMapper().readValue(rawEntity, tClass);
296             restObject.set(t);
297         }
298         catch ( Exception e ) {
299             try {
300                 logger.debug(EELFLoggerDelegate.debugLogger, "<== " + getMethodCallerName() + " Error reading response entity as " + tClass + ": , e="
301                         + e.getMessage() + ", Entity=" + rawEntity);
302             } catch (Exception e2) {
303                 logger.debug(EELFLoggerDelegate.debugLogger, "<== " + getMethodCallerName() + NO_RESPONSE_ENTITY_LOG
304                         + e.getMessage());
305             }
306         }
307
308         int status = cres.getStatus();
309         restObject.setStatusCode (status);
310
311         return restObject;
312     }
313
314     @Override
315     public <T> void Put(T t, org.onap.vid.changeManagement.RequestDetailsWrapper r, String path, RestObject<T> restObject) {
316
317         String methodName = "Put";
318         String url="";
319
320         logger.debug(EELFLoggerDelegate.debugLogger,"<== " +  methodName + START_LOG);
321
322         try {
323
324             MultivaluedHashMap<String, Object> commonHeaders = initMsoClient();
325
326             url = systemProperties.getProperty(MsoProperties.MSO_SERVER_URL) + path;
327             loggingService.logRequest(outgoingRequestsLogger, HttpMethod.PUT, url, r);
328             // Change the content length
329             final Response cres = client.target(url)
330                     .request()
331                     .accept(APPLICATION_JSON)
332                     .headers(commonHeaders)
333                     //.header("content-length", 201)
334                     .put(Entity.entity(r, MediaType.APPLICATION_JSON));
335
336             loggingService.logResponse(outgoingRequestsLogger, HttpMethod.PUT, url, cres);
337
338             try {
339                 t = (T) cres.readEntity(t.getClass());
340                 restObject.set(t);
341             }
342             catch ( Exception e ) {
343                 logger.debug(EELFLoggerDelegate.debugLogger,"<== " + methodName + NO_RESPONSE_ENTITY_LOG
344                         + e.getMessage());
345                 throw e;
346             }
347
348             int status = cres.getStatus();
349             restObject.setStatusCode (status);
350
351             if ( status >= 200 && status <= 299 ) {
352                 logger.info(EELFLoggerDelegate.errorLogger, "<== " + methodName + REST_API_SUCCESSFULL_LOG);
353                 logger.debug(EELFLoggerDelegate.debugLogger,"<== " + methodName + REST_API_SUCCESSFULL_LOG);
354
355             } else {
356                 logger.debug(EELFLoggerDelegate.debugLogger,"<== " + methodName + WITH_STATUS +status+ URL_LOG +url);
357             }
358
359         } catch (Exception e)
360         {
361             logger.debug(EELFLoggerDelegate.debugLogger,"<== " + methodName + WITH_URL_LOG +url+ EXCEPTION_LOG + e.toString());
362             throw e;
363
364         }
365     }
366 }