org.solmix.wmix.web.servlet.AbstractWmixFilter.java Source code

Java tutorial

Introduction

Here is the source code for org.solmix.wmix.web.servlet.AbstractWmixFilter.java

Source

/**
 * Copyright (c) 2015 The Solmix Project
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.gnu.org/licenses/ 
 * or see the FSF site: http://www.fsf.org. 
 */

package org.solmix.wmix.web.servlet;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.solmix.commons.util.Assert;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceEditor;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.context.support.ServletContextResourceLoader;

/**
 * 
 * @author solmix.f@gmail.com
 * @version $Id$ 2015130
 */

public class AbstractWmixFilter implements Filter {

    protected final Logger LOG = LoggerFactory.getLogger(getClass());

    private FilterConfig filterConfig;

    private final Set<String> requiredProperties = new HashSet<String>();

    protected final void addRequiredProperty(String name) {
        this.requiredProperties.add(name);
    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponse httpResponse = (HttpServletResponse) response;

            String method = httpRequest.getMethod();

            if ("HEAD".equalsIgnoreCase(method)) {
                httpResponse = new NoBodyResponse(httpResponse);
            }

            try {
                doFilter(httpRequest, httpResponse, chain);
            } finally {
                if (httpResponse instanceof NoBodyResponse) {
                    ((NoBodyResponse) httpResponse).setContentLength();
                }
            }
        } else {
            LOG.debug("Skipped filtering due to the unknown request/response types: {}, {}",
                    request.getClass().getName(), response.getClass().getName());

            chain.doFilter(request, response);
        }

    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        filterConfig = config;
        logInBothServletAndLoggingSystem("Initializing filter: " + getFilterName());

        try {
            PropertyValues pvs = new FilterConfigPropertyValues(getFilterConfig(), requiredProperties);
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader));
            initBeanWrapper(bw);
            bw.setPropertyValues(pvs, true);
        } catch (Exception e) {
            throw new ServletException("Failed to set bean properties on filter: " + getFilterName(), e);
        }

        try {
            init();
        } catch (Exception e) {
            throw new ServletException("Failed to init filter: " + getFilterName(), e);
        }

        logInBothServletAndLoggingSystem(
                getClass().getSimpleName() + " - " + getFilterName() + ": initialization completed");
    }

    protected void initBeanWrapper(BeanWrapper bw) throws BeansException {
    }

    public final FilterConfig getFilterConfig() {
        return filterConfig;
    }

    public final String getFilterName() {
        return filterConfig == null ? null : filterConfig.getFilterName();
    }

    /** ??webappcontext */
    public final ServletContext getServletContext() {
        return filterConfig == null ? null : filterConfig.getServletContext();
    }

    protected void init() throws Exception {
    }

    protected final void logInBothServletAndLoggingSystem(String msg) {
        getServletContext().log(msg);
        LOG.info(msg);
    }

    private static class FilterConfigPropertyValues extends MutablePropertyValues {

        private static final long serialVersionUID = -5359131251714023794L;

        public FilterConfigPropertyValues(FilterConfig config, Set<String> requiredProperties)
                throws ServletException {

            for (Enumeration<?> e = config.getInitParameterNames(); e.hasMoreElements();) {
                String key = (String) e.nextElement();
                String value = config.getInitParameter(key);

                addPropertyValue(new PropertyValue(key, value));
                requiredProperties.remove(key);
            }

            Assert.assertTrue(requiredProperties.isEmpty(),
                    "Initialization for filter %s failed.  " + "The following required properties were missing: %s",
                    config.getFilterName(), requiredProperties);
        }
    }

    private static class NoBodyResponse extends HttpServletResponseWrapper {
        private final NoBodyOutputStream noBody = new NoBodyOutputStream();
        private PrintWriter writer;
        private boolean didSetContentLength;

        public NoBodyResponse(HttpServletResponse response) {
            super(response);
        }

        public void setContentLength() {
            if (!didSetContentLength) {
                super.setContentLength(noBody.getContentLength());
            }
        }

        @Override
        public void setContentLength(int len) {
            super.setContentLength(len);
            didSetContentLength = true;
        }

        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return noBody;
        }

        @Override
        public PrintWriter getWriter() throws UnsupportedEncodingException {
            if (writer == null) {
                writer = new PrintWriter(new OutputStreamWriter(noBody, getCharacterEncoding()));
            }

            return writer;
        }
    }

    private static class NoBodyOutputStream extends ServletOutputStream {
        private int contentLength;

        public NoBodyOutputStream() {
            contentLength = 0;
        }

        public int getContentLength() {
            return contentLength;
        }

        @Override
        public void write(int b) {
            contentLength++;
        }

        @Override
        public void write(byte[] buf, int offset, int len) throws IOException {
            if (len >= 0) {
                contentLength += len;
            } else {
                throw new IOException("negative length");
            }
        }
    }
}