Save This Page
Home » cglib-src-2.2 » net.sf.cglib.proxy » [javadoc | source]
    1   /*
    2    * Copyright 2003,2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
   10    *  Unless required by applicable law or agreed to in writing, software
   11    * distributed under the License is distributed on an "AS IS" BASIS,
   12    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13    * See the License for the specific language governing permissions and
   14    * limitations under the License.
   15    */
   16   package net.sf.cglib.proxy;
   17   
   18   import java.lang.reflect.InvocationTargetException;
   19   import java.lang.reflect.Method;
   20   
   21   import net.sf.cglib.core.AbstractClassGenerator;
   22   import net.sf.cglib.core.CodeGenerationException;
   23   import net.sf.cglib.core.GeneratorStrategy;
   24   import net.sf.cglib.core.NamingPolicy;
   25   import net.sf.cglib.core.Signature;
   26   import net.sf.cglib.reflect.FastClass;
   27   
   28   /**
   29    * Classes generated by {@link Enhancer} pass this object to the
   30    * registered {@link MethodInterceptor} objects when an intercepted method is invoked. It can
   31    * be used to either invoke the original method, or call the same method on a different
   32    * object of the same type.
   33    * @version $Id: MethodProxy.java,v 1.14 2008/05/26 04:05:50 herbyderby Exp $
   34    */
   35   public class MethodProxy {
   36       private Signature sig1;
   37       private Signature sig2;
   38       private CreateInfo createInfo;
   39       
   40       private final Object initLock = new Object();
   41       private volatile FastClassInfo fastClassInfo;
   42       
   43       /**
   44        * For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class
   45        * for similar functionality.
   46        */
   47       public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
   48           MethodProxy proxy = new MethodProxy();
   49           proxy.sig1 = new Signature(name1, desc);
   50           proxy.sig2 = new Signature(name2, desc);
   51           proxy.createInfo = new CreateInfo(c1, c2);
   52           return proxy;
   53       }
   54   
   55       private void init()
   56       {
   57           /* 
   58            * Using a volatile invariant allows us to initialize the FastClass and
   59            * method index pairs atomically.
   60            * 
   61            * Double-checked locking is safe with volatile in Java 5.  Before 1.5 this 
   62            * code could allow fastClassInfo to be instantiated more than once, which
   63            * appears to be benign.
   64            */
   65           if (fastClassInfo == null)
   66           {
   67               synchronized (initLock)
   68               {
   69                   if (fastClassInfo == null)
   70                   {
   71                       CreateInfo ci = createInfo;
   72   
   73                       FastClassInfo fci = new FastClassInfo();
   74                       fci.f1 = helper(ci, ci.c1);
   75                       fci.f2 = helper(ci, ci.c2);
   76                       fci.i1 = fci.f1.getIndex(sig1);
   77                       fci.i2 = fci.f2.getIndex(sig2);
   78                       fastClassInfo = fci;
   79                   }
   80               }
   81           }
   82       }
   83   
   84       private static class FastClassInfo
   85       {
   86           FastClass f1;
   87           FastClass f2;
   88           int i1;
   89           int i2;
   90       }
   91   
   92       private static class CreateInfo
   93       {
   94           Class c1;
   95           Class c2;
   96           NamingPolicy namingPolicy;
   97           GeneratorStrategy strategy;
   98           boolean attemptLoad;
   99           
  100           public CreateInfo(Class c1, Class c2)
  101           {
  102               this.c1 = c1;
  103               this.c2 = c2;
  104               AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
  105               if (fromEnhancer != null) {
  106                   namingPolicy = fromEnhancer.getNamingPolicy();
  107                   strategy = fromEnhancer.getStrategy();
  108                   attemptLoad = fromEnhancer.getAttemptLoad();
  109               }
  110           }
  111       }
  112   
  113       private static FastClass helper(CreateInfo ci, Class type) {
  114           FastClass.Generator g = new FastClass.Generator();
  115           g.setType(type);
  116           g.setClassLoader(ci.c2.getClassLoader());
  117           g.setNamingPolicy(ci.namingPolicy);
  118           g.setStrategy(ci.strategy);
  119           g.setAttemptLoad(ci.attemptLoad);
  120           return g.create();
  121       }
  122   
  123       private MethodProxy() {
  124       }
  125   
  126       /**
  127        * Return the signature of the proxied method.
  128        */
  129       public Signature getSignature() {
  130           return sig1;
  131       }
  132   
  133       /**
  134        * Return the name of the synthetic method created by CGLIB which is
  135        * used by {@link #invokeSuper} to invoke the superclass
  136        * (non-intercepted) method implementation. The parameter types are
  137        * the same as the proxied method.
  138        */
  139       public String getSuperName() {
  140           return sig2.getName();
  141       }
  142   
  143       /**
  144        * Return the {@link net.sf.cglib.reflect.FastClass} method index
  145        * for the method used by {@link #invokeSuper}. This index uniquely
  146        * identifies the method within the generated proxy, and therefore
  147        * can be useful to reference external metadata.
  148        * @see #getSuperName
  149        */
  150       public int getSuperIndex() {
  151           init();
  152           return fastClassInfo.i2;
  153       }
  154   
  155       /**
  156        * Return the <code>MethodProxy</code> used when intercepting the method
  157        * matching the given signature.
  158        * @param type the class generated by Enhancer
  159        * @param sig the signature to match
  160        * @return the MethodProxy instance, or null if no applicable matching method is found
  161        * @throws IllegalArgumentException if the Class was not created by Enhancer or does not use a MethodInterceptor
  162        */
  163       public static MethodProxy find(Class type, Signature sig) {
  164           try {
  165               Method m = type.getDeclaredMethod(MethodInterceptorGenerator.FIND_PROXY_NAME,
  166                                                 MethodInterceptorGenerator.FIND_PROXY_TYPES);
  167               return (MethodProxy)m.invoke(null, new Object[]{ sig });
  168           } catch (NoSuchMethodException e) {
  169               throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor");
  170           } catch (IllegalAccessException e) {
  171               throw new CodeGenerationException(e);
  172           } catch (InvocationTargetException e) {
  173               throw new CodeGenerationException(e);
  174           }
  175       }
  176   
  177       /**
  178        * Invoke the original method, on a different object of the same type.
  179        * @param obj the compatible object; recursion will result if you use the object passed as the first
  180        * argument to the MethodInterceptor (usually not what you want)
  181        * @param args the arguments passed to the intercepted method; you may substitute a different
  182        * argument array as long as the types are compatible
  183        * @see MethodInterceptor#intercept
  184        * @throws Throwable the bare exceptions thrown by the called method are passed through
  185        * without wrapping in an <code>InvocationTargetException</code>
  186        */
  187       public Object invoke(Object obj, Object[] args) throws Throwable {
  188           try {
  189               init();
  190               FastClassInfo fci = fastClassInfo;
  191               return fci.f1.invoke(fci.i1, obj, args);
  192           } catch (InvocationTargetException e) {
  193               throw e.getTargetException();
  194           } catch (IllegalArgumentException e) {
  195               if (fastClassInfo.i1 < 0)
  196                   throw new IllegalArgumentException("Protected method: " + sig1);
  197               throw e;
  198           }
  199       }
  200   
  201       /**
  202        * Invoke the original (super) method on the specified object.
  203        * @param obj the enhanced object, must be the object passed as the first
  204        * argument to the MethodInterceptor
  205        * @param args the arguments passed to the intercepted method; you may substitute a different
  206        * argument array as long as the types are compatible
  207        * @see MethodInterceptor#intercept
  208        * @throws Throwable the bare exceptions thrown by the called method are passed through
  209        * without wrapping in an <code>InvocationTargetException</code>
  210        */
  211       public Object invokeSuper(Object obj, Object[] args) throws Throwable {
  212           try {
  213               init();
  214               FastClassInfo fci = fastClassInfo;
  215               return fci.f2.invoke(fci.i2, obj, args);
  216           } catch (InvocationTargetException e) {
  217               throw e.getTargetException();
  218           }
  219       }
  220   }

Save This Page
Home » cglib-src-2.2 » net.sf.cglib.proxy » [javadoc | source]