package com.ufida.haisheng.struts;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.BigDecimalConverter;
import org.apache.commons.beanutils.converters.ClassConverter;
import org.apache.commons.beanutils.converters.IntegerConverter;
import org.apache.commons.beanutils.converters.LongConverter;
import org.apache.log4j.Logger;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.util.MessageResources;
import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.hibernate.HibernateException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.ufida.haisheng.constants.Globals;
import com.ufida.haisheng.converter.DateConverter;
import com.ufida.haisheng.converter.TimestampConverter;
import com.ufida.haisheng.exp.ExceptionDTO;
import com.ufida.haisheng.exp.ExceptionDisplayDTO;
import com.ufida.haisheng.exp.exceptionhandler.ExceptionHandlerFactory;
import com.ufida.haisheng.exp.exceptionhandler.ExceptionUtil;
import com.ufida.haisheng.exp.exceptionhandler.IExceptionHandler;
import com.ufida.haisheng.exp.exceptions.BaseAppException;
import com.ufida.haisheng.exp.exceptions.MappingConfigException;
import com.ufida.haisheng.exp.exceptions.NoSuchBeanConfigException;
/**
* 系统的Ajax转发基类。增加模版处理异常信息。
*
* @author 陈志平 chenzp
* @desc BaseDispatchDocumentAction.java
*
* @说明: web 应用基础平台
* @date 2005-03-02 11:18:01 AM
* @版权所有: All Right Reserved 2006-2008
*/
public abstract class BaseDispatchDocumentAction extends Action {
protected Class clazz = this.getClass();
protected static Logger log = Logger.getLogger(
BaseDispatchDocumentAction.class);
/**
* 异常信息
*/
protected static ThreadLocal<ExceptionDisplayDTO>
expDisplayDetails = new ThreadLocal<ExceptionDisplayDTO>();
private static final Long defaultLong = null;
private static ApplicationContext ctx = null;
/**
* 注册转换的工具类 使得From中的string --
* Model中的对应的类型(Date,BigDecimal,Timestamp,Double...)
*/
static {
ConvertUtils.register(new ClassConverter(), Double.class);
ConvertUtils.register(new DateConverter(), Date.class);
ConvertUtils.register(new DateConverter(), String.class);
ConvertUtils.register(new LongConverter(defaultLong), Long.class);
ConvertUtils.register(new IntegerConverter(defaultLong), Integer.class);
ConvertUtils.register(new TimestampConverter(), Timestamp.class);
ConvertUtils.register(new BigDecimalConverter(defaultLong),
BigDecimal.class);
}
/**
* The message resources for this package.
*/
protected static MessageResources messages =
MessageResources.getMessageResources("org.apache.struts.actions.LocalStrings");
/**
* The set of Method objects we have introspected for this class, keyed by
* method name. This collection is populated as different methods are
* called, so that introspection needs to occur only once per method name.
*/
protected HashMap<String, Method> methods = new HashMap<String, Method>();
/**
* The set of argument type classes for the reflected method call. These are
* the same for all calls, so calculate them only once.
*/
protected Class[] types = { ActionMapping.class, ActionForm.class,
Document.class, HttpServletRequest.class,
HttpServletResponse.class };
/**
* Process the specified HTTP request, and create the corresponding HTTP
* response (or forward to another web component that will create it).
* Return an <code>ActionForward</code> instance describing where and how
* control should be forwarded, or <code>null</code> if the response has
* already been completed.
*
* @param mapping
* The ActionMapping used to select this instance
* @param form
* The optional ActionForm bean for this request (if any)
* @param request
* The HTTP request we are processing
* @param response
* The HTTP response we are creating
*
* @exception Exception
* if an exception occurs
*/
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
response.setContentType("text/html; charset=UTF-8");
ExceptionDisplayDTO expDTO = null;
try {
Document doc = createDocumentFromRequest(request);
/*
* 这里直接调用mapping的parameter配置
*/
String actionMethod = mapping.getParameter();
/*
* 校验配置的方法是否正确、有效
*/
isValidMethod(actionMethod);
return dispatchMethod(mapping, form, doc, request,
response, actionMethod);
} catch (BaseAppException ex) {
expDTO = handlerException(request, response, ex);
} catch (Exception ex) {
ExceptionUtil.logException(this.getClass(), ex);
renderText(response,"[Error :对不起,系统出现错误了,
请向管理员报告以下异常信息./n" + ex.getMessage() + "]");
request.setAttribute(Globals.ERRORMSG, "对不起,
系统出现错误了,请向管理员报告以下异常信息./n" + ex.getMessage());
expDTO = handlerException(request,response, ex);
} finally {
expDisplayDetails.set(null);
}
return null == expDTO ? null : (expDTO.getActionForwardName() ==
null ? null : mapping.findForward(expDTO.getActionForwardName()));
}
/**
* 直接输出纯字符串
*/
public void renderText(HttpServletResponse response, String text) {
PrintWriter out = null;
try {
out = response.getWriter();
response.setContentType("text/plain;charset=UTF-8");
out.write(text);
} catch (IOException e) {
log.error(e);
} finally {
if (out != null) {
out.flush();
out.close();
out = null;
}
}
}
/**
* 直接输出纯HTML
*/
public void renderHtml(HttpServletResponse response, String text) {
PrintWriter out = null;
try {
out = response.getWriter();
response.setContentType("text/html;charset=UTF-8");
out.write(text);
} catch (IOException e) {
log.error(e);
} finally {
if (out != null) {
out.flush();
out.close();
out = null;
}
}
}
/**
* 直接输出纯XML
*/
public void renderXML(HttpServletResponse response, String text) {
PrintWriter out = null;
try {
out = response.getWriter();
response.setContentType("text/xml;charset=UTF-8");
out.write(text);
} catch (IOException e) {
log.error(e);
} finally {
if (out != null) {
out.flush();
out.close();
out = null;
}
}
}
/**
* 异常处理
* @param request
* @param out
* @param ex
* @return ExceptionDisplayDTO异常描述对象
*/
private ExceptionDisplayDTO handlerException(HttpServletRequest
request,HttpServletResponse response, Exception ex) {
ExceptionDisplayDTO expDTO = (ExceptionDisplayDTO)
expDisplayDetails.get();
if (null == expDTO) {
expDTO = new ExceptionDisplayDTO(null,this.getClass().getName());
}
IExceptionHandler expHandler =
ExceptionHandlerFactory.getInstance().create();
ExceptionDTO exDto = expHandler.handleException(expDTO.getContext(), ex);
request.setAttribute("ExceptionDTO", exDto);
renderText(response,"[Error:" + (exDto == null ?
"ExceptionDTO is null,请检查expinfo.xml配置文件." : exDto.getMessageCode())
+ "]");
return expDTO;
}
private void isValidMethod(String actionMethod) throws MappingConfigException {
if (actionMethod == null || "execute".equals(actionMethod) ||
"perform".equals(actionMethod)) {
log.error("[BaseDispatchAction->error] parameter = " + actionMethod);
expDisplayDetails.set(new ExceptionDisplayDTO(null,
"MappingConfigException"));
throw new MappingConfigException("对不起,
配置的方法名不能为 " + actionMethod);
}
}
/**
* 解析xml流
* @param request
* @return Document对象
*/
protected static Document createDocumentFromRequest(HttpServletRequest request)
throws Exception {
try {
request.setCharacterEncoding("UTF-8");
Document document = null;
SAXReader reader = new SAXReader();
document = reader.read(request.getInputStream());
return document;
} catch (Exception ex) {
log.warn("TIPS:没有提交获取XML格式数据流! ");
return null;
}
}
/**
* Dispatch to the specified method.
*
* @since Struts 1.1
*/
protected ActionForward dispatchMethod(ActionMapping mapping,
ActionForm form, Document doc,HttpServletRequest request,
HttpServletResponse response, String name) throws Exception {
Method method = null;
try {
method = getMethod(name);
} catch (NoSuchMethodException e) {
String message = messages.getMessage("dispatch.method",
mapping.getPath(), name);
log.error(message, e);
expDisplayDetails.set(new ExceptionDisplayDTO(null,
"MappingConfigException"));
throw new MappingConfigException(message, e);
}
ActionForward forward = null;
try {
Object args[] = { mapping, form, doc, request, response };
log.debug("[execute-begin] -> " + mapping.getPath() + "->
[" + clazz.getName() + "->" + name + "]");
forward = (ActionForward) method.invoke(this, args);
log.debug(" [execute-end] -> " + (null == forward ? "
use ajax send to html/htm" : forward.getPath()));
} catch (ClassCastException e) {
String message = messages.getMessage("dispatch.return",
mapping.getPath(), name);
log.error(message, e);
throw new BaseAppException(message, e);
} catch (IllegalAccessException e) {
String message = messages.getMessage("dispatch.error",
mapping.getPath(), name);
log.error(message, e);
throw new BaseAppException(message, e);
} catch (InvocationTargetException e) {
Throwable t = e.getTargetException();
String message = messages.getMessage("dispatch.error",
mapping.getPath(), name);
throw new BaseAppException(message, t);
}
return (forward);
}
/**
* Introspect the current class to identify a method of the specified name
* that accepts the same parameter types as the <code>execute</code>
* method does.
*
* @param name
* Name of the method to be introspected
*
* @exception NoSuchMethodException
* if no such method can be found
*/
protected Method getMethod(String name) throws NoSuchMethodException {
synchronized (methods) {
Method method = (Method) methods.get(name);
if (method == null) {
method = clazz.getMethod(name, types);
methods.put(name, method);
}
return (method);
}
}
/**
* 返回spring bean对象
* @param name Spring Bean的名称
* @exception BaseAppException
*/
protected Object getSpringBean(String name) throws BaseAppException {
if (ctx == null) {
ctx = WebApplicationContextUtils.getWebApplicationContext
(this.getServlet().getServletContext());
}
Object bean = null;
try {
bean = ctx.getBean(name);
} catch (BeansException ex) {
throw new NoSuchBeanConfigException("对不起,您没有配置名为:"
+ name + "的bean。请检查配置文件!", ex.getRootCause());
}
if (null == bean) {
throw new NoSuchBeanConfigException("对不起,您没有配置名为:"
+ name + "的bean。请检查配置文件!");
}
return bean;
}
}