Update license; improve coverage; add docs dir
[portal.git] / ecomp-portal-BE-os / src / main / java / org / openecomp / portalapp / portal / service / ApplicationsRestClientServiceImpl.java
1 /*-
2  * ============LICENSE_START==========================================
3  * ONAP Portal
4  * ===================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * ===================================================================
7  *
8  * Unless otherwise specified, all software contained herein is licensed
9  * under the Apache License, Version 2.0 (the “License”);
10  * you may not use this software 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  *
21  * Unless otherwise specified, all documentation contained herein is licensed
22  * under the Creative Commons License, Attribution 4.0 Intl. (the “License”);
23  * you may not use this documentation except in compliance with the License.
24  * You may obtain a copy of the License at
25  *
26  *             https://creativecommons.org/licenses/by/4.0/
27  *
28  * Unless required by applicable law or agreed to in writing, documentation
29  * distributed under the License is distributed on an "AS IS" BASIS,
30  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31  * See the License for the specific language governing permissions and
32  * limitations under the License.
33  *
34  * ============LICENSE_END============================================
35  *
36  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
37  */
38 package org.openecomp.portalapp.portal.service;
39
40 import static com.att.eelf.configuration.Configuration.MDC_KEY_REQUEST_ID;
41
42 import java.lang.reflect.Type;
43 import java.net.MalformedURLException;
44 import java.net.URL;
45 import java.util.Date;
46
47 import javax.annotation.PostConstruct;
48 import javax.servlet.http.HttpServletResponse;
49 import javax.ws.rs.core.MediaType;
50 import javax.ws.rs.core.Response;
51
52 import org.apache.cxf.jaxrs.client.WebClient;
53 import org.apache.cxf.transport.http.HTTPException;
54 import org.openecomp.portalapp.portal.domain.EPApp;
55 import org.openecomp.portalapp.portal.logging.aop.EPAuditLog;
56 import org.openecomp.portalapp.portal.logging.aop.EPMetricsLog;
57 import org.openecomp.portalapp.portal.logging.format.EPAppMessagesEnum;
58 import org.openecomp.portalapp.portal.logging.logic.EPLogUtil;
59 import org.openecomp.portalapp.portal.utils.EPSystemProperties;
60 import org.openecomp.portalapp.portal.utils.EcompPortalUtils;
61 import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate;
62 import org.openecomp.portalsdk.core.onboarding.util.CipherUtil;
63 import org.openecomp.portalsdk.core.util.SystemProperties;
64 import org.slf4j.MDC;
65 import org.springframework.beans.factory.annotation.Autowired;
66 import org.springframework.context.annotation.EnableAspectJAutoProxy;
67 import org.springframework.stereotype.Service;
68
69 import com.fasterxml.jackson.databind.ObjectMapper;
70 import com.google.gson.Gson;
71 import com.google.gson.GsonBuilder;
72 import com.google.gson.JsonDeserializationContext;
73 import com.google.gson.JsonDeserializer;
74 import com.google.gson.JsonElement;
75 import com.google.gson.JsonParseException;
76
77 @Service("applicationsRestClientService")
78 @org.springframework.context.annotation.Configuration
79 @EnableAspectJAutoProxy
80 @EPAuditLog
81 public class ApplicationsRestClientServiceImpl implements ApplicationsRestClientService {
82
83         private static final String PASSWORD_HEADER = "password";
84
85         private static final String APP_USERNAME_HEADER = "username";
86
87         private static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ApplicationsRestClientServiceImpl.class);
88
89         @Autowired
90         private AppsCacheService appsCacheService;
91         Gson gson = null;
92
93         private final ObjectMapper mapper = new ObjectMapper();
94
95         @PostConstruct
96         private void init() {
97                 logger.debug(EELFLoggerDelegate.debugLogger, "initializing");
98                 GsonBuilder builder = new GsonBuilder();
99
100                 // Register an adapter to manage the date types as long values
101                 builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
102                         public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
103                                         throws JsonParseException {
104                                 return new Date(json.getAsJsonPrimitive().getAsLong());
105                         }
106                 });
107
108                 gson = builder.create();
109         }
110
111         // TODO: do we need to do additional logging for remote API calls?
112         private static WebClient createClientForPath(String baseUri, String path) {
113                 logger.info(EELFLoggerDelegate.debugLogger, "Creating web client for " + baseUri + "   +   " + path);
114                 WebClient client = WebClient.create(baseUri);
115                 client.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON);
116                 client.path(path);
117                 return client;
118         }
119
120         @EPMetricsLog
121         private void verifyResponse(Response response) throws HTTPException {
122                 int status = response.getStatus();
123                 logger.debug(EELFLoggerDelegate.debugLogger, "http response status=" + status);
124                 MDC.put(EPSystemProperties.EXTERNAL_API_RESPONSE_CODE, Integer.toString(status));
125                 if (!isHttpSuccess(status)) {
126                         String errMsg = "Failed. Status=" + status + "; [" + response.getStatusInfo().getReasonPhrase().toString()
127                                         + "]";
128                         URL url = null;
129                         try {
130                                 // must not be null to avoid NPE in HTTPException constructor
131                                 url = new URL("http://null");
132                                 if (response.getLocation() != null)
133                                         url = response.getLocation().toURL();
134                         } catch (MalformedURLException e) {
135                                 // never mind. it is only for the debug message.
136                                 logger.warn(EELFLoggerDelegate.errorLogger, "Failed to build URL", e);
137                         }
138                         logger.error(EELFLoggerDelegate.errorLogger, "http response failed. " + errMsg + "; url=" + url);
139                         EPLogUtil.logEcompError(EPAppMessagesEnum.BeIncorrectHttpStatusError);
140                         throw new HTTPException(status, errMsg, url);
141                 }
142         }
143
144         private static boolean isHttpSuccess(int status) {
145                 return status / 100 == 2;
146         }
147
148         @EPMetricsLog
149         private WebClient createClientForApp(long appId, String restPath) {
150                 logger.debug(EELFLoggerDelegate.debugLogger, "creating client for appId=" + appId + "; restPath=" + restPath);
151                 EPApp externalApp = appsCacheService.getApp(appId);
152                 if (externalApp != null) {
153                         String appBaseUri = externalApp.getAppRestEndpoint();
154                         String username = externalApp.getUsername();
155                         String encriptedPwd = externalApp.getAppPassword();
156                         String decreptedAppPwd = "";
157
158                         // Set local context
159                         MDC.put(EPSystemProperties.PROTOCOL, EPSystemProperties.HTTP);
160                         if (appBaseUri != null && appBaseUri.contains("https")) {
161                                 MDC.put(EPSystemProperties.PROTOCOL, EPSystemProperties.HTTPS);
162                         }
163                         MDC.put(EPSystemProperties.FULL_URL, appBaseUri + restPath);
164                         MDC.put(EPSystemProperties.TARGET_ENTITY, externalApp.getName());
165                         MDC.put(EPSystemProperties.TARGET_SERVICE_NAME, restPath);
166
167                         try {
168                                 decreptedAppPwd = CipherUtil.decrypt(encriptedPwd,
169                                                 SystemProperties.getProperty(SystemProperties.Decryption_Key));
170                         } catch (Exception e) {
171                                 logger.error(EELFLoggerDelegate.errorLogger, "createClientForApp failed to decrypt", e);
172                         }
173                         logger.debug(EELFLoggerDelegate.debugLogger,
174                                         String.format("App %d found, baseUri=[%s], Headers: [%s=%s, %s=%s]", appId, appBaseUri,
175                                                         APP_USERNAME_HEADER, username, PASSWORD_HEADER, encriptedPwd));
176                         WebClient client = createClientForPath(appBaseUri, restPath);
177                         client.header(APP_USERNAME_HEADER, username);
178                         client.header(PASSWORD_HEADER, decreptedAppPwd);
179                         client.header(SystemProperties.ECOMP_REQUEST_ID, MDC.get(MDC_KEY_REQUEST_ID));
180                         client.header(SystemProperties.USERAGENT_NAME, EPSystemProperties.ECOMP_PORTAL_BE);
181
182                         return client;
183                 }
184                 return null;
185         }
186
187         @Override
188         public <T> T get(Class<T> clazz, long appId, String restPath) throws HTTPException {
189
190                 WebClient webClient = null;
191                 Response response = null;
192                 T t = null;
193
194                 webClient = createClientForApp(appId, restPath);
195                 EcompPortalUtils.logAndSerializeObject(restPath, "GET request =", "no-payload");
196
197                 try {
198                         if (webClient != null) {
199                                 response = webClient.get();
200                         } else {
201                                 logger.error(EELFLoggerDelegate.errorLogger,
202                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
203                         }
204                 } catch (Exception e) {
205                         MDC.put(EPSystemProperties.EXTERNAL_API_RESPONSE_CODE,
206                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
207                         EPLogUtil.logEcompError(EPAppMessagesEnum.BeRestApiGeneralError);
208                         logger.error(EELFLoggerDelegate.errorLogger, "get 1 failed", e);
209                 }
210
211                 if (response != null) {
212                         verifyResponse(response);
213                         String str = response.readEntity(String.class);
214                         EcompPortalUtils.logAndSerializeObject(restPath, "GET result =", str);
215                         try {
216                                 t = mapper.readValue(str, clazz);
217                         } catch (Exception e) {
218                                 logger.error(EELFLoggerDelegate.errorLogger, "get 2 failed", e);
219                                 EPLogUtil.logEcompError(EPAppMessagesEnum.BeInvalidJsonInput);
220                         }
221                 }
222
223                 return t;
224         }
225
226         @Override
227         public <T> T post(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
228                 WebClient client = null;
229                 Response response = null;
230                 T t = null;
231
232                 client = createClientForApp(appId, restPath);
233                 EcompPortalUtils.logAndSerializeObject(restPath, "POST request =", payload);
234
235                 try {
236                         if (client != null) {
237                                 response = client.post(payload);
238                         } else {
239                                 logger.error(EELFLoggerDelegate.errorLogger,
240                                                 "Unable to create the Webclient to make the {} API call", restPath);
241                         }
242                 } catch (Exception e) {
243                         MDC.put(EPSystemProperties.EXTERNAL_API_RESPONSE_CODE,
244                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
245                         EPLogUtil.logEcompError(EPAppMessagesEnum.BeRestApiGeneralError);
246                         logger.error(EELFLoggerDelegate.errorLogger, "post 1 failed", e);
247                 }
248
249                 if (response != null) {
250                         verifyResponse(response);
251
252                         // String contentType = response.getHeaderString("Content-Type");
253                         if (clazz != null) {
254                                 String str = response.readEntity(String.class);
255                                 EcompPortalUtils.logAndSerializeObject(restPath, "POST result =", str);
256                                 try {
257                                         t = gson.fromJson(str, clazz);
258                                 } catch (Exception e) {
259                                         logger.error(EELFLoggerDelegate.errorLogger, "post 2 failed", e);
260                                         EPLogUtil.logEcompError(EPAppMessagesEnum.BeInvalidJsonInput);
261                                 }
262                         }
263                 }
264                 return t;
265         }
266
267         @Override
268         public <T> T put(Class<T> clazz, long appId, Object payload, String restPath) throws HTTPException {
269                 WebClient client = null;
270                 Response response = null;
271                 T t = null;
272
273                 client = createClientForApp(appId, restPath);
274                 EcompPortalUtils.logAndSerializeObject(restPath, "PUT request =", payload);
275
276                 try {
277                         if (client != null) {
278                                 response = client.put(payload);
279                         } else {
280                                 logger.error(EELFLoggerDelegate.errorLogger,
281                                                 "Unable to create the Webclient to make the '" + restPath + "' API call.");
282                         }
283                 } catch (Exception e) {
284                         MDC.put(EPSystemProperties.EXTERNAL_API_RESPONSE_CODE,
285                                         Integer.toString(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
286                         EPLogUtil.logEcompError(EPAppMessagesEnum.BeRestApiGeneralError);
287                         logger.error(EELFLoggerDelegate.errorLogger, "put 1 failed", e);
288                 }
289
290                 if (response != null) {
291                         verifyResponse(response);
292                         String str = response.readEntity(String.class);
293                         EcompPortalUtils.logAndSerializeObject(restPath, "PUT result =", str);
294                         try {
295                                 t = gson.fromJson(str, clazz);
296                         } catch (Exception e) {
297                                 logger.error(EELFLoggerDelegate.errorLogger, "put 2 failed", e);
298                                 EPLogUtil.logEcompError(EPAppMessagesEnum.BeInvalidJsonInput);
299                         }
300                 }
301                 return t;
302         }
303 }