027d972c26b6ff0f3c9a167ae006eb8668e63381
[portal.git] / ecomp-portal-BE-common / src / main / java / org / openecomp / portalapp / portal / service / ApplicationsRestClientServiceImpl.java
1 /*-
2  * ================================================================================
3  * ECOMP Portal SDK
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property
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  * ================================================================================
19  */
20 package org.openecomp.portalapp.portal.service;
21
22 import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
23
24 import java.lang.reflect.Type;
25 import java.net.MalformedURLException;
26 import java.net.URL;
27 import java.util.Base64;
28 import java.util.Date;
29
30 import javax.annotation.PostConstruct;
31 import javax.servlet.http.HttpServletResponse;
32 import javax.ws.rs.core.MediaType;
33 import javax.ws.rs.core.Response;
34
35 import org.apache.cxf.jaxrs.client.WebClient;
36 import org.apache.cxf.transport.http.HTTPException;
37 import org.openecomp.portalapp.portal.domain.EPApp;
38 import org.openecomp.portalapp.portal.logging.aop.EPAuditLog;
39 import org.openecomp.portalapp.portal.logging.aop.EPMetricsLog;
40 import org.openecomp.portalapp.portal.logging.format.EPAppMessagesEnum;
41 import org.openecomp.portalapp.portal.logging.logic.EPLogUtil;
42 import org.openecomp.portalapp.portal.utils.EPCommonSystemProperties;
43 import org.openecomp.portalapp.portal.utils.EcompPortalUtils;
44 import org.openecomp.portalapp.util.SystemType;
45 import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate;
46 import org.openecomp.portalsdk.core.onboarding.util.CipherUtil;
47 import org.openecomp.portalsdk.core.util.SystemProperties;
48 import org.slf4j.MDC;
49 import org.springframework.beans.factory.annotation.Autowired;
50 import org.springframework.context.annotation.EnableAspectJAutoProxy;
51 import org.springframework.stereotype.Service;
52
53 import com.fasterxml.jackson.databind.ObjectMapper;
54 import com.google.gson.Gson;
55 import com.google.gson.GsonBuilder;
56 import com.google.gson.JsonDeserializationContext;
57 import com.google.gson.JsonDeserializer;
58 import com.google.gson.JsonElement;
59 import com.google.gson.JsonParseException;
60
61 @Service("applicationsRestClientService")
62 @org.springframework.context.annotation.Configuration
63 @EnableAspectJAutoProxy
64 @EPAuditLog
65 public class ApplicationsRestClientServiceImpl implements ApplicationsRestClientService {
66
67         private static final String PASSWORD_HEADER = "password";
68
69         private static final String APP_USERNAME_HEADER = "username";
70
71         private static final String BASIC_AUTHENTICATION_HEADER = "Authorization";
72
73         private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ApplicationsRestClientServiceImpl.class);
74
75         @Autowired
76         private AppsCacheService appsCacheService;
77
78         Gson gson = null;
79
80         private final ObjectMapper mapper = new ObjectMapper();
81
82         @PostConstruct
83         private void init() {
84                 logger.debug(EELFLoggerDelegate.debugLogger, "initializing");
85                 GsonBuilder builder = new GsonBuilder();
86
87                 // Register an adapter to manage the date types as long values
88                 builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
89                         public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
90                                         throws JsonParseException {
91                                 return new Date(json.getAsJsonPrimitive().getAsLong());
92                         }
93                 });
94
95                 gson = builder.create();
96         }
97
98         // TODO: do we need to do additional logging for remote API calls?
99         private static WebClient createClientForPath(String baseUri, String path) {
100                 logger.info(EELFLoggerDelegate.debugLogger, "Creating web client for " + baseUri + "   +   " + path);
101                 WebClient client = WebClient.create(baseUri);
102                 client.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
103                 client.path(path);
104                 return client;
105         }
106
107         @EPMetricsLog
108         private void verifyResponse(Response response) throws HTTPException {
109                 int status = response.getStatus();
110                 logger.debug(EELFLoggerDelegate.debugLogger, "http response status=" + status);
111                 MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE, Integer.toString(status));
112                 if (!isHttpSuccess(status)) {
113                         String errMsg = "Failed. Status=" + status + "; [" + response.getStatusInfo().getReasonPhrase().toString()
114                                         + "]";
115                         URL url = null;
116                         try {
117                                 // must not be null to avoid NPE in HTTPException constructor
118                                 url = new URL("http://null");
119                                 if (response.getLocation() != null)
120                                         url = response.getLocation().toURL();
121                         } catch (MalformedURLException e) {
122                                 // never mind. it is only for the debug message.
123                                 logger.warn(EELFLoggerDelegate.errorLogger, "Failed to build URL", e);
124                         }
125                         logger.error(EELFLoggerDelegate.errorLogger, "http response failed. " + errMsg + "; url=" + url);
126                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeIncorrectHttpStatusError);
127                         throw new HTTPException(status, errMsg, url);
128                 }
129         }
130
131         private static boolean isHttpSuccess(int status) {
132                 return status / 100 == 2;
133         }
134         
135         
136         private WebClient createClientForApp(long appId, String restPath) {
137                 return createClientFor(appId, restPath, SystemType.APPLICATION);
138         }
139
140         //TODO Need to implement the mylogins once the endpoint is confirmed
141         @EPMetricsLog
142         private WebClient createClientFor(long appSystemId, String restPath, SystemType type) {
143                 logger.debug(EELFLoggerDelegate.debugLogger, "creating client for appId=" + appSystemId + "; restPath=" + restPath);
144                 EPApp externalApp = null;
145                 
146                 if(type == SystemType.APPLICATION){
147                 externalApp = appsCacheService.getApp(appSystemId);
148                 }else{
149                         // TO DO 
150                 }
151                 
152                 if (externalApp != null) {
153                         String appBaseUri = (type == SystemType.APPLICATION) ? externalApp.getAppRestEndpoint() : "";
154                         String username = (type == SystemType.APPLICATION) ? externalApp.getUsername(): "";
155                         String encriptedPwd = (type == SystemType.APPLICATION) ? externalApp.getAppPassword(): "";
156                         String appName = (type == SystemType.APPLICATION) ? externalApp.getName(): "";
157                         String decreptedAppPwd = "";
158
159                         // Set local context
160                         MDC.put(EPCommonSystemProperties.PROTOCOL, EPCommonSystemProperties.HTTP);
161                         if (appBaseUri != null && appBaseUri.contains("https")) {
162                                 MDC.put(EPCommonSystemProperties.PROTOCOL, EPCommonSystemProperties.HTTPS);
163                         }
164                         MDC.put(EPCommonSystemProperties.FULL_URL, appBaseUri + restPath);
165                         MDC.put(EPCommonSystemProperties.TARGET_ENTITY, appName);
166                         MDC.put(EPCommonSystemProperties.TARGET_SERVICE_NAME, restPath);
167
168                         try {
169                                 decreptedAppPwd = CipherUtil.decrypt(encriptedPwd,
170                                                 SystemProperties.getProperty(SystemProperties.Decryption_Key));
171                         } catch (Exception e) {
172                                 logger.error(EELFLoggerDelegate.errorLogger, "Unable to decrypt App name = " + externalApp,
173                                                 EcompPortalUtils.getStackTrace(e));
174                                 logger.error(EELFLoggerDelegate.errorLogger, "Unable to decrypt App name = " + externalApp,
175                                                 EcompPortalUtils.getStackTrace(e));
176                         }
177                         
178                         WebClient client = createClientForPath(appBaseUri, restPath);
179
180                         // support basic authentication for some partners
181                         String encoding = Base64.getEncoder().encodeToString((username + ":" + decreptedAppPwd).getBytes());
182                         String encodingStr = "Basic " + encoding;
183                         client.header(BASIC_AUTHENTICATION_HEADER, encodingStr);
184
185                         // But still keep code downward compatible for non compliant apps
186                         client.header(APP_USERNAME_HEADER, username);
187                         client.header(PASSWORD_HEADER, decreptedAppPwd);
188
189                         client.header(SystemProperties.ECOMP_REQUEST_ID, MDC.get(MDC_KEY_REQUEST_ID));
190                         client.header(SystemProperties.USERAGENT_NAME, EPCommonSystemProperties.ECOMP_PORTAL_BE);
191                         
192                         logger.debug(EELFLoggerDelegate.debugLogger,
193                                         String.format("App %d found, baseUri=[%s], Headers: [%s=%s, %s=%s, %s=%s]", appSystemId, appBaseUri,
194                                                         APP_USERNAME_HEADER, username, PASSWORD_HEADER, encriptedPwd, BASIC_AUTHENTICATION_HEADER, encodingStr));
195
196                         return client;
197                 }
198                 return null;
199         }
200
201         @Override
202         public <T> T get(Class<T> clazz, long appId, String restPath) throws HTTPException {
203                 T t = null;
204                 Response response = getResponse(appId, restPath);
205
206                 if (response != null) {
207                         verifyResponse(response);
208                         String str = response.readEntity(String.class);
209                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET result =", str);
210                         try {
211                                 t = gson.fromJson(str, clazz);
212                         } catch (Exception e) {
213                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
214                         }
215                 }
216
217                 return t;
218         }
219         
220         @Override
221         public String getIncomingJsonString(long appId, String restPath) throws HTTPException {
222                 Response response = getResponse(appId, restPath);
223
224                 if (response != null) {
225                         verifyResponse(response);
226                         String incomingJson = response.readEntity(String.class);
227                         return incomingJson;
228                 }
229                 
230                 return "";
231         }
232
233
234         /*
235          * (non-Javadoc)
236          * 
237          * @see
238          * org.openecomp.portalapp.portal.service.ApplicationsRestClientService#get(
239          * java.lang.Class, long, java.lang.String, boolean)
240          */
241         @Override
242         public <T> T get(Class<T> clazz, long appId, String restPath, boolean useJacksonMapper) throws HTTPException {
243
244                 if (!useJacksonMapper)
245                         return get(clazz, appId, restPath);
246
247                 T t = null;
248                 Response response = getResponse(appId, restPath);
249
250                 if (response != null) {
251                         verifyResponse(response);
252                         String str = response.readEntity(String.class);
253                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET result =", str);
254
255                         try {
256                                 t = mapper.readValue(str, clazz);
257                         } catch (Exception e) {
258                                 e.printStackTrace();
259                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
260                         }
261                 }
262
263                 return t;
264         }
265
266         protected Response getResponse(long appId, String restPath) {
267                 WebClient webClient = null;
268                 Response response = null;
269
270                 webClient = createClientForApp(appId, restPath);
271                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "GET request =", "no-payload");
272
273                 try {
274                         if (webClient != null) {
275                                 response = webClient.get();
276                         } else {
277                                 logger.error(EELFLoggerDelegate.errorLogger,
278                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
279                         }
280                 } catch (Exception e) {
281                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
282                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
283                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
284                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the GET REST API call", e);
285                 }
286                 return response;
287         }
288         
289         
290         @Override
291         public <T> T post(Class<T> clazz, long appId, Object payload, String restPath, SystemType type) throws HTTPException {
292                 WebClient client = null;
293                 Response response = null;
294                 T t = null;
295
296                 client = createClientFor(appId, restPath, type);
297                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST request =", payload);
298
299                 try {
300                         if (client != null) {
301                                 response = client.post(payload);
302                         } else {
303                                 logger.error(EELFLoggerDelegate.errorLogger,
304                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
305                         }
306                 } catch (Exception e) {
307                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
308                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
309                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
310                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the POST REST API call", e);
311                 }
312
313                 if (response != null) {
314                         verifyResponse(response);
315
316                         // String contentType = response.getHeaderString("Content-Type");
317                         if (clazz != null) {
318                                 String str = response.readEntity(String.class);
319                                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST result =", str);
320                                 try {
321                                         t = gson.fromJson(str, clazz);
322                                 } catch (Exception e) {
323                                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
324                                 }
325                         }
326                 }
327                 return t;
328         }
329
330         @Override
331         public <T> T post(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
332                 return post( clazz, appId, payload, restPath, SystemType.APPLICATION);
333         }
334
335         //@Override
336         public <T> T postForClass(Class<T> clazz, long appId, Object payload, String restPath, Class<T> forClass) throws HTTPException {
337                 WebClient client = null;
338                 Response response = null;
339                 T t = null;
340
341                 client = createClientForApp(appId, restPath);
342                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST request =", payload);
343
344                 try {
345                         if (client != null) {
346                                 response = client.post(payload);
347                         } else {
348                                 logger.error(EELFLoggerDelegate.errorLogger,
349                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
350                         }
351                 } catch (Exception e) {
352                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
353                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
354                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
355                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the POST REST API call", e);
356                 }
357
358                 if (response != null) {
359                         verifyResponse(response);
360
361                         // String contentType = response.getHeaderString("Content-Type");
362                         if (clazz != null) {
363                                 String str = response.readEntity(String.class);
364                                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "POST result =", str);
365                                 try {
366                                         t = gson.fromJson(str, clazz);
367                                 } catch (Exception e) {
368                                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
369                                 }
370                         }
371                 }
372                 return t;
373         }
374
375         
376         @Override
377         public <T> T put(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
378                 WebClient client = null;
379                 Response response = null;
380                 T t = null;
381
382                 client = createClientForApp(appId, restPath);
383                 EcompPortalUtils.logAndSerializeObject(logger, restPath, "PUT request =", payload);
384
385                 try {
386                         if (client != null) {
387                                 response = client.put(payload);
388                         } else {
389                                 logger.error(EELFLoggerDelegate.errorLogger,
390                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
391                         }
392                 } catch (Exception e) {
393                         MDC.put(EPCommonSystemProperties.EXTERNAL_API_RESPONSE_CODE,
394                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
395                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiGeneralError, e);
396                         logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while making the PUT REST API call", e);
397                 }
398
399                 if (response != null) {
400                         verifyResponse(response);
401                         String str = response.readEntity(String.class);
402                         EcompPortalUtils.logAndSerializeObject(logger, restPath, "PUT result =", str);
403                         try {
404                                 t = gson.fromJson(str, clazz);
405                         } catch (Exception e) {
406                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInvalidJsonInput, e);
407                         }
408                 }
409                 return t;
410         }
411 }