re base code
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / filters / BeServletFilter.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.be.filters;
22
23 import com.google.gson.GsonBuilder;
24 import org.openecomp.sdc.be.config.BeEcompErrorManager;
25 import org.openecomp.sdc.be.config.Configuration;
26 import org.openecomp.sdc.be.config.ConfigurationManager;
27 import org.openecomp.sdc.be.dao.api.ActionStatus;
28 import org.openecomp.sdc.be.dao.jsongraph.TitanDao;
29 import org.openecomp.sdc.be.impl.ComponentsUtils;
30 import org.openecomp.sdc.be.impl.WebAppContextWrapper;
31 import org.openecomp.sdc.common.api.Constants;
32 import org.openecomp.sdc.common.log.elements.LogFieldsMdcHandler;
33 import org.openecomp.sdc.common.log.enums.LogLevel;
34 import org.openecomp.sdc.common.log.enums.Severity;
35 import org.openecomp.sdc.common.log.wrappers.Logger;
36 import org.openecomp.sdc.common.log.wrappers.LoggerSdcAudit;
37 import org.openecomp.sdc.common.util.ThreadLocalsHolder;
38 import org.openecomp.sdc.exception.ResponseFormat;
39 import org.slf4j.MDC;
40 import org.springframework.web.context.WebApplicationContext;
41
42 import javax.annotation.Priority;
43 import javax.servlet.ServletContext;
44 import javax.servlet.http.HttpServletRequest;
45 import javax.ws.rs.container.ContainerRequestContext;
46 import javax.ws.rs.container.ContainerRequestFilter;
47 import javax.ws.rs.container.ContainerResponseContext;
48 import javax.ws.rs.container.ContainerResponseFilter;
49 import javax.ws.rs.core.Context;
50 import javax.ws.rs.core.Response;
51 import javax.ws.rs.ext.Provider;
52 import java.io.IOException;
53 import java.util.UUID;
54
55 @Provider
56 @Priority(1)
57 public class BeServletFilter implements ContainerRequestFilter, ContainerResponseFilter {
58
59     @Context
60     private HttpServletRequest sr;
61     private static final Logger log = Logger.getLogger(BeServletFilter.class);
62     private static LoggerSdcAudit audit = new LoggerSdcAudit(BeServletFilter.class);
63
64     @Override
65     public void filter(ContainerRequestContext requestContext) throws IOException {
66         try {
67
68             MDC.clear();
69
70             audit.startLog(requestContext);
71
72             // In case of 405 response code, this function is not entered, then
73             // we'll process
74             // the MDC fields and UUID during the response
75             ThreadLocalsHolder.setMdcProcessed(true);
76
77             // Timing HTTP request
78             ThreadLocalsHolder.setRequestStartTime(System.currentTimeMillis());
79
80             String uuid = processMdcFields(requestContext);
81
82             ThreadLocalsHolder.setUuid(uuid);
83
84             inHttpRequest();
85
86         } catch (Exception e) {
87             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Error during request filter");
88             log.debug("Error during request filter: {} ", e);
89         }
90     }
91
92     @Override
93     public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
94         try {
95             // Formatting the response in case of 405
96             if (responseContext.getStatus() == Response.Status.METHOD_NOT_ALLOWED.getStatusCode()) {
97                 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NOT_ALLOWED);
98                 responseContext.setEntity(new GsonBuilder().setPrettyPrinting().create().toJson(responseFormat.getRequestError()));
99             }
100
101             if (ThreadLocalsHolder.isMdcProcessed()) {
102                 // filter() was executed during request - this is the regular
103                 // flow
104                 responseContext.getHeaders().add(Constants.X_ECOMP_REQUEST_ID_HEADER, ThreadLocalsHolder.getUuid());
105                 Long startTime = ThreadLocalsHolder.getRequestStartTime();
106                 if (startTime != null) {
107                     long endTime = System.currentTimeMillis();
108                     MDC.put("timer", Long.toString(endTime - startTime));
109                 }
110             } else {
111                 // this is the 405 response code case
112                 // we have no MDC fields since filter() wasn't executed during
113                 // request
114                 String uuid = processMdcFields(requestContext);
115
116                 responseContext.getHeaders().add(Constants.X_ECOMP_REQUEST_ID_HEADER, uuid);
117                 // call to start-log method to fill mandatory fields
118                 audit.startLog(requestContext);
119             }
120
121             writeToTitan(responseContext);
122
123             //write to Audit log in case it's valuable action
124             // (e.g. ignoring healthCheck and any other unlogged urls as in yaml
125             if (isInfoLog()) {
126                 audit.log(sr.getRemoteAddr(),
127                         requestContext,
128                         responseContext.getStatusInfo(),
129                         LogLevel.INFO,
130                         Severity.OK,
131                         LogFieldsMdcHandler.getInstance()
132                                 .getAuditMessage());
133             }
134
135             outHttpResponse(responseContext);
136
137         } catch (Exception e) {
138             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Error during request filter");
139             log.debug("Error during response filter: {} ", e);
140         } finally {
141             // Cleaning up
142             MDC.clear();
143             ThreadLocalsHolder.cleanup();
144         }
145     }
146
147     private void writeToTitan(ContainerResponseContext responseContext) {
148         log.debug("Close transaction from filter");
149         TitanDao titanDao = getTitanDao();
150         if (titanDao != null) {
151             if (responseContext.getStatus() == Response.Status.OK.getStatusCode() ||
152                     responseContext.getStatus() == Response.Status.CREATED.getStatusCode()) {
153                 titanDao.commit();
154                 log.debug("Doing commit from filter");
155             } else {
156                 titanDao.rollback();
157                 log.debug("Doing rollback from filter");
158             }
159         }
160     }
161
162     private String processMdcFields(ContainerRequestContext requestContext) {
163         // UserId for logging
164         String userId = requestContext.getHeaderString(Constants.USER_ID_HEADER);
165         MDC.put("userId", userId);
166
167         String serviceInstanceID = requestContext.getHeaderString(Constants.X_ECOMP_SERVICE_ID_HEADER);
168         MDC.put("serviceInstanceID", serviceInstanceID);
169
170         MDC.put("remoteAddr", sr.getRemoteAddr());
171         MDC.put("localAddr", sr.getLocalAddr());
172
173         // UUID
174         String uuid = requestContext.getHeaderString(Constants.X_ECOMP_REQUEST_ID_HEADER);
175         if (uuid == null) {
176             // Generate the UUID
177             uuid = UUID.randomUUID().toString();
178
179             // Add to MDC for logging
180             MDC.put("uuid", uuid);
181
182             // This log message should already be with the UUID
183             uuidGeneration(uuid);
184
185         } else {
186             // According to Ella, in case this header exists, we don't have to
187             // perform any validations
188             // since it's not our responsibilty, so we log the UUID just as it
189             // was received.
190             MDC.put("uuid", uuid);
191         }
192         return uuid;
193     }
194
195     private ComponentsUtils getComponentsUtils() {
196         ServletContext context = this.sr.getSession().getServletContext();
197
198         WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
199         WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
200         return webApplicationContext.getBean(ComponentsUtils.class);
201     }
202
203     private TitanDao getTitanDao() {
204         ServletContext context = this.sr.getSession().getServletContext();
205
206         WebAppContextWrapper webApplicationContextWrapper = (WebAppContextWrapper) context.getAttribute(Constants.WEB_APPLICATION_CONTEXT_WRAPPER_ATTR);
207         WebApplicationContext webApplicationContext = webApplicationContextWrapper.getWebAppContext(context);
208         return webApplicationContext.getBean(TitanDao.class);
209     }
210
211     // Extracted for purpose of clear method name, for logback %M parameter
212     private void inHttpRequest() {
213         if (isInfoLog()) {
214             log.info("{} {} {}", sr.getMethod(), sr.getRequestURI(), sr.getProtocol());
215         } else {
216             log.debug("{} {} {}", sr.getMethod(), sr.getRequestURI(), sr.getProtocol());
217         }
218     }
219
220     // Extracted for purpose of clear method name, for logback %M parameter
221     private void outHttpResponse(ContainerResponseContext responseContext) {
222         if (isInfoLog()) {
223             log.info("{} {} {} SC=\"{}\"", sr.getMethod(), sr.getRequestURI(), sr.getProtocol(), responseContext.getStatus());
224         } else {
225             log.debug("{} {} {} SC=\"{}\"", sr.getMethod(), sr.getRequestURI(), sr.getProtocol(), responseContext.getStatus());
226         }
227     }
228
229     private boolean isInfoLog() {
230         boolean logRequest = true;
231         Configuration configuration = ConfigurationManager.getConfigurationManager().getConfiguration();
232         String requestURI = sr.getRequestURI();
233         if (requestURI != null && configuration.getUnLoggedUrls() != null) {
234             logRequest = !configuration.getUnLoggedUrls().contains(requestURI);
235         }
236         return logRequest;
237     }
238
239     // Extracted for purpose of clear method name, for logback %M parameter
240     private void uuidGeneration(String uuid) {
241         log.info("No requestID  provided -> Generated UUID {}", uuid);
242     }
243 }