All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.taketoday.aop.framework.StandardProxyInvoker Maven / Gradle / Ivy

/*
 * Original Author -> Harry Yang ([email protected]) https://taketoday.cn
 * Copyright © TODAY & 2017 - 2022 All Rights Reserved.
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see [http://www.gnu.org/licenses/]
 */

package cn.taketoday.aop.framework;

import org.aopalliance.intercept.MethodInterceptor;

import java.lang.reflect.Method;

import cn.taketoday.aop.AopInvocationException;
import cn.taketoday.aop.TargetSource;
import cn.taketoday.lang.Experimental;
import cn.taketoday.util.ObjectUtils;

/**
 * @author TODAY 2021/2/16 22:58
 * @since 3.0
 */
@Experimental
public abstract class StandardProxyInvoker {

  public static Object proceed(Object proxy, Object target, TargetInvocation targetInv, Object[] args) throws Throwable {
    return new StandardMethodInvocation(proxy, target, targetInv, args).proceed();
  }

  public static Object staticExposeProceed(
          Object proxy, Object target, TargetInvocation targetInv, Object[] args) throws Throwable {
    Object oldProxy = null;
    try {
      oldProxy = AopContext.setCurrentProxy(proxy);
      return proceed(proxy, target, targetInv, args);
    }
    finally {
      AopContext.setCurrentProxy(oldProxy);
    }
  }

  public static Object dynamicExposeProceed(
          Object proxy, TargetSource targetSource, TargetInvocation targetInv, Object[] args) throws Throwable {

    Object oldProxy = null;
    final Object target = targetSource.getTarget();
    try {
      oldProxy = AopContext.setCurrentProxy(proxy);
      return proceed(proxy, target, targetInv, args);
    }
    finally {
      AopContext.setCurrentProxy(oldProxy);
      if (target != null && !targetSource.isStatic()) {
        targetSource.releaseTarget(target);
      }
    }
  }

  public static Object dynamicProceed(
          Object proxy, TargetSource targetSource, TargetInvocation targetInv, Object[] args) throws Throwable {

    final Object target = targetSource.getTarget();
    try {
      return proceed(proxy, target, targetInv, args);
    }
    finally {
      if (target != null && !targetSource.isStatic()) {
        targetSource.releaseTarget(target);
      }
    }
  }

  public static Object dynamicAdvisedProceed(
          Object proxy, AdvisedSupport advised,
          TargetInvocation targetInv, Object[] args) throws Throwable {

    Object target = null;
    Object oldProxy = null;
    boolean restore = false;

    final TargetSource targetSource = advised.getTargetSource();
    try {
      if (advised.isExposeProxy()) {
        // Make invocation available if necessary.
        oldProxy = AopContext.setCurrentProxy(proxy);
        restore = true;
      }
      target = targetSource.getTarget();

      final MethodInterceptor[] interceptors = targetInv.getDynamicInterceptors(advised);
      // Check whether we only have one Interceptor: that is, no real advice,
      // but just use MethodInvoker invocation of the target.
      if (ObjectUtils.isEmpty(interceptors)) {
        return targetInv.proceed(target, args);
      }

      // We need to create a DynamicStandardMethodInvocation...
      final Object retVal = new DynamicStandardMethodInvocation(
              proxy, target, targetInv, args, interceptors).proceed();
      assertReturnValue(retVal, targetInv.getMethod());
      return retVal;
    }
    finally {
      if (target != null && !targetSource.isStatic()) {
        targetSource.releaseTarget(target);
      }
      if (restore) {
        // Restore old proxy.
        AopContext.setCurrentProxy(oldProxy);
      }
    }
  }

  public static void assertReturnValue(Object retVal, Method method) {
    Class returnType;
    if (retVal == null && (returnType = method.getReturnType()) != Void.TYPE && returnType.isPrimitive()) {
      throw new AopInvocationException(
              "Null return value from advice does not match primitive return type for: " + method);
    }
  }

  public static Object processReturnValue(Object proxy, Object target, Object retVal, Method method) {
    // Massage return value if necessary.
    Class returnType;
    if (retVal != null && retVal == target &&
            (returnType = method.getReturnType()) != Object.class && returnType.isInstance(proxy)) {
      // Special case: it returned "this" and the return type of the method
      // is type-compatible. Note that we can't help if the target sets
      // a reference to itself in another returned object.
      retVal = proxy;
    }
    if (retVal == null && (returnType = method.getReturnType()) != Void.TYPE && returnType.isPrimitive()) {
      throw new AopInvocationException(
              "Null return value from advice does not match primitive return type for: " + method);
    }
    return retVal;
  }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy