Package org.soybeanMilk.core.exe

Source Code of org.soybeanMilk.core.exe.Invoke$Arg

/**
* 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 org.soybeanMilk.core.exe;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.soybeanMilk.SbmUtils;
import org.soybeanMilk.core.ExecuteException;
import org.soybeanMilk.core.ObjectSource;
import org.soybeanMilk.core.ObjectSourceException;
import org.soybeanMilk.core.exe.AbstractExecutable;
import org.soybeanMilk.core.exe.ArgPrepareExecuteException;
import org.soybeanMilk.core.exe.InvocationExecuteException;

/**
* 调用,它用于执行对象方法。
* @author earthangry@gmail.com
* @date 2010-9-30
*/
public class Invoke extends AbstractExecutable
{
  private static final long serialVersionUID = 1L;
 
  private static Log log=LogFactory.getLog(Invoke.class);
 
  /**调用方法名*/
  private String methodName;
 
  /**调用方法参数*/
  private transient Arg[] args;
 
  /**调用结果存放到对象源中的关键字*/
  private Serializable resultKey;
 
  /**调用目标*/
  private transient Resolver resolver;
 
  /**此调用的打断器在对象源中的关键字,打断器可以控制调用方法是否执行*/
  private Serializable breaker;
 
  private transient volatile MethodInfo methodInfo;
 
  public Invoke()
  {
    super();
  }
 
  public Invoke(String name, Resolver resolver, String methodName, Arg[] args, Serializable resultKey)
  {
    super.setName(name);
    this.methodName=methodName;
    this.args=args;
    this.resolver=resolver;
    this.resultKey=resultKey;
  }
 
  /**
   * 获取调用方法名
   * @return
   * @date 2012-5-9
   */
  public String getMethodName() {
    return methodName;
  }
 
  /**
   * 设置调用方法名
   * @return
   * @date 2012-5-9
   */
  public void setMethodName(String methodName) {
    this.methodName = methodName;
  }

  /**
   * 获取调用参数
   * @return
   * @date 2012-5-9
   */
  public Arg[] getArgs() {
    return args;
  }

  /**
   * 设置调用参数
   * @return
   * @date 2012-5-9
   */
  public void setArgs(Arg[] args) {
    this.args = args;
  }
 
  /**
   * 获取调用结果存储关键字
   * @return
   * @date 2012-5-9
   */
  public Serializable getResultKey() {
    return resultKey;
  }
 
  /**
   * 设置调用结果存储关键字
   * @return
   * @date 2012-5-9
   */
  public void setResultKey(Serializable resultKey) {
    this.resultKey = resultKey;
  }
 
  /**
   * 获取调用目标
   * @return
   * @date 2012-5-9
   */
  public Resolver getResolver() {
    return resolver;
  }
 
  /**
   * 设置调用目标
   * @return
   * @date 2012-5-9
   */
  public void setResolver(Resolver resolver) {
    this.resolver = resolver;
  }
 
  /**
   * 获取调用打断器
   * @return
   * @date 2012-5-9
   */
  public Serializable getBreaker() {
    return breaker;
  }
 
  /**
   * 设置调用打断器
   * @param breaker
   * @date 2012-5-9
   */
  public void setBreaker(Serializable breaker) {
    this.breaker = breaker;
  }
 
  //@Override
  public void execute(ObjectSource objectSource) throws ExecuteException
  {
    if(log.isDebugEnabled())
      log.debug("start  execute "+SbmUtils.toString(this));
   
    boolean breaked=isBreaked(objectSource);
   
    if(!breaked)
    {
      Object result=executeMethod(objectSource);
      saveMethodResult(result, objectSource);
    }
    else
    {
      if(log.isDebugEnabled())
        log.debug("Invoke method not executed, it is breaked in current object source");
    }
   
    if(log.isDebugEnabled())
      log.debug("finish execute "+SbmUtils.toString(this));
  }
 
  //@Override
  public String toString()
  {
    return getClass().getSimpleName()+" [name="+getName()+", resultKey=" + resultKey + ", resolver="
        + resolver + ", methodName=" + methodName + ", args="
        + Arrays.toString(args) + ", breaker=" + breaker + "]";
  }
 
  /**
   * 执行调用方法
   * @param objectSource
   * @throws ExecuteException
   * @date 2011-1-12
   */
  protected Object executeMethod(ObjectSource objectSource) throws ExecuteException
  {
    Resolver resolver=getResolver();
    MethodInfo methodInfo=getMethodInfo();
    Object resolverObject=null;
   
    try
    {
      resolverObject=resolver.getResolverObject(objectSource);
    }
    catch(Exception e)
    {
      throw new ResolverObjectPrepareExecuteException(this, e);
    }
   
    if(methodInfo == null)
    {
      Class<?> resolverClass=null;
     
      try
      {
        resolverClass=resolver.getResolverClass(objectSource);
      }
      catch(Exception e)
      {
        throw new ExecuteException(e);
      }
     
      if(resolverClass==null && resolverObject!=null)
        resolverClass=resolverObject.getClass();
     
      if(resolverClass == null)
        throw new ExecuteException("got null resolver class from Resolver "+SbmUtils.toString(resolver));
     
      methodInfo=findMethodInfo(resolverClass, this.methodName, this.args, true);
      if(methodInfo == null)
        methodInfo=findMethodInfo(resolverClass, this.methodName, this.args, false);
     
      if(methodInfo == null)
        throw new ExecuteException("no method named "+SbmUtils.toString(this.methodName)+" with "+SbmUtils.toString(this.args)
            +" arguments can be found in resolver class "+SbmUtils.toString(resolverClass));
     
      setMethodInfo(methodInfo);
    }
   
    Object[] argValues=prepareMethodArgValues(methodInfo, objectSource);
   
    try
    {
      return methodInfo.getMethod().invoke(resolverObject, argValues);
    }
    catch(InvocationTargetException e)
    {
      throw new InvocationExecuteException(this, e.getCause());
    }
    catch(IllegalArgumentException e)
    {
      throw new ExecuteException(e);
    }
    catch(IllegalAccessException e)
    {
      throw new ExecuteException(e);
    }
  }
 
  /**
   * 将调用方法结果保存到对象源
   * @param methodResult
   * @param objectSource
   * @throws ExecuteException
   * @date 2012-5-7
   */
  protected void saveMethodResult(Object methodResult, ObjectSource objectSource) throws ExecuteException
  {
    Serializable resultKey=getResultKey();
   
    if(resultKey != null)
    {
      try
      {
        objectSource.set(resultKey, methodResult);
      }
      catch(ObjectSourceException e)
      {
        throw new ExecuteException(e);
      }
    }
  }
 
  /**
   * 获取方法的参数值数组
   * @param methodInfo
   * @param objectSource
   * @return
   * @throws ExecuteException
   * @date 2012-5-6
   */
  protected Object[] prepareMethodArgValues(MethodInfo methodInfo,ObjectSource objectSource) throws ExecuteException
  {
    Object[] values=null;
   
    Arg[] args=this.args;
   
    if(args != null)
    {
      values=new Object[args.length];
     
      for(int i=0;i<args.length;i++)
      {
        try
        {
          values[i]=args[i].getValue(objectSource, methodInfo.getArgType(i), methodInfo.getMethod(), methodInfo.getMethodClass());
        }
        catch(Exception e)
        {
          throw new ArgPrepareExecuteException(this, i, e);
        }
      }
    }
   
    if(log.isDebugEnabled())
      log.debug("prepared method arguments: "+SbmUtils.toString(values));
   
    return values;
  }
 
  /**
   * 此调用是否会在给定对象源上执行时被打断
   * @param objectSource
   * @return
   * @date 2011-10-28
   */
  protected boolean isBreaked(ObjectSource objectSource) throws ExecuteException
  {
    if(this.breaker == null)
      return false;
   
    Boolean breaked=null;
   
    if(this.breaker instanceof Boolean)
      breaked=(Boolean)this.breaker;
    else
    {
      Object breakerObj=null;
     
      try
      {
        breakerObj=objectSource.get(this.breaker);
      }
      catch(Exception e)
      {
        throw new ExecuteException(e);
      }
     
      if(breakerObj instanceof Boolean)
        breaked=(Boolean)breakerObj;
      else
        breaked=(breakerObj != null);
    }
   
    return breaked == null ? false : breaked;
  }
 
  protected MethodInfo getMethodInfo() {
    return methodInfo;
  }

  protected void setMethodInfo(MethodInfo methodInfo) {
    this.methodInfo = methodInfo;
  }
 
  /**
   * 获取调用参数个数
   * @return
   * @date 2012-5-7
   */
  protected int getArgNums()
  {
    return (this.args==null ? 0 : this.args.length);
  }
 
  /**
   * 根据方法名和参数查找方法
   * @param clazz
   * @param methodName
   * @param args
   * @param exactMatch 是否精确匹配类型
   * @return
   * @throws ExecuteException
   * @date 2012-5-11
   */
  protected MethodInfo findMethodInfo(Class<?> clazz, String methodName, Arg[] args, boolean exactMatch)
  {
    MethodInfo result=null;
   
    //动态代理类会丢失泛型信息,所以如果是动态代理类,则需要在其实现的接口中查找方法,以获取泛型信息
    if(isAncestorType(Proxy.class, clazz))
    {
       Class<?>[] interfaces=clazz.getInterfaces();
      
       if(interfaces!=null && interfaces.length>0)
       {
         for(Class<?> si : interfaces)
         {
           result=findMethodInfo(si, methodName, args, exactMatch);
          
           if(result != null)
             break;
         }
       }
    }
    else
    {
      Method method=null;
      Class<?> methodClass=clazz;
     
      int al=(args == null ? 0 : args.length);
      Type[] argTypes=new Type[al];
      for(int i=0; i<al; i++)
        argTypes[i]=args[i].getType();
     
      Method[] ms=clazz.getMethods();
     
      for(Method m : ms)
      {
        //忽略小三方法
        if(m.isSynthetic())
          continue;
       
        if(m.getName().equals(methodName) && Modifier.isPublic(m.getModifiers()))
        {
          Class<?>[] types=m.getParameterTypes();
          int mal=(types == null ? 0 : types.length);
         
          if(mal == al)
          {
            boolean match=true;
           
            for(int i=0; i<mal; i++)
            {
              //null认为是匹配
              if(argTypes[i] == null)
                continue;
             
              //精确匹配
              if(exactMatch)
              {
                if(!argTypes[i].equals(types[i]))
                {
                  match=false;
                  break;
                }
              }
              //方法类型是参数类型的父类
              else
              {
                Class<?> methodType=SbmUtils.narrowToClass(wrapType(types[i]));
                Type argType=wrapType(argTypes[i]);
               
                if(!isAncestorType(methodType, argType))
                {
                  match=false;
                  break;
                }
              }
            }
           
            if(match)
            {
              method=m;
              break;
            }
          }
        }
      }
     
      if(method != null)
        result=new MethodInfo(method, methodClass);
    }
   
    return result;
  }
 
  /**
   * 给定类型是否是另一类型的父类型
   * @param ancestor
   * @param descendant
   * @return
   * @date 2012-5-24
   */
  protected boolean isAncestorType(Type ancestor, Type descendant)
  {
    return SbmUtils.isAncestorType(ancestor, descendant);
  }
 
  /**
   * 将基本类型转换为包装类型,如果<code>type</code>不是基本类型,它将直接被返回。
   * @param type
   * @return
   * @date 2012-5-24
   */
  protected Type wrapType(Type type)
  {
    return SbmUtils.wrapType(type);
  }
 
  /**
   * 方法信息
   * @author earthangry@gmail.com
   * @date 2012-5-6
   */
  protected static class MethodInfo
  {
    private Method method;
   
    private Type[] argTypes;
   
    private Class<?> methodClass;
   
    public MethodInfo(Method method, Class<?> methodClass)
    {
      this.method=method;
      this.methodClass=methodClass;
      this.argTypes=this.method.getGenericParameterTypes();
    }
   
    public Method getMethod() {
      return method;
    }

    public void setMethod(Method method) {
      this.method = method;
    }

    public Type[] getArgTypes() {
      return argTypes;
    }

    public void setArgTypes(Type[] argTypes) {
      this.argTypes = argTypes;
    }

    public Class<?> getMethodClass() {
      return methodClass;
    }
   
    public void setMethodClass(Class<?> methodClass) {
      this.methodClass = methodClass;
    }
   
    public Type getArgType(int argIdx)
    {
      return this.argTypes[argIdx];
    }
  }
 
  /**
   * 调用目标,{@linkplain Invoke 调用}执行调用方法时依赖的调用目标对象由它提供
   * @author earthangry@gmail.com
   * @date 2010-10-19
   */
  public static interface Resolver
  {
    /**
     * 获取调用目标对象
     * @param objectSource
     * @return
     * @throws Exception
     * @date 2012-5-7
     */
    Object getResolverObject(ObjectSource objectSource) throws Exception;
   
    /**
     * 获取调用目标类型,{@linkplain Invoke 调用}使用它来查找和确定调用方法,
     * 如果返回<code>null</code>{@linkplain #getResolverObject(ObjectSource)}的类型将被作为调用目标类型。
     * @param objectSource
     * @return
     * @throws Exception
     * @date 2012-5-18
     */
    Class<?> getResolverClass(ObjectSource objectSource) throws Exception;
  }
 
  /**
   * 调用参数
   * @author earthangry@gmail.com
   * @date 2010-10-3
   */
  public static interface Arg
  {
    /**
     * 获取参数值
     * @param objectSource
     * @param argType
     * @param method
     * @param methodClass
     * @return
     * @throws Exception
     * @date 2012-5-7
     */
    Object getValue(ObjectSource objectSource, Type argType, Method method, Class<?> methodClass) throws Exception;
   
    /**
     * 获取参数类型,它可以让{@linkplain Invoke 调用}更准确地找到调用方法,也可以返回<code>null</code>,由{@linkplain Invoke 调用}自己查找
     * @return
     * @date 2012-5-11
     */
    Type getType();
  }
}
TOP

Related Classes of org.soybeanMilk.core.exe.Invoke$Arg

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.