package com.yingying.tourist.request;

import org.apache.commons.io.IOUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;


/**
 * request.getInputStream()/getReader 只能获取一次的问题
 * 
 * @author sks
 *
 */
@Component
@Order(1)
@WebFilter(filterName = "HttpServletRequestReplacedFilter", urlPatterns = "/*")
public class HttpServletRequestReplacedFilter implements Filter {

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		ServletRequest requestWrapper = null;
		if (request instanceof HttpServletRequest) {
			String contentType = request.getContentType();
			if (contentType != null && contentType.contains("application/json")) {
				requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
			}
		}
		if (null == requestWrapper) {
			chain.doFilter(request, response);
		} else {
			chain.doFilter(requestWrapper, response);
		}
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub

	}

	private class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
		private final byte[] rawData;

		public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
			super(request);
			rawData = IOUtils.toByteArray(request.getReader());
		}

		@Override
		public BufferedReader getReader() throws IOException {
			return new BufferedReader(new InputStreamReader(getInputStream()));
		}

		@Override
		public ServletInputStream getInputStream() throws IOException {
			final ByteArrayInputStream bais = new ByteArrayInputStream(rawData);
			return new ServletInputStream() {

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

				@Override
				public boolean isFinished() {
					return bais.available() == 0;
				}

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

				@Override
				public void setReadListener(ReadListener arg0) {
					throw new RuntimeException("Not implemented");
				}
			};
		}
	}

}
