Search code examples
spring-cloud-dataflow

How to use Filter in Spring Cloud Data Flow?


I would like to add a Filter in Spring Cloud Data Flow (SCDF) to debug and see how it works when receiving some requests.

I have tried to implements javax.servlet.Filter and override doFilter method but It's seem not work because there are some default Filter of SCDF had been started before my Filter class.

Are there any way do write a filter for SCDF? Is it possible if I apply this link for this purpose?

This is my Filter class:

@Component
public class CustomFilter implements Filter {


    @Override
    public void destroy() {
        System.out.println("init fillter ");
    }

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
            throws IOException, ServletException {
        try {
            HttpServletRequest req = (HttpServletRequest) arg0;
            ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(
                    (HttpServletResponse) arg1);
            ResettableStreamHttpServletRequest wrappedRequest = new ResettableStreamHttpServletRequest(
                    (HttpServletRequest) req);
            logger.info(">>>>>link: " + req.getServletPath() + "?");
            for (Entry<String, String[]> entry : req.getParameterMap().entrySet()) {
                logger.info(">>>>>param: " + entry.getKey() + ":" + entry.getValue()[0]);
            }
            String bodyRequest = IOUtils.toString(wrappedRequest.getReader());
            logger.info(">>>>>link: " + req.getServletPath() + "?");
            for (Entry<String, String[]> entry : req.getParameterMap().entrySet()) {
                logger.info(">>>>>param: " + entry.getKey() + ":" + entry.getValue()[0]);
            }

            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            transformerFactory.setAttribute("indent-number", 2);
            javax.xml.transform.Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            try {

                logger.info("Request: " + bodyRequest);
            } catch (Exception e) {
                logger.info("Request: " + bodyRequest);
            }

            wrappedRequest.resetInputStream();
            arg2.doFilter(wrappedRequest, responseWrapper);
            logger.info("Response: " + IOUtils.toString(responseWrapper.getContentInputStream()));

            responseWrapper.copyBodyToResponse();
        } catch (Exception ex) {
            logger.info("doFilter: " + ex);
        }
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        System.out.println("init fillter " + arg0);
    }

    private static class ResettableStreamHttpServletRequest extends HttpServletRequestWrapper {

        private byte[] rawData;
        private HttpServletRequest request;
        private ResettableServletInputStream servletStream;

        public ResettableStreamHttpServletRequest(HttpServletRequest request) {
            super(request);
            this.request = request;
            this.servletStream = new ResettableServletInputStream();
        }

        public void resetInputStream() {
            servletStream.stream = new ByteArrayInputStream(rawData);
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            if (rawData == null) {
                rawData = IOUtils.toByteArray(this.request.getReader());
                servletStream.stream = new ByteArrayInputStream(rawData);
            }
            return servletStream;
        }

        @Override
        public BufferedReader getReader() throws IOException {
            if (rawData == null) {
                rawData = IOUtils.toByteArray(this.request.getReader());
                servletStream.stream = new ByteArrayInputStream(rawData);
            }
            return new BufferedReader(new InputStreamReader(servletStream));
        }

        private class ResettableServletInputStream extends ServletInputStream {

            private InputStream stream;

            @Override
            public int read() throws IOException {
                return stream.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener arg0) {

            }
        }
    }
}

Solution

  • Spring Cloud Data Flow server is inherently a Spring Boot application and hence it allows you to inject specific configuration beans into Data Flow configuration to extend/customize.

    In your case, you can create a bean that extends javax.servlet.http.HttpFilter or implements javax.servlet.Filter and have that bean injected into SCDF configuration.