diff options
Diffstat (limited to 'eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf')
4 files changed, 410 insertions, 0 deletions
| diff --git a/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/TomcatAjpConfiguration.java b/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/TomcatAjpConfiguration.java new file mode 100644 index 00000000..c665edb3 --- /dev/null +++ b/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/TomcatAjpConfiguration.java @@ -0,0 +1,145 @@ +package at.gv.egiz.eaaf.utils.springboot.ajp; + +import java.io.File; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Map; + +import org.apache.catalina.connector.Connector; +import org.apache.commons.lang3.StringUtils; +import org.apache.coyote.AbstractProtocol; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.ajp.AbstractAjpProtocol; +import org.apache.tomcat.util.net.NioChannel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +import at.gv.egiz.eaaf.utils.springboot.ajp.logging.LoggingProperties; +import at.gv.egiz.eaaf.utils.springboot.ajp.logging.MdcEnhancerFilter; +import ch.qos.logback.access.tomcat.LogbackValve; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Configuration +@EnableConfigurationProperties(value = {LoggingProperties.class, TomcatProperties.class}) +@PropertySource("classpath:tomcat.properties") +@PropertySource(value = "classpath:tomcat-${spring.profiles.active}.properties", ignoreResourceNotFound = true) +public class TomcatAjpConfiguration { +  private static final String PROTOCOL = "AJP/1.3"; +   +  @Autowired +  private LoggingProperties loggingProperties;   + +  @Autowired +  private TomcatProperties tomcatProperties; + +  @Value("${tomcat.workingdir:./work}") +  String tomcatWorkDirectory; +   +  /** +   * Set MDC variables for embedded Tomcat access-logging. +   *  +   * @param filter {@link MdcEnhancerFilter} that injects MDS variables +   * @return +   */ +  @Bean +  public FilterRegistrationBean<MdcEnhancerFilter> enhacedMdcFilter(@Autowired MdcEnhancerFilter filter) { +    FilterRegistrationBean<MdcEnhancerFilter> registration = new FilterRegistrationBean<>(filter); +    registration.setEnabled(loggingProperties.getMdc().isEnabled()); +    return registration; +     +  } +   +  /** +   * Adds AJP Connector to embedded Tomcat. +   * +   * @return +   */ +  @Bean +  public TomcatServletWebServerFactory servletContainer() { +    final TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory(); +     +    //set working directory +    final File workDirFile = new File(tomcatWorkDirectory); +    checkBasekDirectory(workDirFile); +    tomcat.setBaseDirectory(workDirFile); +    log.info("Set embedded Tomcat workingDirectory to: {}", +        workDirFile.getAbsolutePath()); +     +    //set logger configuration +    if (loggingProperties.getAccessLog().isEnabled()) { +      LogbackValve valve = new LogbackValve(); +      valve.setFilename(loggingProperties.getAccessLog().getFilename()); +      tomcat.addEngineValves(valve); +    } +     +    final TomcatProperties.Ajp ajp = tomcatProperties.getAjp(); +    if (ajp != null && ajp.isEnabled()) { +      final Connector ajpConnector = new Connector(PROTOCOL); +      ajpConnector.setPort(ajp.getPort()); +      ajpConnector.setSecure(ajp.isSecure()); +      ajpConnector.setAllowTrace(ajp.isAllowTrace()); +      ajpConnector.setScheme(ajp.getScheme()); +      setNetworkAddress(ajpConnector.getProtocolHandler(),  +          ajp.getNetworkAddress()); +       +      if (ajp.getAdditionalAttributes() != null) { +        for (final Map.Entry<String, String> entry :  +            ajp.getAdditionalAttributes().entrySet()) { +          log.debug("Set Tomcat AJP property: {} with value: {}", +              entry.getKey(), entry.getValue()); +          ajpConnector.setAttribute(entry.getKey(), entry.getValue()); +        } +      } +      log.debug("AJP connector requires secret: {}",  +          ((AbstractAjpProtocol<?>) ajpConnector.getProtocolHandler()).getSecretRequired()); +       +      tomcat.addAdditionalTomcatConnectors(ajpConnector); +    } + +    return tomcat; +  } +   +  private void setNetworkAddress(ProtocolHandler protocolHandler, String address) {     +    log.trace("Set network address: {} to ProtocolHandler: {}", address, protocolHandler.getClass().getName()); +    if (StringUtils.isNotEmpty(address) +        && protocolHandler instanceof AbstractProtocol<?>) { +      try { +        ((AbstractProtocol<NioChannel>) protocolHandler).setAddress(InetAddress.getByName(address)); +        log.info("Bind connector: {} to address: {}", PROTOCOL, address); +         +      } catch (UnknownHostException e) { +        log.error("Can NOT set network address: {} to connector: {}", address, PROTOCOL); +         +      } +             +    } else { +      log.debug("Bind connector: {} to default address", PROTOCOL); +       +    }     +  } +   +  private void checkBasekDirectory(File workDirFile) { +    if (!workDirFile.exists()) { +      log.debug("Embedded Tomcat workingDirectory: {} not exist. Create it ... ", +          workDirFile.getAbsolutePath()); +      if (workDirFile.mkdirs()) { +        log.info("Embedded Tomcat workingDirectory created"); + +      } +    } + +    if (!workDirFile.isDirectory()) { +      log.error("Path to embedded Tomcat workingDirectory: {} is NOT directory", +          workDirFile.getAbsolutePath()); + +    } +  } + +} diff --git a/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/TomcatProperties.java b/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/TomcatProperties.java new file mode 100644 index 00000000..acddafa0 --- /dev/null +++ b/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/TomcatProperties.java @@ -0,0 +1,72 @@ +package at.gv.egiz.eaaf.utils.springboot.ajp; + +import java.util.Map; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Getter; +import lombok.Setter; + +/** + * Embedded tomcat configuration properties. + */ +@ConfigurationProperties(prefix = "tomcat", ignoreInvalidFields = true) +@Getter +@Setter +public class TomcatProperties { + +  /** +   * AJP connector properties. +   */ +  private Ajp ajp; + +  /** +   * AJP connector properties. +   */ +  @Getter +  @Setter +  public static class Ajp { + +    /** +     * Should the AJP port be enabled. +     */ +    private boolean enabled; + +    /** +     * AJP protocol. +     */ +    private String protocol = "AJP/1.3"; + +    /** +     * AJP port. +     */ +    private int port = 8009; + +    /** +     * Secure connection flag. +     */ +    private boolean secure; + +    /** +     * Flag, to disable or enable the TRACE HTTP method. +     */ +    private boolean allowTrace; + +    /** +     * Scheme that will be assigned to requests received through this connector. +     */ +    private String scheme = "http"; + +    /** +     * Network address to bind this connector. +     */ +    private String networkAddress = null; +     +    /** +     * Additional AJP Connector Attributes e.g. packetSize. +     */ +    private Map<String, String> additionalAttributes; + +  } + +} diff --git a/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/logging/LoggingProperties.java b/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/logging/LoggingProperties.java new file mode 100644 index 00000000..b3d5d846 --- /dev/null +++ b/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/logging/LoggingProperties.java @@ -0,0 +1,94 @@ +package at.gv.egiz.eaaf.utils.springboot.ajp.logging; + +import java.util.Collections; +import java.util.List; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import lombok.Getter; +import lombok.Setter; + +/** + * Logger configuration for embedded Tomcat. + * + * @author BRZ development team + * @author tlenz + * + */ +@ConfigurationProperties(prefix = "logging") +@Getter +@Setter +public class LoggingProperties { +  /** +   * Whether to log in JSON format. +   */ +  private boolean json = true; +  /** +   * Whether to log in plain text. +   */ +  private boolean text = false; +  /** +   * Default Logback Pattern. +   */ +  private String pattern = "### unused property ###"; +  /** +   * Logback Mapped Diagnostic Context. +   */ +  private Mdc mdc = new Mdc(); + +  /** +   * Logback Mapped Diagnostic Context. +   */ + +  @Getter +  @Setter +  public static class Mdc { +    /** +     * Whether to use Logback's MDC. +     */ +    private boolean enabled = false; +    /** +     * List of HTTP Headers to make available in Logback's MDC. +     */ +    private List<String> headers = Collections.emptyList(); +    private String headerPrefix = ""; +    private String headerPostfix = ""; +    /** +     * List of HTTP Cookies to make available in Logback's MDC. +     */ +    private List<String> cookies = Collections.emptyList(); +    private String cookiePrefix = ""; +    private String cookiePostfix = ""; +    /** +     * List of HTTP Session Attributes to make available in Logback's MDC. +     */ +    private List<String> sessionAttributes = Collections.emptyList(); +    private String sessionAttributePrefix = ""; +    private String sessionAttributePostfix = ""; +    /** +     * Value to use if a configured MDC entry would be null. +     */ +    private String nullValue = null; +  } + +  /** +   * Tomcat AccessLog. +   */ +  private AccessLog accessLog = new AccessLog(); + +  /** +   * Tomcat AccessLog. +   */ +  @Getter +  @Setter +  public static class AccessLog { +    /** +     * Enable AccessLog. +     */ +    private boolean enabled = false; +    /** +     * Logback access log filename. +     */ +    private String filename = "logback-access.xml"; +  } +} diff --git a/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/logging/MdcEnhancerFilter.java b/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/logging/MdcEnhancerFilter.java new file mode 100644 index 00000000..d63c47c9 --- /dev/null +++ b/eaaf-springboot-utils/src/main/java/at/gv/egiz/eaaf/utils/springboot/ajp/logging/MdcEnhancerFilter.java @@ -0,0 +1,99 @@ +package at.gv.egiz.eaaf.utils.springboot.ajp.logging; + +import java.io.IOException; + +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.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@EnableConfigurationProperties(LoggingProperties.class) +public class MdcEnhancerFilter implements Filter { + +  /** +   * Logging properties. +   */ +  @Autowired +  private LoggingProperties loggingProperties; + +  /** +   * {@inheritDoc} +   */ +  @Override +  public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, +      final FilterChain filterChain) throws IOException, ServletException { +    final HttpServletRequest request = (HttpServletRequest) servletRequest; + +    String key; +    String value; +    for (final String header : loggingProperties.getMdc().getHeaders()) { +      key = loggingProperties.getMdc().getHeaderPrefix() + header + loggingProperties.getMdc() +          .getHeaderPostfix(); +      value = request.getHeader(header); +      if (!StringUtils.isEmpty(value)) { +        MDC.put(key, value); +      } else if (loggingProperties.getMdc().getNullValue() != null) { +        MDC.put(key, loggingProperties.getMdc().getNullValue()); +      } +    } + +    for (final String cookie : loggingProperties.getMdc().getCookies()) { +      key = loggingProperties.getMdc().getCookiePrefix() + cookie + loggingProperties.getMdc() +          .getCookiePostfix(); +      value = getCookie(cookie, request.getCookies()); +      if (!StringUtils.isEmpty(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 header : loggingProperties.getMdc().getHeaders()) { +        MDC.remove(header); +      } +      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.isEmpty(cookie)) { +      return null; +    } +    for (final Cookie c : cookies) { +      if (c.getName().equals(cookie)) { +        return c.getValue(); +      } +    } +    return null; +  } +}
\ No newline at end of file | 
