Fix 404 in sdc-FE calls to workflow
[sdc.git] / catalog-fe / src / main / java / org / openecomp / sdc / fe / servlets / FeProxyServlet.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 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.openecomp.sdc.fe.servlets;
22
23 import com.google.common.annotations.VisibleForTesting;
24 import org.apache.commons.lang3.NotImplementedException;
25 import org.apache.commons.lang3.StringUtils;
26 import org.eclipse.jetty.client.api.Response;
27 import org.openecomp.sdc.common.api.Constants;
28 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
29 import org.openecomp.sdc.common.log.wrappers.Logger;
30 import org.openecomp.sdc.fe.config.Configuration;
31 import org.openecomp.sdc.fe.config.Configuration.CatalogFacadeMsConfig;
32 import org.openecomp.sdc.fe.config.ConfigurationManager;
33 import org.openecomp.sdc.fe.config.FeEcompErrorManager;
34 import org.openecomp.sdc.fe.config.PluginsConfiguration;
35 import org.openecomp.sdc.fe.config.PluginsConfiguration.Plugin;
36 import org.openecomp.sdc.fe.impl.LogHandler;
37 import org.openecomp.sdc.fe.utils.BeProtocol;
38
39 import javax.servlet.http.HttpServletRequest;
40 import javax.servlet.http.HttpServletResponse;
41 import java.net.MalformedURLException;
42 import java.net.URL;
43
44 import static org.apache.commons.lang3.StringUtils.isEmpty;
45
46
47 public class FeProxyServlet extends SSLProxyServlet {
48         private static final long serialVersionUID = 1L;
49         private static final String URL = "%s://%s%s%s";
50         private static final String MS_URL = "%s://%s:%s";
51         private static final String ONBOARDING_CONTEXT = "/onboarding-api";
52         private static final String DCAED_CONTEXT = "/dcae-api";
53         private static final String WORKFLOW_CONTEXT = "/wf";
54         private static final String SDC1_FE_PROXY = "/sdc1/feProxy";
55         private static final String PLUGIN_ID_WORKFLOW = "WORKFLOW";
56         public static final String UUID = "uuid";
57         public static final String TRANSACTION_START_TIME = "transactionStartTime";
58         private static Logger log = Logger.getLogger(FeProxyServlet.class.getName());
59
60         private static String msUrl;
61         private static final String FACADE_PATH_IDENTIFIER = "uicache";
62         private static final String CATALOG_REQUEST_IDENTIFIER = "/v1/catalog";
63         private static final String ARCHIVE_PATH_IDENTIFIER = String.format("%s/archive/", CATALOG_REQUEST_IDENTIFIER);
64         private static final String HOME_REQUEST_IDENTIFIER = "/v1/followed";
65         @Override
66         protected String rewriteTarget(HttpServletRequest request) {
67                 String originalUrl="";
68                 String redirectedUrl = "";
69
70                 try {
71                         logFeRequest(request);
72                         originalUrl = request.getRequestURL().toString();
73
74                         Configuration config = getConfiguration(request);
75                         if (config == null) {
76                                 log.error("failed to retrieve configuration.");
77                         }
78                         if (isMsRequest(request.getRequestURL().toString())) {
79                                 redirectedUrl = redirectMsRequestToMservice(request, config);
80                         } else {
81                                 redirectedUrl = getModifiedUrl(config, getPluginConfiguration(request), request.getRequestURI(), getQueryString(request));
82                         }
83                 }
84                 catch (MalformedURLException mue) {
85                         FeEcompErrorManager.getInstance().logFeHttpLoggingError("FE Request");
86                         log.error(EcompLoggerErrorCode.DATA_ERROR, "FeProxyServlet rewriteTarget", "sdc-FE", "Malformed URL Exception: ", mue);
87                 }
88                 catch (Exception e) {
89             log.error(EcompLoggerErrorCode.UNKNOWN_ERROR,"FeProxyServlet rewriteTarget", "sdc-FE", "Unexpected FE request processing error: ", e);
90                 }
91                 if (log.isDebugEnabled()) {
92                         log.debug("FeProxyServlet Redirecting request from: {} , to: {}", originalUrl, redirectedUrl);
93                 }
94
95                 return redirectedUrl;
96         }
97
98         @Override
99         protected void onProxyResponseSuccess(HttpServletRequest request, HttpServletResponse proxyResponse, Response response) {
100                 try {
101                         logFeResponse(request, response);
102                 } catch (Exception e) {
103                         FeEcompErrorManager.getInstance().logFeHttpLoggingError("FE Response");
104             log.error(EcompLoggerErrorCode.UNKNOWN_ERROR,"FeProxyServlet onProxyResponseSuccess", "sdc-FE", "Unexpected FE response logging error: ", e);
105                 }
106                 super.onProxyResponseSuccess(request, proxyResponse, response);
107         }
108
109         private void logFeRequest(HttpServletRequest httpRequest){
110                 LogHandler.logFeRequest(httpRequest);
111                 inHttpRequest(httpRequest);
112         }
113
114         private void logFeResponse(HttpServletRequest request, Response proxyResponse){
115                 LogHandler.logFeResponse(request);
116                 outHttpResponse(proxyResponse);
117         }
118
119         // Extracted for purpose of clear method name, for logback %M parameter
120         private void inHttpRequest(HttpServletRequest httpRequest) {
121                 log.info("{} {} {}", httpRequest.getMethod(), httpRequest.getRequestURI(), httpRequest.getProtocol());
122         }
123
124         // Extracted for purpose of clear method name, for logback %M parameter
125         private void outHttpResponse(Response proxyResponse) {
126                 log.info("SC=\"{}\"", proxyResponse.getStatus());
127         }
128
129         private String getModifiedUrl(Configuration config, PluginsConfiguration pluginConf, String uri, String queryString) throws MalformedURLException{
130                 if (config == null) {
131             log.error(EcompLoggerErrorCode.UNKNOWN_ERROR,"FeProxyServlet getModifiedUrl", "sdc-FE", "failed to retrieve configuration.");
132                         throw new RuntimeException("failed to read FE configuration");
133                 }
134                 String protocol;
135                 String host;
136                 String port;
137                 String path = "";
138                 if (uri.contains(ONBOARDING_CONTEXT)){
139                         uri = uri.replace(SDC1_FE_PROXY+ONBOARDING_CONTEXT,ONBOARDING_CONTEXT);
140                         protocol = config.getOnboarding().getProtocolBe();
141                         host = config.getOnboarding().getHostBe();
142                         port = config.getOnboarding().getPortBe().toString();           
143                 }else if(uri.contains(DCAED_CONTEXT)){
144                         uri = uri.replace(SDC1_FE_PROXY+DCAED_CONTEXT,DCAED_CONTEXT);
145                         protocol = config.getBeProtocol();
146                         host = config.getBeHost();
147                         if (config.getBeProtocol().equals(BeProtocol.HTTP.getProtocolName())) {
148                                 port = config.getBeHttpPort().toString();
149                         } else {
150                                 port = config.getBeSslPort().toString();
151                         }
152                 }
153                 else if (uri.contains(WORKFLOW_CONTEXT)){
154                         uri = uri.replace(SDC1_FE_PROXY +WORKFLOW_CONTEXT,WORKFLOW_CONTEXT);
155                         String workflowPluginURL = pluginConf.getPluginsList()
156                                         .stream()
157                                         .filter(plugin -> plugin.getPluginId().equalsIgnoreCase(PLUGIN_ID_WORKFLOW))
158                                         .map(Plugin::getPluginDiscoveryUrl)
159                                         .findFirst().orElse(null);
160
161                         java.net.URL workflowURL = new URL(workflowPluginURL);
162                         protocol = workflowURL.getProtocol();
163                         host = workflowURL.getHost();
164                         path = workflowURL.getPath();
165                         port = String.valueOf(workflowURL.getPort());
166                 }
167                 else{
168                         uri = uri.replace(SDC1_FE_PROXY,"/sdc2");
169                         protocol = config.getBeProtocol();
170                         host = config.getBeHost();
171                         if (config.getBeProtocol().equals(BeProtocol.HTTP.getProtocolName())) {
172                                 port = config.getBeHttpPort().toString();
173                         } else {
174                                 port = config.getBeSslPort().toString();
175                         }
176                 }       
177
178                 final String authority = getAuthority(host, port);
179                 String modifiedUrl = String.format(URL, protocol, authority, path, uri);
180                 if (StringUtils.isNotEmpty(queryString)) {
181                         modifiedUrl += "?" + queryString;
182                 }
183                  
184                 return modifiedUrl;
185         }
186
187         @VisibleForTesting
188         String redirectMsRequestToMservice(HttpServletRequest request, Configuration config) throws MalformedURLException {
189
190                 boolean isMsToggledOn = isMsToggleOn(config);
191                 String redirectValue;
192                 if (isMsToggledOn) {
193                         redirectValue = handleMsToggleOnRedirect(request, config);
194                 } else {
195                         redirectValue = handleMsToggleOffRedirect(request, config);
196                 }
197                 return redirectValue;
198         }
199 private PluginsConfiguration getPluginConfiguration(HttpServletRequest request) {
200                 return ((ConfigurationManager) request.getSession().getServletContext().getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)).getPluginsConfiguration();
201   }
202         private boolean isMsToggleOn(Configuration config) {
203                 boolean toggleOn = true;
204                 final CatalogFacadeMsConfig catalogFacadeMs = config.getCatalogFacadeMs();
205                 if (catalogFacadeMs == null) {
206                         toggleOn = false;
207                         ;
208                 } else if (isEmpty(catalogFacadeMs.getHealthCheckUri())) {
209                         toggleOn = false;
210                 } else if (isEmpty(catalogFacadeMs.getHost())) {
211                         toggleOn = false;
212                 } else if (isEmpty(catalogFacadeMs.getPath())) {
213                         toggleOn = false;
214                 } else if (isEmpty(catalogFacadeMs.getProtocol())) {
215                         toggleOn = false;
216                 } else if (catalogFacadeMs.getPort() == null) {
217                         toggleOn = false;
218                 }
219                 return toggleOn;
220         }
221         private String handleMsToggleOffRedirect(HttpServletRequest request, Configuration config) throws MalformedURLException {
222                 String redirectValue;
223                 String currentURI = request.getRequestURI();
224                 if (isEmpty(request.getQueryString())) {
225                         // Catalog
226                         if (currentURI.endsWith(CATALOG_REQUEST_IDENTIFIER)) {
227                                 String facadeSuffix = String.format("%s%s", FACADE_PATH_IDENTIFIER, CATALOG_REQUEST_IDENTIFIER);
228                                 String nonFacadeUrl = currentURI.replace(facadeSuffix, "rest/v1/screen");
229                                 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), nonFacadeUrl, "excludeTypes=VFCMT&excludeTypes=Configuration");
230                         }
231                         // Home
232                         else if (currentURI.endsWith(HOME_REQUEST_IDENTIFIER)){
233                                 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), currentURI, getQueryString(request));
234                         }
235                         // Archive
236                         else if (currentURI.endsWith(ARCHIVE_PATH_IDENTIFIER)) {
237                                 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), currentURI, getQueryString(request));
238                         } else {
239                                 String message = String.format("facade is toggled off, Could not rediret url %s", currentURI);
240                                 log.error(message);
241                                 throw new NotImplementedException(message);
242                         }
243                 } else {
244                         // Left Pallet
245                         if (currentURI.contains("/latestversion/notabstract/metadata")) {
246                                 String nonFacadeUrl = currentURI.replace(FACADE_PATH_IDENTIFIER, "rest");
247                                 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), nonFacadeUrl, getQueryString(request));
248                         }
249                         // Catalog with Query Params
250                         else if (currentURI.endsWith(CATALOG_REQUEST_IDENTIFIER)) {
251                                 String facadeSuffix = String.format("%s%s", FACADE_PATH_IDENTIFIER, CATALOG_REQUEST_IDENTIFIER);
252                                 String nonFacadeUrl = currentURI.replace(facadeSuffix, "rest/v1/screen");
253                                 redirectValue = getModifiedUrl(config, getPluginConfiguration(request), nonFacadeUrl, "excludeTypes=VFCMT&excludeTypes=Configuration");
254                         } else {
255                                 String message = String.format("facade is toggled off, Could not rediret url %s with query params %s",
256                                                 currentURI, getQueryString(request));
257                                 log.error(message);
258                                 throw new NotImplementedException(message);
259                         }
260                 }
261
262                 return redirectValue;
263         }
264
265   private String handleMsToggleOnRedirect(HttpServletRequest request, Configuration config) {
266                 String currentUrl = request.getRequestURL()
267                                 .toString();
268                 if (StringUtils.isEmpty(msUrl)) {
269                         // do that only once
270                         msUrl = String.format(MS_URL, config.getCatalogFacadeMs()
271                                         .getProtocol(),
272                                         config.getCatalogFacadeMs().getHost(),
273                                         config.getCatalogFacadeMs().getPort());
274                 }
275                 StringBuilder url;
276                 String queryString;
277                 String msPath = config.getCatalogFacadeMs().getPath();
278                 if (currentUrl.endsWith(ARCHIVE_PATH_IDENTIFIER)) {
279                         url = new StringBuilder(msUrl + msPath + CATALOG_REQUEST_IDENTIFIER);
280                         queryString = "arc=true";
281                 } else {
282                         url = new StringBuilder(msUrl + currentUrl.substring(currentUrl.indexOf(msPath)));
283                         queryString = request.getQueryString();
284                 }
285                 if (queryString != null) {
286                         url.append("?").append(queryString);
287                 }
288                 if (log.isDebugEnabled()) {
289                         log.debug("Redirect catalog request to {}", url.toString());
290                 }
291                 return url.toString();
292         }
293
294         @VisibleForTesting
295         boolean isMsRequest(String currentUrl) {
296                 return currentUrl.contains(FACADE_PATH_IDENTIFIER) || currentUrl.endsWith(ARCHIVE_PATH_IDENTIFIER);
297         }
298         private Configuration getConfiguration(HttpServletRequest request) {
299                 return ((ConfigurationManager) request.getSession().getServletContext().getAttribute(Constants.CONFIGURATION_MANAGER_ATTR)).getConfiguration();
300         }
301
302         private String getAuthority(String host, String port) {
303                 String authority;
304                 if (port == null) {
305                         authority = host;
306                 } else {
307                         authority = host + ":" + port;
308                 }
309                 return authority;
310         }
311         
312         private String getQueryString(HttpServletRequest request){
313                 final String queryString = request.getQueryString();
314                 return StringUtils.isEmpty(queryString) ? StringUtils.EMPTY : queryString;
315         }
316
317 }