Package org.eweb4j.mvc.action

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

package org.eweb4j.mvc.action;

import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import org.eweb4j.cache.ActionConfigBeanCache;
import org.eweb4j.cache.SingleBeanCache;
import org.eweb4j.config.LogFactory;
import org.eweb4j.ioc.IOC;
import org.eweb4j.mvc.Context;
import org.eweb4j.mvc.MIMEType;
import org.eweb4j.mvc.ParamUtil;
import org.eweb4j.mvc.action.annotation.DateFormat;
import org.eweb4j.mvc.action.annotation.Ioc;
import org.eweb4j.mvc.action.annotation.Singleton;
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.InterExecution;
import org.eweb4j.mvc.validator.ValidateExecution;
import org.eweb4j.util.ClassUtil;
import org.eweb4j.util.JsonConverter;
import org.eweb4j.util.ReflectUtil;
import org.eweb4j.util.StringUtil;

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

  private Context context;

  private Object actionObject;
  private Class<?> clazz;
  private Object retn;

  private ReflectUtil ru;

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

    Map<String, String> error = ValidateExecution.checkValidate(context
        .getMvcBean().getValidator(), context.getQueryParamMap(),
        context.getRequest());

    if (error != null && !error.isEmpty()) {
      ValidateExecution.showValidateError(context.getMvcBean()
          .getShowValErrorType(), error, context.getRequest(),
          context.getResponse());

      StringBuilder sb = new StringBuilder();
      sb.append("MVC:验证器发现了错误").append(error);

      LogFactory.getMVCLogger("INFO").write(sb.toString());
      return false;
    }

    return true;
  }

  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.setMvcBean((ActionConfigBean) pathParams.get(
            "mvcBean").get(0));

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

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

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

    return false;
  }

  private Object initPojo() throws Exception {
    clazz = ActionClassCache.get(this.context.getMvcBean().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 {
    Field[] 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("MVC:执行")
        .append(this.context.getUri() + "@"
            + this.context.getHttpMethod()).append("[Action];");
    LogFactory.getMVCLogger("INFO").write(sb.toString());
  }

  private Object[] assemParams(Class<?>[] paramTypes, Annotation[][] paramAnns)
      throws Exception {
    Object[] params = new Object[paramTypes.length];
    for (int i = 0; i < paramTypes.length; ++i) {
      Annotation[] anns = paramAnns[i];
      Class<?> paramClass = paramTypes[i];
      String[] paramValue = null;

      // ------------------------------------------------------
      // 通过给定class 获取对应的ActionContextObj
      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(clazz.getName()));

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

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

      if (ClassUtil.isPojo(paramClass)) {
        params[i] = this.injectParam2Pojo(paramClass);
        continue;
      }

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

      QueryParam queryParamAnn = this.getQueryParamAnn(anns);
      if (queryParamAnn == null)
        continue;

      paramValue = this.getQueryParamValue(queryParamAnn);

      if (java.util.Date.class.isAssignableFrom(paramClass)) {
        params[i] = this.getDateParam(anns, paramValue[0]);
        continue;
      }

      if (paramClass.isArray())
        params[i] = ClassUtil.getParamVals(paramClass, paramValue);
      else
        params[i] = ClassUtil.getParamVal(paramClass, paramValue[0]);
    }

    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(QueryParam paramAnn) {
    String[] paramValue = this.context.getQueryParamMap().get(
        paramAnn.value());

    return getParamValue(paramValue);
  }

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

    return getParamValue(paramValue);
  }

  private String[] getParamValue(String[] paramValue) {
    if (paramValue == null || paramValue.length == 0
        || paramValue[0] == null) {
      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) throws Exception {
    Object paramObj = paramClass.newInstance();
    this.injectActionCxt2Pojo(paramObj);
    // 注入mvc action 请求参数
    ParamUtil.injectParam(this.context.getQueryParamMap(), paramObj);

    return paramObj;
  }

  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 void handleResult() throws Exception {

    this.exeActionLog();

    if (retn == null)
      return;
    String re = null;

    String mimeType = null;
    List<String> produces = this.context.getMvcBean().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.getWriter().print(JsonConverter.convert(retn));
        this.context.getResponse().setContentType(MIMEType.JSON);
      } else {
        this.context.getWriter().print("暂时不支持JSON以外的视图渲染技术");
      }
      this.context.getWriter().flush();
      return;
    }

    re = String.valueOf(retn);

    // String contextPath = this.context.getRequest().getContextPath();
    String baseUrl = (String) this.context.getServletContext()
        .getAttribute(MVCConfigConstant.BASE_URL_KEY);
    List<ResultConfigBean> results = this.context.getMvcBean().getResult();
    if (results == null || results.size() == 0) {

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

        this.context.getResponse().sendRedirect(location);
      } else if (re.startsWith("action:")) {
        // ACTION 重定向
        String path = re.substring("action:".length());
        this.context.getResponse().sendRedirect(baseUrl + path);

      } else if (re.startsWith("out:") || re.trim().length() == 0) {
        String location = re.substring("out:".length());
        this.context.getWriter().print(location);
        this.context.getWriter().flush();
      } else if (re.startsWith("forward:")) {
        String location = re.substring("forward:".length());
        HttpServletRequest request = this.context.getRequest();
        request.setAttribute(MVCConfigConstant.REQ_PARAM_MAP_NAME,
            this.context.getQueryParamMap());
        // 服务端跳转
        request.getRequestDispatcher(
            MVCConfigConstant.FORWARD_BASE_PATH + location).forward(
            request, this.context.getResponse());
      } else {
        this.context.getWriter().print(retn);
        this.context.getWriter().flush();
      }
    } else {

      for (ResultConfigBean r : results) {
        if (!"_props_".equals(r.getName()) && !r.getName().equals(re)
            && !"".equals(re))
          continue;

        String type = r.getType();
        String location = r.getLocation();
        if (MVCConfigConstant.REDIRECT_TYPE.equalsIgnoreCase(type)) {
          this.context.getResponse().sendRedirect(location);
        } else if (MVCConfigConstant.FORWARD_TYPE
            .equalsIgnoreCase(type)) {
          HttpServletRequest request = this.context.getRequest();
          request.setAttribute(MVCConfigConstant.REQ_PARAM_MAP_NAME,
              this.context.getQueryParamMap());
          // 服务端跳转
          request.getRequestDispatcher(
              MVCConfigConstant.FORWARD_BASE_PATH + location)
              .forward(request, this.context.getResponse());
        } else if (re != null && re.startsWith("action:")) {
          // ACTION 重定向
          String path = re.substring("action:".length());
          this.context.getResponse().sendRedirect(baseUrl + path);

        } else if (MVCConfigConstant.OUT_TYPE.equalsIgnoreCase(type)
            || location.trim().length() == 0) {
          this.context.getWriter().print(location);
          this.context.getWriter().flush();
        }
      }
    }
  }

  /**
   * 执行Action
   *
   * @param methodName
   * @return
   * @throws Exception
   */
  private Object excuteMethod(String methodName) throws Exception {
    // 要执行的Action方法
    Method m = null;

    // 拿到所有方法
    Method[] methods = ru.getMethods(methodName);
    if (methods == null || methods.length == 0)
      return null;

    m = this.getFirstMethd(methods);
    if (m == null)
      return null;

    Class<?>[] paramTypes = m.getParameterTypes();
    // 无参数运行方法
    if (paramTypes == null || paramTypes.length == 0)
      return m.invoke(actionObject);

    Annotation[][] paramAnns = m.getParameterAnnotations();
    // 拿到方法所需要的参数
    Object[] params = assemParams(paramTypes, paramAnns);

    // 带参数运行方法
    return m.invoke(actionObject, params);
  }

  private void injectActionCxt2Pojo(Object pojo) throws Exception {
    ReflectUtil ru = new ReflectUtil(pojo);
    HttpServletRequest req = this.context.getRequest();
    HttpServletResponse res = this.context.getResponse();
    PrintWriter out = this.context.getWriter();
    // ServletOutputStream sos = this.context.getOut();
    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 (HttpServletRequest.class.isAssignableFrom(clazz)) {
        m.invoke(pojo, req);
      } else if (HttpServletResponse.class.isAssignableFrom(clazz)) {
        m.invoke(pojo, res);
      } else if (PrintWriter.class.isAssignableFrom(clazz)) {
        m.invoke(pojo, out);
      } else if (ServletOutputStream.class.isAssignableFrom(clazz)) {
        m.invoke(pojo, this.context.getOut());
      } else if (HttpSession.class.isAssignableFrom(clazz)) {
        m.invoke(pojo, session);
      } else if (ActionProp.class.isAssignableFrom(clazz)) {
        if (actionProp == null)
          actionProp = new ActionProp(clazz.getName());

        this.context.setActionProp(actionProp);
        m.invoke(pojo, actionProp);
      } else if (QueryParams.class.isAssignableFrom(clazz)) {
        m.invoke(pojo, queryParams);
      }
    }
  }

  /**
   * 执行Action
   *
   * @throws Exception
   */
  public void execute() throws Exception {

    // 验证参数
    if (!this.handleValidator()) {
      return;
    }

    // 实例化pojo
    initPojo();

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

    // 注入框架mvc action 上下文环境
    this.injectActionCxt2Pojo(actionObject);

    // 注入mvc action 请求参数
    ParamUtil.injectParam(this.context.getQueryParamMap(), actionObject);

    String methodName = this.context.getMvcBean().getMethod();

    if (methodName != null && methodName.length() > 0)
      // 执行方法
      retn = excuteMethod(methodName);
    else if (IAction.class.isAssignableFrom(clazz)) {
      // struts2风格
      IAction action = (IAction) actionObject;
      action.init(this.context);
      retn = action.execute();
    }

    InterExecution after_interExe = new InterExecution("after",
        this.context);// 7.后置拦截器
    if (after_interExe.findAndExecuteInter()) {
      after_interExe.showErr();
      return;
    }

    // 对Action执行返回结果的处理
    this.handleResult();

  }
}
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.