package at.gv.egiz.eaaf.utils.springboot.ajp.logging;
import java.io.IOException;
import java.util.HashMap;
import java.util.Optional;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Getter;
@Component
@EnableConfigurationProperties(LoggingProperties.class)
public class MdcEnhancerFilter implements Filter {
/**
* Logging properties.
*/
private LoggingProperties loggingProperties;
/**
* To reduce the overhead of building the final "headerMap".
*
*
* The map is to be built when the object is initiated.
*
*/
private final HashMap headerMap;
/**
* Create a new instance of {@link MdcEnhancerFilter}.
*
* @param loggingProperties an instance of {@link LoggingProperties}
*/
public MdcEnhancerFilter(LoggingProperties loggingProperties) {
this.loggingProperties = loggingProperties;
this.headerMap = new HashMap<>(this.loggingProperties.getMdc().getHeaderMap());
// add TXID into map (no overrides)
for (final Txid txid : Txid.values()) {
this.headerMap.putIfAbsent(txid.getFieldName(), txid.getHeaderName());
}
}
/**
* Filter the request headers based on the configured MDC properties.
*
* @param request incoming {@link HttpServletRequest}
*/
private void filterHeader(final HttpServletRequest request) {
this.headerMap.forEach((field, header) -> {
// to provide backwards compatibility we have to put the "null-value" into the
// MDC if it is not present
final String value = Optional.ofNullable(request.getHeader(header))
.orElse(this.loggingProperties.getMdc().getNullValue());
MDC.put(field, value);
});
}
/**
* {@inheritDoc}
*/
@Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
filterHeader(request);
String key;
String value;
for (final String cookie : loggingProperties.getMdc().getCookies()) {
key = loggingProperties.getMdc().getCookiePrefix() + cookie + loggingProperties.getMdc()
.getCookiePostfix();
value = getCookie(cookie, request.getCookies());
if (StringUtils.isNotBlank(value)) {
MDC.put(key, value);
} else if (loggingProperties.getMdc().getNullValue() != null) {
MDC.put(key, loggingProperties.getMdc().getNullValue());
}
}
Object object;
for (final String attribute : loggingProperties.getMdc().getSessionAttributes()) {
key = loggingProperties.getMdc().getSessionAttributePrefix() + attribute + loggingProperties.getMdc()
.getSessionAttributePostfix();
object = request.getSession(true).getAttribute(attribute);
if (object != null) {
MDC.put(key, object.toString());
} else if (loggingProperties.getMdc().getNullValue() != null) {
MDC.put(key, loggingProperties.getMdc().getNullValue());
}
}
try {
filterChain.doFilter(servletRequest, servletResponse);
} finally {
for (final String field : this.headerMap.keySet()) {
MDC.remove(field);
}
for (final String cookie : loggingProperties.getMdc().getCookies()) {
MDC.remove(cookie);
}
for (final String attribute : loggingProperties.getMdc().getSessionAttributes()) {
MDC.remove(attribute);
}
}
}
private static String getCookie(final String cookie, final Cookie[] cookies) {
if (cookies == null || !StringUtils.isNotBlank(cookie)) {
return null;
}
for (final Cookie c : cookies) {
if (c.getName().equals(cookie)) {
return c.getValue();
}
}
return null;
}
/**
* Enumeration of default TXIDs handled by the auto-configuration.
*/
@Getter
private enum Txid {
HTTP_REQUEST("AM-TXID-HTTP-Request", "amTxidHttpRequest"),
BROWSER("AM-TXID-Browser-Session", "amTxidBrowserSession"),
IDP("AM-TXID-IdP-Session", "amTxidIdpSession"),
SP("AM-TXID-SP-Session", "amTxidSpSession");
private final String headerName;
private final String fieldName;
Txid(final String headerName, final String fieldName) {
this.headerName = headerName;
this.fieldName = fieldName;
}
}
}