Revert "Promise Request-id header: Check MDC value if no header"
[vid.git] / vid-app-common / src / main / java / org / onap / vid / controller / filter / PromiseRequestIdFilter.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 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.onap.vid.controller.filter;
22
23
24 import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
25 import static org.apache.commons.lang3.StringUtils.isNotEmpty;
26 import static org.onap.portalsdk.core.util.SystemProperties.ECOMP_REQUEST_ID;
27
28 import com.google.common.collect.ImmutableList;
29 import java.io.IOException;
30 import java.util.Collections;
31 import java.util.Enumeration;
32 import java.util.UUID;
33 import java.util.function.Supplier;
34 import java.util.regex.Pattern;
35 import javax.servlet.FilterChain;
36 import javax.servlet.ServletException;
37 import javax.servlet.ServletRequest;
38 import javax.servlet.ServletResponse;
39 import javax.servlet.annotation.WebFilter;
40 import javax.servlet.http.HttpServletRequest;
41 import javax.servlet.http.HttpServletRequestWrapper;
42 import javax.servlet.http.HttpServletResponse;
43 import javax.validation.constraints.NotNull;
44 import org.onap.vid.logging.Headers;
45 import org.onap.vid.logging.RequestIdHeader;
46 import org.springframework.web.filter.GenericFilterBean;
47
48 @WebFilter(urlPatterns = "/*")
49 public class PromiseRequestIdFilter extends GenericFilterBean {
50
51     // The wrapped request is guaranteed to have the transaction id as the value
52     // of the header PROMISED_HEADER_NAME.
53     // PROMISED_HEADER_NAME is set to ECOMP_REQUEST_ID as long as
54     // org.onap.portalsdk...UserUtils.getRequestId() is using the header
55     // "X-ECOMP-RequestID".
56     private static final RequestIdHeader PROMISED_HEADER = RequestIdHeader.ECOMP_ID;
57     private static final String REQUEST_ID_RESPONSE_HEADER = ECOMP_REQUEST_ID + "-echo";
58
59     private static final Pattern uuidRegex = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", Pattern.CASE_INSENSITIVE);
60
61     @Override
62     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
63             throws IOException, ServletException {
64
65         if (request instanceof HttpServletRequest) {
66             request = wrapIfNeeded(request);
67
68             if (response instanceof HttpServletResponse) {
69                 final String actualRequestId = PROMISED_HEADER.getHeaderValue((HttpServletRequest) request);
70                 ((HttpServletResponse) response).addHeader(REQUEST_ID_RESPONSE_HEADER, actualRequestId);
71             }
72         }
73
74         chain.doFilter(request, response);
75     }
76
77     public ServletRequest wrapIfNeeded(ServletRequest request) {
78         final HttpServletRequest httpRequest = (HttpServletRequest) request;
79
80         final RequestIdHeader highestPriorityHeader = highestPriorityHeader(httpRequest);
81         final String originalRequestId = highestPriorityHeader.getHeaderValue(httpRequest);
82
83         if (isWrapNeeded(highestPriorityHeader, originalRequestId)) {
84             // Copy originalRequestId to the promised header value
85             request = new PromiseRequestIdRequestWrapper(httpRequest, toUuidOrElse(originalRequestId, UUID::randomUUID));
86         }
87
88         return request;
89     }
90
91     private boolean verifyAndValidateUuid(String value) {
92         return isNotEmpty(value) && uuidRegex.matcher(value).matches();
93     }
94
95     private boolean isWrapNeeded(RequestIdHeader highestPriorityHeader, String originalRequestId) {
96         boolean headerExistsAndValid =
97             PROMISED_HEADER == highestPriorityHeader && verifyAndValidateUuid(originalRequestId);
98
99         return !headerExistsAndValid;
100     }
101
102     UUID toUuidOrElse(String uuid, Supplier<UUID> uuidSupplier) {
103         if (verifyAndValidateUuid(uuid)) {
104             try {
105                 return UUID.fromString(uuid);
106             } catch (IllegalArgumentException e) {
107                 return uuidSupplier.get();
108             }
109         } else {
110             return uuidSupplier.get();
111         }
112     }
113
114     RequestIdHeader highestPriorityHeader(HttpServletRequest httpRequest) {
115         return defaultIfNull(Headers.highestPriorityHeader(httpRequest), PROMISED_HEADER);
116     }
117
118     private static class PromiseRequestIdRequestWrapper extends HttpServletRequestWrapper {
119
120         private final UUID requestId;
121
122         PromiseRequestIdRequestWrapper(HttpServletRequest request, @NotNull UUID requestId) {
123             super(request);
124             this.requestId = requestId;
125         }
126
127         @Override
128         public String getHeader(String name) {
129             return isRequestIdHeaderName(name) ?
130                     requestId.toString() : super.getHeader(name);
131         }
132
133         @Override
134         public Enumeration<String> getHeaders(String name) {
135             if (isRequestIdHeaderName(name)) {
136                 return Collections.enumeration(Collections.singleton(requestId.toString()));
137             } else {
138                 return super.getHeaders(name);
139             }
140         }
141
142         @Override
143         public Enumeration<String> getHeaderNames() {
144
145             if (null == super.getHeader(PROMISED_HEADER.getHeaderName())) {
146                 return Collections.enumeration(ImmutableList.<String>builder()
147                     .add(PROMISED_HEADER.getHeaderName())
148                     .addAll(Collections.list(super.getHeaderNames()))
149                     .build());
150             }
151
152             return super.getHeaderNames();
153         }
154
155         private boolean isRequestIdHeaderName(String name) {
156             return PROMISED_HEADER.stringEquals(name);
157         }
158     }
159 }