Tagged: filter

Extending Filter Implemtations


Let’s say you are going to extend a class implementing Filter interface.

public class MyFilter implements Filter {


    @Override
    public void init(final FilterConfig config) throws ServletException {

        logger = newLogger();
    }


    protected Logger getLogger() {

        if (logger == null) {
            // before init() or after destroy();
            throw new IllegalStateException("no logger");
        }

        return logger;
    }


    @Override
    public void destroy() {

        logger = null;
    }


    private Logger logger;
}

This is how we should override those two important life-cycle methods

public class YourFilter extends MyFilter {


    @Override
    public void init(final FilterConfig config) throws ServletException {

        super.init(config);

        // do your jobs, after.
        getLogger().log("init()");
    }


    @Override
    public void destroy() {

        // do your jobs, before.
        getLogger().log("destroy()");

        super.destroy();
    }
}
Advertisements

Adding additional headers on a ServletRequest


References

Problem

Simply, we can’t add or modify request headers on given HttpServletRequest instances.

Solution

The only solution, at least mentioned in above links, is using HttpServletRequestWrapper class. I wrote, for my own, a class which wraps additional headers around the actual request instance.

public class RequestHeaderWrapper extends HttpServletRequestWrapper {

    public RequestHeaderWrapper(
        final HttpServletRequest request,
        final Map<String, List<String>> precedingHeaders,
        final Map<String, List<String>> succeedingHeaders) {

        super(request);

        headers = new HashMap<>();

        if (precedingHeaders != null) {
            for (final String name : precedingHeaders.keySet()) {
                List<String> values = headers.get(name);
                if (values == null) {
                    values = new ArrayList<>();
                    headers.put(name, values);
                }
                values.addAll(precedingHeaders.get(name));
            }
        }

        for (final Enumeration<String> names = request.getHeaderNames();
             names.hasMoreElements();) {
            final String name = names.nextElement();
            List<String> value = headers.get(name);
            if (value == null) {
                value = new ArrayList<>();
                headers.put(name, value);
            }
            value.addAll(Collections.list(request.getHeaders(name)));
        }

        if (succeedingHeaders != null) {
            for (final String name : succeedingHeaders.keySet()) {
                List<String> values = headers.get(name);
                if (values == null) {
                    values = new ArrayList<>();
                    headers.put(name, values);
                }
                values.addAll(succeedingHeaders.get(name));
            }
        }
    }

    @Override
    public String getHeader(final String name) {
        final List<String> values = headers.get(name);
        if (values != null && !values.isEmpty()) {
            return values.get(0);
        }
        return null;
    }

    @Override
    public Enumeration<String> getHeaders(final String name) {
        List<String> values = headers.get(name);
        if (values == null) {
            return Collections.emptyEnumeration();
        }
        return Collections.enumeration(values);
    }

    @Override
    public Enumeration<String> getHeaderNames() {
        return Collections.enumeration(headers.keySet());
    }

    private final Map<String, List<String>> headers;
}

Full and latest source code is here and the apidocs is here.

Apache Maven

Please check the central if you’re using Apache Maven.

<dependency>
  <groupId>com.googlecode.jinahya</groupId>
  <artifactId>jinahya-ee</artifactId>
  <version>@@?</version>
</dependency>

Usage

There are some factory methods for simple use.

public class MyFilter implements Filter {

    @Override
    public void doFilter(final ServletRequest request,
                         final ServletResponse response,
                         final FilterChain chain)
        throws IOException, ServletException {

        final ServletRequest wrapper =
            RequestHeaderWrapper.newPrecedingInstance(
                requerst, "Accept", "application/xml");
        chain.doFilter(wrapper, response);
}

Servlet Filter for HTTP


A problem of Filter is that the doChain method is for ServletRequest and ServletResponse.

public class MyFilter implements Filter {

    @Override
    public void init(final FilterConfig filterConfig)
        throws ServletException {
    }

    @Override
    public void doFilter(
        final ServletRequest request, final ServletResponse response,
        final FilterChain chain)
        throws IOException, ServletException {
    }

    @Override
    public void destroy() {
    }
}

It’s not a big deal if you presume that those are actually instances of HTTP version.

@Override
public void doFilter(final ServletRequest request,
                     final ServletResponse response,
                     final FilterChain chain)
    throws IOException, ServletException {

    final HttpServletRequest hequest = (HttpServletRequest) request;
    final HttpServletResponse hesponse = (HttpServletResponse) response;

    // happy, now?
}

I quickly tired of doing this.

public abstract class HttpFilter implements Filter {

    @Override
    public void doFilter(final ServletRequest request,
                         final ServletResponse response,
                         final FilterChain chain)
        throws IOException, ServletException {

        if (request instanceof HttpServletRequest
            && response instanceof HttpServletResponse) {

            doFilter((HttpServletRequest) request,
                     (HttpServletResponse) resposne, chain);

           return;
        }

        chain.doFilter(request, response, chain);
    }

    protected abstract void doFilter(HttpServletRequest request,
                                     HttpServletResponse response,
                                     FilterChain chain)
        throws IOException, ServletException;
}

Now I can do this.

public class MyFilter extends HttpFilter {

    @Override
    protected void doFilter(final HttpServletRequest request,
                            final HttpServletResponse response,
                            final FilterChain chain)
        throws IOException, ServletException {

        // never bean happier. :)
    }
}

Full source is here.