Save This Page
Home » openejb-3.0-src » org.apache » openejb » core » interceptor » [javadoc | source]
    1   /**
    2    *
    3    * Licensed to the Apache Software Foundation (ASF) under one or more
    4    * contributor license agreements.  See the NOTICE file distributed with
    5    * this work for additional information regarding copyright ownership.
    6    * The ASF licenses this file to You under the Apache License, Version 2.0
    7    * (the "License"); you may not use this file except in compliance with
    8    * the License.  You may obtain a copy of the License at
    9    *
   10    *     http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    *  Unless required by applicable law or agreed to in writing, software
   13    *  distributed under the License is distributed on an "AS IS" BASIS,
   14    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15    *  See the License for the specific language governing permissions and
   16    *  limitations under the License.
   17    */
   18   package org.apache.openejb.core.interceptor;
   19   
   20   import org.apache.openejb.core.Operation;
   21   
   22   import javax.interceptor.InvocationContext;
   23   import java.util.Iterator;
   24   import java.util.Map;
   25   import java.util.List;
   26   import java.util.TreeMap;
   27   import java.lang.reflect.Method;
   28   import java.lang.reflect.InvocationTargetException;
   29   
   30   /**
   31    * @version $Rev: 634462 $ $Date: 2008-03-06 15:45:47 -0800 (Thu, 06 Mar 2008) $
   32    */
   33   public class ReflectionInvocationContext implements InvocationContext {
   34       private final Iterator<Interceptor> interceptors;
   35       private final Object target;
   36       private final Method method;
   37       private final Object[] parameters;
   38       private final Map<String, Object> contextData = new TreeMap<String, Object>();
   39       private final Class<?>[] parameterTypes;
   40   
   41       private final Operation operation;
   42   
   43       public ReflectionInvocationContext(Operation operation, List<Interceptor> interceptors, Object target, Method method, Object... parameters) {
   44           if (operation == null) throw new NullPointerException("operation is null");
   45           if (interceptors == null) throw new NullPointerException("interceptors is null");
   46           if (target == null) throw new NullPointerException("target is null");
   47   
   48           this.operation = operation;
   49           this.interceptors = interceptors.iterator();
   50           this.target = target;
   51           this.method = method;
   52           this.parameters = parameters;
   53   
   54           if (method == null) {
   55               parameterTypes = new Class[0];
   56           } else {
   57               parameterTypes = method.getParameterTypes();
   58           }
   59       }
   60   
   61       public Object getTarget() {
   62           return target;
   63       }
   64   
   65       public Method getMethod() {
   66           return method;
   67       }
   68   
   69       public Object[] getParameters() {
   70           if (operation.isCallback()) {
   71               throw new IllegalStateException(getIllegalParameterAccessMessage());
   72           }
   73           return parameters.clone();
   74       }
   75   
   76       private String getIllegalParameterAccessMessage() {
   77           String m = "Callback methods cannot access parameters.";
   78           m += "  Callback Type: "+operation;
   79           if (method!= null){
   80               m += ", Target Method: " + method.getName();
   81           }
   82           if (target != null){
   83               m += ", Target Bean: "+target.getClass().getName();
   84           }
   85           return m;
   86       }
   87   
   88       public void setParameters(Object[] parameters) {
   89           if (operation.isCallback()) {
   90               throw new IllegalStateException(getIllegalParameterAccessMessage());
   91           }
   92           if (parameters == null) throw new NullPointerException("parameters is null");
   93           if (parameters.length != this.parameters.length) {
   94               throw new IllegalArgumentException("Expected " + this.parameters.length + " parameters, but only got " + parameters.length + " parameters");
   95           }
   96   //        for (int i = 0; i < parameters.length; i++) {
   97   //            Object parameter = parameters[i];
   98   //            Class<?> parameterType = parameterTypes[i];
   99   //
  100   //            if (parameter == null) {
  101   //                if (parameterType.isPrimitive()) {
  102   //                    throw new IllegalArgumentException("Expected parameter " + i + " to be primitive type " + parameterType.getName() +
  103   //                        ", but got a parameter that is null");
  104   //                }
  105   //            } else if (!parameterType.isInstance(parameter)) {
  106   //                throw new IllegalArgumentException("Expected parameter " + i + " to be of type " + parameterType.getName() +
  107   //                    ", but got a parameter of type " + parameter.getClass().getName());
  108   //            }
  109   //        }
  110           System.arraycopy(parameters, 0, this.parameters, 0, parameters.length);
  111       }
  112   
  113       public Map<String, Object> getContextData() {
  114           return contextData;
  115       }
  116   
  117       private Invocation next() {
  118           if (interceptors.hasNext()) {
  119               Interceptor interceptor = interceptors.next();
  120               Object nextInstance = interceptor.getInstance();
  121               Method nextMethod = interceptor.getMethod();
  122   
  123               if (nextMethod.getParameterTypes().length > 0){
  124                   return new InterceptorInvocation(nextInstance, nextMethod, this);
  125               } else {
  126                   return new LifecycleInvocation(nextInstance, nextMethod, this);
  127               }
  128           } else if (method != null) {
  129               return new BeanInvocation(target, method, parameters);
  130           } else {
  131               return new NoOpInvocation();
  132           }
  133       }
  134   
  135       public Object proceed() throws Exception {
  136           // The bulk of the logic of this method has intentionally been moved
  137           // out so stepping through a large stack in a debugger can be done quickly.
  138           // Simply put one break point on 'next.invoke()' or one inside that method.
  139           try {
  140               Invocation next = next();
  141               return next.invoke();
  142           } catch (InvocationTargetException e) {
  143               throw unwrapInvocationTargetException(e);
  144           }
  145       }
  146   
  147       private abstract static class Invocation {
  148           private final Method method;
  149           private final Object[] args;
  150           private final Object target;
  151   
  152           public Invocation(Object target, Method method, Object[] args) {
  153               this.target = target;
  154               this.method = method;
  155               this.args = args;
  156           }
  157           public Object invoke() throws Exception {
  158               Object value = method.invoke(target, args);
  159               return value;
  160           }
  161   
  162           public String toString() {
  163               return method.getDeclaringClass().getName() + "." + method.getName();
  164           }
  165       }
  166   
  167       private static class BeanInvocation extends Invocation {
  168           public BeanInvocation(Object target, Method method, Object[] args) {
  169               super(target, method, args);
  170           }
  171       }
  172   
  173       private static class InterceptorInvocation extends Invocation {
  174           public InterceptorInvocation(Object target, Method method, InvocationContext invocationContext) {
  175               super(target, method, new Object[] {invocationContext});
  176           }
  177       }
  178   
  179       private static class LifecycleInvocation extends Invocation {
  180           private final InvocationContext invocationContext;
  181   
  182           public LifecycleInvocation(Object target, Method method, InvocationContext invocationContext) {
  183               super(target, method, new Object[] {});
  184               this.invocationContext = invocationContext;
  185           }
  186   
  187           public Object invoke() throws Exception {
  188               // invoke the callback
  189               super.invoke();
  190   
  191               // we need to call proceed so callbacks in subclasses get invoked
  192               Object value = invocationContext.proceed();
  193               return value;
  194           }
  195       }
  196   
  197       private static class NoOpInvocation extends Invocation {
  198           public NoOpInvocation() {
  199               super(null, null, null);
  200           }
  201   
  202           public Object invoke() throws IllegalAccessException, InvocationTargetException {
  203               return null;
  204           }
  205       }
  206   
  207       // todo verify excpetion types
  208   
  209       /**
  210        * Business method interceptors can only throw exception allowed by the target business method.
  211        * Lifecycle interceptors can only throw RuntimeException.
  212        * @param e the invocation target exception of a reflection method invoke
  213        * @return the cause of the exception
  214        * @throws AssertionError if the cause is not an Exception or Error.
  215        */
  216       private Exception unwrapInvocationTargetException(InvocationTargetException e) {
  217           Throwable cause = e.getCause();
  218           if (cause == null) {
  219               return e;
  220           } else if (cause instanceof Exception) {
  221               return (Exception) cause;
  222           } else if (cause instanceof Error) {
  223               throw (Error) cause;
  224           } else {
  225               throw new AssertionError(cause);
  226           }
  227       }
  228   
  229       public String toString() {
  230           String methodName = (method != null)? method.getName(): null;
  231   
  232           return "InvocationContext(operation=" + operation + ", target="+target.getClass().getName()+", method="+methodName+")";
  233       }
  234   }

Save This Page
Home » openejb-3.0-src » org.apache » openejb » core » interceptor » [javadoc | source]