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