/*
* Copyright 2008-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.hasor.web.startup;
import net.hasor.core.AppContext;
import net.hasor.core.utils.ExceptionUtils;
import net.hasor.core.utils.StringUtils;
import net.hasor.web.Invoker;
import net.hasor.web.ServletVersion;
import net.hasor.web.invoker.ExceuteCaller;
import net.hasor.web.invoker.InvokerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* 入口Filter,同一个应用程序只能实例化一个 RuntimeFilter 对象。
* @version : 2017-01-10
* @author 赵永春 (zyc@hasor.net)
*/
public class RuntimeFilter implements Filter {
protected Logger logger = LoggerFactory.getLogger(getClass());
private final AtomicBoolean inited = new AtomicBoolean(false);
public static final String HTTP_REQUEST_ENCODING_KEY = "HTTP_REQUEST_ENCODING";
public static final String HTTP_RESPONSE_ENCODING_KEY = "HTTP_RESPONSE_ENCODING";
private String httpRequestEncoding = null;
private String httpResponseEncoding = null;
//
private AppContext appContext = null;
private InvokerContext invokerContext = null;
//
public void init(FilterConfig filterConfig) throws ServletException {
if (!this.inited.compareAndSet(false, true)) {
return;
}
Map<String, String> configMap = new HashMap<String, String>();
Enumeration<?> names = filterConfig.getInitParameterNames();
if (names != null) {
while (names.hasMoreElements()) {
String name = names.nextElement().toString();
configMap.put(name, filterConfig.getInitParameter(name));
}
}
// .编码
AppContext appContext = RuntimeListener.getAppContext(filterConfig.getServletContext());
this.httpRequestEncoding = appContext.findBindingBean(HTTP_REQUEST_ENCODING_KEY, String.class);
this.httpResponseEncoding = appContext.findBindingBean(HTTP_RESPONSE_ENCODING_KEY, String.class);
try {
this.appContext = appContext;
this.invokerContext = new InvokerContext();
this.invokerContext.initContext(appContext, configMap);
} catch (ServletException e) {
throw (ServletException) e;
} catch (Throwable e) {
throw ExceptionUtils.toRuntimeException(e);
}
//
// .启动日志
if (ServletVersion.V2_5.le(this.appContext.getInstance(ServletVersion.class))) {
logger.info("RuntimeFilter started, at {}", filterConfig.getServletContext().getServerInfo());
} else {
logger.info("RuntimeFilter started, context at {}", filterConfig.getServletContext().getContextPath());
}
}
@Override
public void destroy() {
this.invokerContext.destroyContext();
}
//
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//
// .设置编码
HttpServletRequest httpReq = (HttpServletRequest) request;
HttpServletResponse httpRes = (HttpServletResponse) response;
if (StringUtils.isNotBlank(this.httpRequestEncoding))
httpReq.setCharacterEncoding(this.httpRequestEncoding);
if (StringUtils.isNotBlank(this.httpResponseEncoding))
httpRes.setCharacterEncoding(this.httpResponseEncoding);
//
// .执行
try {
this.beforeRequest(this.appContext, httpReq, httpRes);
doFilter(chain, httpReq, httpRes);
} catch (Throwable e) {
logger.error(e.getMessage(), e);
String mode = appContext.getEnvironment().getWorkMode();
if ("debug".equalsIgnoreCase(mode) && !response.isCommitted()) {
e.printStackTrace(response.getWriter());
}
if (e instanceof IOException)
throw (IOException) e;
if (e instanceof ServletException)
throw (ServletException) e;
throw ExceptionUtils.toRuntimeException(e);
} finally {
this.afterResponse(this.appContext, httpReq, httpRes);
}
}
private void doFilter(FilterChain chain, HttpServletRequest httpReq, HttpServletResponse httpRes) throws IOException, ServletException {
try {
Invoker invoker = this.invokerContext.newInvoker(httpReq, httpRes);
ExceuteCaller caller = this.invokerContext.genCaller(invoker);
if (caller != null) {
Future<Object> resultData = caller.invoke(invoker, chain);
if (resultData != null && resultData.isDone()) {
resultData.get();
}
} else {
chain.doFilter(httpReq, httpRes);
}
//
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException)
throw (IOException) cause;
if (cause instanceof ServletException)
throw (ServletException) cause;
if (cause instanceof RuntimeException)
throw (RuntimeException) cause;
throw ExceptionUtils.toRuntimeException(cause);
//
} catch (IOException e) {
throw (IOException) e;
} catch (ServletException e) {
throw (ServletException) e;
} catch (Throwable e) {
throw ExceptionUtils.toRuntimeException(e);
}
}
//
/**在filter请求处理之前。*/
protected void beforeRequest(final AppContext appContext, final HttpServletRequest httpReq, final HttpServletResponse httpRes) {
}
//
/**在filter请求处理之后。*/
protected void afterResponse(final AppContext appContext, final HttpServletRequest httpReq, final HttpServletResponse httpRes) {
}
}