Package org.eweb4j.mvc.action

Source Code of org.eweb4j.mvc.action.ActionExecution

package org.eweb4j.mvc.action;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase.InvalidContentTypeException;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.eweb4j.cache.ActionConfigBeanCache;
import org.eweb4j.cache.SingleBeanCache;
import org.eweb4j.config.ConfigConstant;
import org.eweb4j.config.Log;
import org.eweb4j.config.LogFactory;
import org.eweb4j.config.bean.ConfigBean;
import org.eweb4j.config.bean.UploadConfigBean;
import org.eweb4j.ioc.IOC;
import org.eweb4j.mvc.ActionMethod;
import org.eweb4j.mvc.Context;
import org.eweb4j.mvc.MIMEType;
import org.eweb4j.mvc.ParamUtil;
import org.eweb4j.mvc.action.annotation.Ioc;
import org.eweb4j.mvc.action.annotation.Singleton;
import org.eweb4j.mvc.action.annotation.Transactional;
import org.eweb4j.mvc.config.ActionClassCache;
import org.eweb4j.mvc.config.MVCConfigConstant;
import org.eweb4j.mvc.config.bean.ActionConfigBean;
import org.eweb4j.mvc.config.bean.ResultConfigBean;
import org.eweb4j.mvc.interceptor.After;
import org.eweb4j.mvc.interceptor.Before;
import org.eweb4j.mvc.interceptor.InterExecution;
import org.eweb4j.mvc.upload.Upload;
import org.eweb4j.mvc.upload.UploadFile;
import org.eweb4j.mvc.validator.ValidateExecution;
import org.eweb4j.mvc.validator.annotation.DateFormat;
import org.eweb4j.orm.dao.DAO;
import org.eweb4j.orm.dao.DAOFactory;
import org.eweb4j.orm.dao.DAOImpl;
import org.eweb4j.orm.dao.cascade.CascadeDAO;
import org.eweb4j.orm.dao.delete.DeleteDAO;
import org.eweb4j.orm.dao.insert.InsertDAO;
import org.eweb4j.orm.dao.select.DivPageDAO;
import org.eweb4j.orm.dao.select.SearchDAO;
import org.eweb4j.orm.dao.select.SelectDAO;
import org.eweb4j.orm.dao.update.UpdateDAO;
import org.eweb4j.orm.jdbc.transaction.Trans;
import org.eweb4j.orm.jdbc.transaction.Transaction;
import org.eweb4j.util.ClassUtil;
import org.eweb4j.util.FileUtil;
import org.eweb4j.util.JsonConverter;
import org.eweb4j.util.ReflectUtil;
import org.eweb4j.util.StringUtil;
import org.eweb4j.util.xml.BeanXMLUtil;
import org.eweb4j.util.xml.XMLWriter;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;

/**
* Action 执行器
*
* @author weiwei
* @since 1.b.8
*
*/
public class ActionExecution {

  private static Log log = LogFactory.getMVCLogger(ActionExecution.class);

  // 要执行的Action方法
  private Method method;
  private Field[] fields;
 
  private Context context;

  private Object actionObject;
  private Object retn;

  private ReflectUtil ru;

  // 验证器
  private void handleValidator() throws Exception {

    this.context.setValidation(ValidateExecution.checkValidate(context.getActionConfigBean().getValidator(), context.getQueryParamMap(), context.getRequest()));
  }

  public ActionExecution(String uri, String httpMethod, Context context) {
    this.context = context;
    this.context.setUri(uri);
    this.context.setHttpMethod(httpMethod);
    this.context.setQueryParamMap(new HashMap<String, String[]>());
    this.context.setPathParamMap(new HashMap<String, String[]>());
  }

  public boolean findAction() throws Exception {
    // URL参数
    Map<String, List<?>> pathParams = null;
    if (ActionConfigBeanCache.containsKey(this.context.getUri())|| (pathParams = ActionConfigBeanCache.getByMatches(this.context.getUri(), this.context.getHttpMethod())) != null) {

      // 处理形如" /xxx/{id}/{name} "的URI
      if (pathParams != null && pathParams.containsKey("mvcBean")) {
        // 根据Url配置的UrlParam获取参数值
        this.context.setActionConfigBean((ActionConfigBean) pathParams.get("mvcBean").get(0));

        this.context.getPathParamMap().putAll(ParamUtil.getPathParamMap(pathParams));
        this.context.getQueryParamMap().putAll(this.context.getPathParamMap());
      } else
        this.context.setActionConfigBean(ActionConfigBeanCache.get(this.context.getUri()));

      // 将request的请求参数转到另外一个map中去
      this.context.getQueryParamMap().putAll(ParamUtil.copyReqParams(this.context.getRequest()));

      if (this.context.getActionConfigBean() != null)
        return true;
    }

    return false;
  }

  private Object initPojo() throws Exception {
    Class<?> clazz = ActionClassCache.get(this.context.getActionConfigBean().getClazz());
    Annotation singletonAnn = clazz.getAnnotation(Singleton.class);
    if (singletonAnn != null) {
      this.actionObject = SingleBeanCache.get(clazz);
      if (this.actionObject == null) {
        this.actionObject = clazz.newInstance();
        SingleBeanCache.add(clazz, this.actionObject);
      }
    } else
      this.actionObject = clazz.newInstance();

    ru = new ReflectUtil(this.actionObject);

    return this.actionObject;
  }

  // IOC,注入对象到pojo
  private void injectIocBean() throws Exception {
    fields = ru.getFields();
    if (fields == null)
      return;

    for (Field f : fields) {
      Class<?> type = f.getType();

      Ioc ioc = f.getAnnotation(Ioc.class);
      if (ioc == null)
        continue;
      String beanId = "";
      if (ioc.value().trim().length() == 0)
        beanId = type.getSimpleName();
      else
        beanId = StringUtil.parsePropValue(ioc.value());

      Method setter = ru.getSetter(f.getName());
      if (setter == null)
        continue;

      setter.invoke(this.actionObject, IOC.getBean(beanId));
    }
  }

  private void exeActionLog() {
    StringBuilder sb = new StringBuilder();
    sb.append("execute ").append(this.context.getUri()).append(ActionMethod.CON)
      .append(this.context.getHttpMethod()).append("[Action]; ");

    log.debug(sb.toString());
  }

  private Object[] assemParams(Class<?>[] paramTypes, Annotation[][] paramAnns)throws Exception {
    Object[] params = new Object[paramTypes.length];
    int pathParamIndex = 0;
    for (int i = 0; i < paramTypes.length; ++i) {
      Annotation[] anns = paramAnns[i];
      Class<?> paramClass = paramTypes[i];
      String[] paramValue = null;
      // ------------------------------------------------------
      // 通过给定class 获取对应的ActionContextObj
      if (Context.class.isAssignableFrom(paramClass)) {
        params[i] = this.context;
        continue;
      }

      if (HttpServletRequest.class.isAssignableFrom(paramClass)) {
        params[i] = this.context.getRequest();
        continue;
      }

      if (HttpServletResponse.class.isAssignableFrom(paramClass)) {
        params[i] = this.context.getResponse();
        continue;
      }

      if (PrintWriter.class.isAssignableFrom(paramClass)) {
        params[i] = this.context.getWriter();
        continue;
      }

      if (ServletOutputStream.class.isAssignableFrom(paramClass)) {
        params[i] = this.context.getOut();
        continue;
      }

      if (HttpSession.class.isAssignableFrom(paramClass)) {
        params[i] = this.context.getSession();
        continue;
      }

      if (ActionProp.class.isAssignableFrom(paramClass)) {
        if (this.context.getActionProp() == null)
          this.context.setActionProp(new ActionProp(this.actionObject.getClass().getName()));

        params[i] = this.context.getActionProp();
        continue;
      }

      if (Validation.class.isAssignableFrom(paramClass)) {
        params[i] = this.context.getValidation();
        continue;
      }

      if (QueryParams.class.isAssignableFrom(paramClass)) {
        params[i] = this.context.getQueryParams();
        continue;
      }

      if (DAO.class.isAssignableFrom(paramClass)) {
        params[i] = new DAOImpl("");
        continue;
      }

      if (InsertDAO.class.isAssignableFrom(paramClass)) {
        params[i] = DAOFactory.getInsertDAO();
        continue;
      }

      if (DeleteDAO.class.isAssignableFrom(paramClass)) {
        params[i] = DAOFactory.getDeleteDAO();
        continue;
      }

      if (UpdateDAO.class.isAssignableFrom(paramClass)) {
        params[i] = DAOFactory.getUpdateDAO();
        continue;
      }

      if (SelectDAO.class.isAssignableFrom(paramClass)) {
        params[i] = DAOFactory.getSelectDAO();
        continue;
      }

      if (DivPageDAO.class.isAssignableFrom(paramClass)) {
        params[i] = DAOFactory.getDivPageDAO();
        continue;
      }

      if (SearchDAO.class.isAssignableFrom(paramClass)) {
        params[i] = DAOFactory.getSearchDAO();
        continue;
      }

      if (CascadeDAO.class.isAssignableFrom(paramClass)) {
        params[i] = DAOFactory.getCascadeDAO();
        continue;
      }

      PathParam pathParamAnn = this.getPathParamAnn(anns);
            if (pathParamAnn != null) {
                paramValue = this.getPathParamValue(pathParamAnn.value());
                params[i] = ClassUtil.getParamVal(paramClass, paramValue[0]);
                continue;
            }

      QueryParam queryParamAnn = this.getQueryParamAnn(anns);

            // 视图模型
            if (queryParamAnn == null && Map.class.isAssignableFrom(paramClass)) {
                    params[i] = this.context.getModel();
                    continue;
            }

            if (queryParamAnn != null) {
              final String fieldName = queryParamAnn.value();
        if (File.class.isAssignableFrom(paramClass)) {
          if (!this.context.getUploadMap().containsKey(fieldName))
            continue;
          List<UploadFile> list = this.context.getUploadMap().get(fieldName);
          if (list == null || list.isEmpty())
            continue;
         
          UploadFile uploadFile = list.get(0);
          File file = uploadFile.getTmpFile();
          params[i] = file;
         
          continue;
        }
       
        if (File[].class.isAssignableFrom(paramClass)){
          if (!this.context.getUploadMap().containsKey(fieldName))
            continue;
          List<UploadFile> list = this.context.getUploadMap().get(fieldName);
          if (list == null || list.isEmpty())
            continue;
          File[] files = new File[list.size()];
          for (int j = 0; j < files.length; j++)
            files[j] = list.get(j).getTmpFile();
         
          params[i] = files;
        }
       
        if (UploadFile.class.isAssignableFrom(paramClass)) {
          if (!this.context.getUploadMap().containsKey(fieldName))
            continue;
          List<UploadFile> list = this.context.getUploadMap().get(fieldName);
          if (list == null || list.isEmpty())
            continue;
         
          UploadFile uploadFile = list.get(0);
          params[i] = uploadFile;
         
          continue;
        }
       
        if (UploadFile[].class.isAssignableFrom(paramClass)){
          if (!this.context.getUploadMap().containsKey(fieldName))
            continue;
          List<UploadFile> list = this.context.getUploadMap().get(fieldName);
          if (list == null || list.isEmpty())
            continue;
         
          params[i] = list.toArray(new UploadFile[]{});
        }
       
        String defaultValue = null;
        DefaultValue defaultValueAnn = this.getDefaultValueAnn(anns);
        if (defaultValueAnn != null)defaultValue = defaultValueAnn.value();
 
        paramValue = this.getQueryParamValue(fieldName, defaultValue);
 
        if (java.util.Date.class.isAssignableFrom(paramClass)) {
          params[i] = this.getDateParam(anns, paramValue[0]);
          continue;
        }
 
        String startName = fieldName;
        if (ClassUtil.isPojo(paramClass)) {
          params[i] = this.injectParam2Pojo(paramClass, startName);
          continue;
        }
 
        if (Map.class.isAssignableFrom(paramClass)) {
          params[i] = this.injectParam2Map(startName);
          continue;
        }
 
        if (paramClass.isArray())
          params[i] = ClassUtil.getParamVals(paramClass, paramValue);
        else
          params[i] = ClassUtil.getParamVal(paramClass, paramValue[0]);
            } else {
        // 如果是基本数据类型,则按照排序进行注入
        paramValue = this.getPathParamValue(this.context.getActionConfigBean().getPathParams()[pathParamIndex]);
        params[i] = ClassUtil.getParamVal(paramClass, paramValue[0]);
        pathParamIndex++;
        continue;
      }
    }

    return params;
  }

  private Method getFirstMethd(Method[] methods) {
    Method m = methods[0];
    if (methods.length == 1)
      return m;

    // 如果含有两个或以上同名的方法,优先拿到被@Path注解的第一个方法
    for (Method mm : methods) {
      Path p = mm.getAnnotation(Path.class);
      if (p == null)
        continue;

      m = mm;
      break;
    }

    return m;
  }

  private String[] getQueryParamValue(String paramName, String defaultValue) {
    String[] paramValue = this.context.getQueryParamMap().get(paramName);

    return getParamValue(paramValue, defaultValue);
  }

  private String[] getPathParamValue(String pathParamName) {
    String[] paramValue = this.context.getPathParamMap().get(pathParamName);

    return getParamValue(paramValue, null);
  }

  private String[] getParamValue(String[] paramValue, String defaultValue) {
    if (paramValue == null || paramValue.length == 0 || paramValue[0] == null) {
      if (defaultValue != null)
        paramValue = new String[] { defaultValue };
      else
        paramValue = new String[] { "" };
    }

    return paramValue;
  }

  private Date getDateParam(Annotation[] anns, String paramValue)
      throws Exception {
    DateFormat dateAnn = null;
    for (Annotation a : anns) {
      if (a == null)
        continue;

      if (!a.annotationType().isAssignableFrom(DateFormat.class))
        continue;

      dateAnn = (DateFormat) a;
      break;
    }

    String pattern = "yyyy-MM-dd HH:mm:ss";
    if (dateAnn != null)
      pattern = dateAnn.value();

    SimpleDateFormat sdf = new SimpleDateFormat(pattern);
    return sdf.parse(paramValue);
  }

  private Object injectParam2Pojo(Class<?> paramClass, String startName)
      throws Exception {
    Object paramObj = paramClass.newInstance();
    ReflectUtil ru = new ReflectUtil(paramObj);
    this.injectActionCxt2Pojo(ru);
    // 注入mvc action 请求参数
    ParamUtil.injectParam(this.context, ru, startName);

    return paramObj;
  }

  private Object injectParam2Map(String startName) throws Exception {
    Map<String, Object> map = new HashMap<String, Object>();
    ReflectUtil ru = new ReflectUtil(map);
    this.injectActionCxt2Pojo(ru);
    // 注入mvc action 请求参数
    ParamUtil.injectParam(this.context, ru, startName);

    return map;
  }

  private PathParam getPathParamAnn(Annotation[] anns) {
    for (Annotation a : anns) {
      if (a == null)
        continue;

      if (!a.annotationType().isAssignableFrom(PathParam.class))
        continue;

      return (PathParam) a;
    }

    return null;
  }

  private QueryParam getQueryParamAnn(Annotation[] anns) {
    for (Annotation a : anns) {
      if (a == null)
        continue;

      if (!a.annotationType().isAssignableFrom(QueryParam.class))
        continue;

      return (QueryParam) a;
    }

    return null;
  }
 
  private DefaultValue getDefaultValueAnn(Annotation[] anns) {
    for (Annotation a : anns) {
      if (a == null)
        continue;

      if (!a.annotationType().isAssignableFrom(DefaultValue.class))
        continue;

      return (DefaultValue) a;
    }

    return null;
  }

  private void handleDownload(File file) throws Exception{
    if (file.exists()){
      HttpServletResponse response = this.context.getResponse();
      String filename = URLEncoder.encode(file.getName(), "utf-8");
            response.reset();
            response.setContentType("application/x-msdownload");
            response.addHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
            int fileLength = (int) file.length();
            response.setContentLength(fileLength);
            /*如果文件长度大于0*/
            if (fileLength != 0) {
                /*创建输入流*/
                InputStream inStream = new FileInputStream(file);
                byte[] buf = new byte[4096];
                /*创建输出流*/
                ServletOutputStream servletOS = response.getOutputStream();
                int readLength;
                while (((readLength = inStream.read(buf)) != -1)) {
                    servletOS.write(buf, 0, readLength);
                }
                inStream.close();
                servletOS.flush();
                servletOS.close();
            }
    }
  }
  private void handleResult() throws Exception {

    this.exeActionLog();

    if (retn == null)
      return;
    String baseUrl = (String) this.context.getServletContext().getAttribute(MVCConfigConstant.BASE_URL_KEY);
    if (File.class.isAssignableFrom(retn.getClass())){
      File file = (File)retn;
      this.handleDownload(file);
      return ;
    }else if(File[].class.isAssignableFrom(retn.getClass())){
      File[] files = (File[])retn;
     
      String fileName = StringUtil.getNowTime("yyyyMMddHHmmss")+ "_" + "download.zip";
     
      HttpServletResponse resp = this.context.getResponse();
      resp.reset();
      resp.setContentType("application/zip")
            resp.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
           
          ServletOutputStream outputStream = resp.getOutputStream()
          ZipOutputStream zip = new ZipOutputStream(outputStream)
        
          for (File file :files){
            byte[] b = new byte[1024]
             int len; 
            zip.putNextEntry(new ZipEntry(file.getName()))
            FileInputStream fis = new FileInputStream(file)
             while ((len = fis.read(b)) != -1) { 
                 zip.write(b, 0, len)
            
            
             fis.close();
          }
           
          zip.flush()
          zip.close()
          outputStream.flush()
     
      return;
    }
   
    String re = null;

    String mimeType = MIMEType.JSON;
    List<String> produces = this.context.getActionConfigBean().getProduces();
    if (produces != null && produces.size() > 0)
      for (String produce : produces) {
        mimeType = produce;
        break;
      }

    if (!String.class.isAssignableFrom(retn.getClass())) {
      if (this.context.getWriter() == null)
        this.context.setWriter(this.context.getResponse().getWriter());

      if (MIMEType.JSON.equals(mimeType) || "json".equalsIgnoreCase(mimeType)) {
        this.context.getResponse().setContentType(MIMEType.JSON);
        this.context.getWriter().print(JsonConverter.convert(retn));
      } else if (MIMEType.XML.equals(mimeType) || "xml".equalsIgnoreCase(mimeType)) {
        Class<?> cls = retn.getClass();
        if (Collection.class.isAssignableFrom(cls)) {
          Class<?> _cls = ClassUtil.getPojoClass(this.method);
          if (_cls != null)
            cls = _cls;
        }

        XMLWriter writer = BeanXMLUtil.getBeanXMLWriter(retn);
        writer.setCheckStatck(true);
        writer.setSubNameAuto(true);
        writer.setClass(cls);
        writer.setRootElementName(null);
        this.context.getResponse().setContentType(MIMEType.XML);
        this.context.getWriter().print(writer.toXml());
      } else {
        this.context.getWriter().print("@Produces 注解暂时不支持JSON 、XML以外的渲染技术");
      }
     
      this.context.getWriter().flush();
      return;
    }

    re = String.valueOf(retn);

    for (Field f : fields) {
      Method getter = ru.getGetter(f.getName());
      if (getter == null)
        continue;

      String name = f.getName();
      if (this.context.getModel().containsKey(name))
        continue;
     
      this.context.getModel().put(name, getter.invoke(actionObject));
    }

    this.context.getModel().put(MVCConfigConstant.BASE_URL_KEY, baseUrl);

    // 客户端重定向
    if (re.startsWith(RenderType.REDIRECT + ":")) {
      String url = re.substring((RenderType.REDIRECT + ":").length());
      String location = url;

      this.context.getResponse().sendRedirect(StringUtil.replaceChinese2Utf8(location));

      return;
    } else if (re.startsWith(RenderType.ACTION + ":")) {
      String path = re.substring((RenderType.ACTION + ":").length());
      // ACTION 重定向
      handleActionRedirect(context, path, baseUrl);

      return;
    } else if (re.startsWith(RenderType.OUT + ":")) {
      String location = re.substring((RenderType.OUT + ":").length());
      this.context.getWriter().print(location);
      this.context.getWriter().flush();

      return;
    } else if (re.startsWith(RenderType.FORWARD + ":")) {
      String location = re.substring((RenderType.FORWARD + ":").length());
      HttpServletRequest request = this.context.getRequest();
      request.setAttribute(MVCConfigConstant.REQ_PARAM_MAP_NAME, this.context.getQueryParamMap());

      for (Iterator<Entry<String, Object>> it = this.context.getModel().entrySet().iterator(); it.hasNext(); ) {
        Entry<String, Object> entry = it.next();
        request.setAttribute(entry.getKey(), entry.getValue());
      }

      // 服务端跳转
      request.getRequestDispatcher(MVCConfigConstant.FORWARD_BASE_PATH + location).forward(request, this.context.getResponse());

      return;
    } else if (re.startsWith(RenderType.FREEMARKER + ":")) {
      String location = re.substring((RenderType.FREEMARKER + ":").length());
      // FreeMarker 渲染
      Configuration cfg = new Configuration();
      // 指定模板从何处加载的数据源,这里设置成一个文件目录。
      cfg.setDirectoryForTemplateLoading(new File(ConfigConstant.ROOT_PATH + MVCConfigConstant.FORWARD_BASE_PATH));
      // 指定模板如何检索数据模型
      cfg.setObjectWrapper(new DefaultObjectWrapper());
      cfg.setDefaultEncoding("utf-8");

      Template template = cfg.getTemplate(location);
      template.setEncoding("utf-8");

      template.process(this.context.getModel(), this.context.getWriter());

      return;
    } else {
      List<ResultConfigBean> results = this.context.getActionConfigBean().getResult();

      if (results == null || results.size() == 0) {
        this.context.getWriter().print(retn);
        this.context.getWriter().flush();
        return;
      }

      boolean isOut = true;
      for (ResultConfigBean r : results) {
        if (!"_props_".equals(r.getName()) && !r.getName().equals(re)
            && !"".equals(re)){
          continue;
        }
       
        isOut = false;
        String type = r.getType();
        String location = r.getLocation();
        if (RenderType.REDIRECT.equalsIgnoreCase(type)) {
          this.context.getResponse().sendRedirect(StringUtil.replaceChinese2Utf8(location));
         
          return ;
        } else if (RenderType.FORWARD.equalsIgnoreCase(type)) {
          HttpServletRequest request = this.context.getRequest();
          request.setAttribute(MVCConfigConstant.REQ_PARAM_MAP_NAME, this.context.getQueryParamMap());

          fields = ru.getFields();
          if (fields == null)
            return;

          for (Iterator<Entry<String, Object>> it = this.context.getModel().entrySet()
              .iterator(); it.hasNext();) {
            Entry<String, Object> entry = it.next();
            request.setAttribute(entry.getKey(), entry.getValue());
          }
          // 服务端跳转
          request.getRequestDispatcher(MVCConfigConstant.FORWARD_BASE_PATH + location).forward(request, this.context.getResponse());
         
          return ;
        } else if (RenderType.FREEMARKER.equalsIgnoreCase(type)) {
          // FreeMarker 渲染
          Configuration cfg = new Configuration();
          // 指定模板从何处加载的数据源,这里设置成一个文件目录。
          cfg.setDirectoryForTemplateLoading(new File(ConfigConstant.ROOT_PATH + MVCConfigConstant.FORWARD_BASE_PATH));
          // 指定模板如何检索数据模型
          cfg.setObjectWrapper(new DefaultObjectWrapper());
          cfg.setDefaultEncoding("utf-8");

          Template template = cfg.getTemplate(location);
          template.setEncoding("utf-8");

          template.process(this.context.getModel(), this.context.getWriter());
         
          return ;
        } else if (RenderType.ACTION.equalsIgnoreCase(type)) {
          // ACTION 重定向
          handleActionRedirect(context, location, baseUrl);

          return ;
        } else if (RenderType.OUT.equalsIgnoreCase(type)
            || location.trim().length() == 0) {
          this.context.getWriter().print(location);
          this.context.getWriter().flush();
         
          return ;
        }
      }
     
      if (isOut){
        this.context.getWriter().print(retn);
        this.context.getWriter().flush();
      }
    }

  }

  public static void handleActionRedirect(Context context, String path, String baseUrl)
      throws IOException {
    String method;
    String location;
    if (!path.contains("@")) {
      method = HttpMethod.GET;
      location = path;
    } else {
      int lastIndex = path.indexOf("@") + 1;
      method = path.substring(lastIndex);
      location = path.substring(0, lastIndex - 1);
    }
    StringBuilder sb = new StringBuilder("");
    String param = null;
    if (path.contains("?")) {
      int lastIndex2 = path.indexOf("?") + 1;
      param = path.substring(lastIndex2);
      String[] params = param.split("&");
      for (String para : params) {
        String[] p = para.split("=");
        sb.append(String.format("<input name='%s' value='%s' />", p[0], p[1]));
      }

      method = method.substring(0, method.indexOf("?"));
    }

    if (HttpMethod.GET.equalsIgnoreCase(method)) {
      String pa = param == null ? "" : "?" + StringUtil.replaceChinese2Utf8(param);
      context.getResponse().sendRedirect(baseUrl + location + pa);
      return;
    }

    String _method = "";
    if (HttpMethod.PUT.equalsIgnoreCase(method) || HttpMethod.DELETE.equalsIgnoreCase(method)) {
      _method = new String(method);
      method = HttpMethod.POST;
    }

    String action = baseUrl + location;
    // 构造一个Form表单模拟客户端发送新的Action请求
    String format = "<form id='ACTION_REDIRECT_FORM' action='%s' method='%s' ><input name='_method' value='%s' />%s<input type='submit' /></form>";
    String form = String.format(format, action, method, _method, sb.toString());
    String js = "<script>document.getElementById('ACTION_REDIRECT_FORM').submit();</script>";
    context.getWriter().print(form + js);
  }

  private void handleUpload() throws Exception{
    ConfigBean cb = (ConfigBean) SingleBeanCache.get(ConfigConstant.CONFIGBEAN_ID);
   
    Upload upload = method.getAnnotation(Upload.class);
    UploadConfigBean ucb = cb.getMvc().getUpload();
    String tmpDir = ucb.getTmp();
    int memoryMax = StringUtil.strToInt(StringUtil.parseFileSize(ucb.getMaxMemorySize())+"");
    long sizeMax = StringUtil.parseFileSize(ucb.getMaxRequestSize());
    //String[] suffix = ucb.getSuffix().split(",");
    if (upload != null){
      if (upload.tmpDir().trim().length() > 0)
        tmpDir = upload.tmpDir();
     
      if (upload.maxMemorySize().trim().length() > 0)
        memoryMax =  StringUtil.strToInt(StringUtil.parseFileSize(upload.maxMemorySize())+"");
     
      if (upload.maxRequestSize().trim().length() > 0)
        sizeMax = StringUtil.parseFileSize(upload.maxRequestSize());
     
      //if (upload.suffix().length > 0)
        //suffix = upload.suffix();
    }
   
    if (tmpDir.trim().length() == 0)
      tmpDir = "${RootPath}"+File.separator+"WEB-INF"+File.separator+"tmp";
   
    tmpDir = tmpDir.replace("${RootPath}", ConfigConstant.ROOT_PATH);
   
    DiskFileItemFactory factory = new DiskFileItemFactory();
    factory.setSizeThreshold(memoryMax);
    factory.setRepository(new File(tmpDir));
   
    ServletFileUpload _upload = new ServletFileUpload(factory);
    _upload.setSizeMax(sizeMax);
    if (upload != null){
      Class<?> clazz = upload.listener();
      if (!void.class.isAssignableFrom(clazz) && ProgressListener.class.isAssignableFrom(clazz))
        _upload.setProgressListener((ProgressListener) clazz.newInstance());
    }
   
    try{
      List<FileItem> items = _upload.parseRequest(this.context.getRequest());
      Iterator<FileItem> it = items.iterator();
      while (it.hasNext()){
        FileItem item = it.next();
        String fieldName = item.getFieldName();
        if (item.isFormField()){
          String value = item.getString();
          this.context.getQueryParamMap().put(fieldName, new String[]{value});
        } else {
          String fileName = item.getName();
          if (fileName == null || fileName.trim().length() == 0)
            continue;
         
          String stamp = StringUtil.getNowTime("yyyyMMddHHmmss");
          File tmpFile = new File(tmpDir + File.separator + stamp + "_" + fileName);
          item.write(tmpFile);
         
          UploadFile uploadFile = new UploadFile(tmpFile, fileName, fieldName, item.getSize(), item.getContentType());
         
          if (this.context.getUploadMap().containsKey(fieldName)){
            this.context.getUploadMap().get(fieldName).add(uploadFile);
          }else{
            List<UploadFile> uploads = new ArrayList<UploadFile>();
            uploads.add(uploadFile);
            this.context.getUploadMap().put(fieldName, uploads);
          }
        }
      }
    }catch(InvalidContentTypeException e){
     
    }
  }
 
  /**
   * 执行Action
   *
   * @param methodName
   * @throws Exception
   */
  private void excuteMethod(String methodName) throws Exception{

    /* 对于外部配置的前置拦截器,方法体内的前置拦截器较后执行  */
    Before before = method.getAnnotation(Before.class);
    if (before != null){
      InterExecution before_interExe = new InterExecution("before", context);
      before_interExe.execute(before.value());
      if (before_interExe.getError() != null){
        before_interExe.showErr();
        return ;
      }
    }
   
    boolean isTrans = false;
    if (method.getAnnotation(Transactional.class) != null)
      isTrans = true;
    else if (actionObject.getClass().getAnnotation(Transactional.class) != null)
      isTrans = true;

    Class<?>[] paramTypes = method.getParameterTypes();

    // 无参数运行方法
    if (paramTypes == null || paramTypes.length == 0) {
      // 无参数运行方法
      if (isTrans)
        Transaction.execute(new Trans() {
          @Override
          public void run(Object... args) throws Exception {
            retn = method.invoke(actionObject);
          }
        }, "");
      else
        retn = method.invoke(actionObject);
    } else {
     
      Annotation[][] paramAnns = method.getParameterAnnotations();
      // 拿到方法所需要的参数
      final Object[] params = assemParams(paramTypes, paramAnns);

      // 带参数运行方法
      if (isTrans)
        Transaction.execute(new Trans() {
          @Override
          public void run(Object... args) throws Exception {
            retn = method.invoke(actionObject, params);
          }
        }, "");
      else
        retn = method.invoke(actionObject, params);
    }
  }

  private void injectActionCxt2Pojo(ReflectUtil ru) throws Exception {
    HttpServletRequest req = this.context.getRequest();
    HttpServletResponse res = this.context.getResponse();
    PrintWriter out = this.context.getWriter();
    HttpSession session = this.context.getSession();
    ActionProp actionProp = this.context.getActionProp();
    QueryParams queryParams = this.context.getQueryParams();
    for (String n : ru.getFieldsName()) {
      Method m = ru.getSetter(n);
      if (m == null)
        continue;

      Class<?> clazz = m.getParameterTypes()[0];
      if (Context.class.isAssignableFrom(clazz)) {
        m.invoke(ru.getObject(), this.context);
      } else if (HttpServletRequest.class.isAssignableFrom(clazz)) {
        m.invoke(ru.getObject(), req);
      } else if (HttpServletResponse.class.isAssignableFrom(clazz)) {
        m.invoke(ru.getObject(), res);
      } else if (PrintWriter.class.isAssignableFrom(clazz)) {
        m.invoke(ru.getObject(), out);
      } else if (ServletOutputStream.class.isAssignableFrom(clazz)) {
        m.invoke(ru.getObject(), this.context.getOut());
      } else if (HttpSession.class.isAssignableFrom(clazz)) {
        m.invoke(ru.getObject(), session);
      } else if (ActionProp.class.isAssignableFrom(clazz)) {
        if (actionProp == null)
          actionProp = new ActionProp(clazz.getName());

        this.context.setActionProp(actionProp);
        m.invoke(ru.getObject(), actionProp);
      } else if (QueryParams.class.isAssignableFrom(clazz)) {
        m.invoke(ru.getObject(), queryParams);
      } else if (Validation.class.isAssignableFrom(clazz)) {
        m.invoke(ru.getObject(), this.context.getValidation());
      } else {
        /* 如果找不到注入的类型,则尝试从IOC容器获取 */
        Object obj = IOC.getBean(n);
        if (obj != null)
          m.invoke(ru.getObject(), obj);
      }
    }
  }

  /**
   * 执行Action
   *
   * @throws Exception
   */
  public void execute() throws Exception {
    // 实例化pojo
    initPojo();

    // IOC注入对象到pojo中
    injectIocBean();

    // 注入框架mvc action 上下文环境
    this.injectActionCxt2Pojo(this.ru);
   
    if (IAction.class.isAssignableFrom(this.actionObject.getClass())) {
      // struts2风格
      IAction action = (IAction) actionObject;
      action.init(this.context);
      retn = action.execute();
      // 对Action执行返回结果的处理
      this.handleResult();
     
      return ;
    }
   
    String methodName = this.context.getActionConfigBean().getMethod();
    Method[] methods = ru.getMethods(methodName);
    if (methods == null || methods.length == 0)
      return;

    method = this.getFirstMethd(methods);
    if (method == null)
      return;
   
    // 执行验证器
    this.handleValidator();
    try{
      // upload files
      this.handleUpload();
     
      // 注入mvc action 请求参数
      ParamUtil.injectParam(this.context, this.ru, null);
 
      // execute the action method
      excuteMethod(methodName);
     
      /* 方法体内的后置拦截器先执行  */
      After after = method.getAnnotation(After.class);
      if (after != null){
        // 后置拦截器
        InterExecution after_interExe = new InterExecution("after", context);
        after_interExe.execute(after.value());
        if (after_interExe.getError() != null){
          after_interExe.showErr();
          return ;
        }
      }
     
      /* 外部配置的后置拦截器后执行 */
      InterExecution after_interExe = new InterExecution("after", this.context);// 7.后置拦截器
      if (after_interExe.findAndExecuteInter()) {
        after_interExe.showErr();
        return;
      }
     
      // 对Action执行返回结果的处理
      this.handleResult();
    }catch(Exception e){
      throw e;
    }finally{
      // Action方法执行之后,清空临时文件
      if (!this.context.getUploadMap().isEmpty())
        for (Iterator<Entry<String, List<UploadFile>>> it = this.context.getUploadMap().entrySet().iterator(); it.hasNext(); ){
          Entry<String, List<UploadFile>> en = it.next();
          if (en.getValue() == null)
            continue;
         
          for (UploadFile f : en.getValue()){
            FileUtil.deleteFile(f.getTmpFile());
        }
      }
    }
   
  }
}
TOP

Related Classes of org.eweb4j.mvc.action.ActionExecution

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.