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