Clover coverage report - Code Coverage for tapestry release 4.0-alpha-3
Coverage timestamp: Mon May 16 2005 09:05:49 EDT
file stats: LOC: 185   Methods: 5
NCLOC: 101   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
ListenerMethodInvokerImpl.java 100% 100% 100% 100%
coverage
 1   
 // Copyright 2005 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 15   
 package org.apache.tapestry.listener;
 16   
 
 17   
 import java.lang.reflect.InvocationTargetException;
 18   
 import java.lang.reflect.Method;
 19   
 
 20   
 import org.apache.hivemind.ApplicationRuntimeException;
 21   
 import org.apache.hivemind.util.Defense;
 22   
 import org.apache.tapestry.IRequestCycle;
 23   
 import org.apache.tapestry.Tapestry;
 24   
 
 25   
 /**
 26   
  * Logic for mapping a listener method name to an actual method invocation; this may require a
 27   
  * little searching to find the correct version of the method, based on the number of parameters to
 28   
  * the method (there's a lot of flexibility in terms of what methods may be considered a listener
 29   
  * method).
 30   
  * 
 31   
  * @author Howard M. Lewis Ship
 32   
  * @since 4.0
 33   
  */
 34   
 public class ListenerMethodInvokerImpl implements ListenerMethodInvoker
 35   
 {
 36   
     /**
 37   
      * Methods with a name appropriate for this class, sorted into descending order by number of
 38   
      * parameters.
 39   
      */
 40   
 
 41   
     private final Method[] _methods;
 42   
 
 43   
     /**
 44   
      * The listener method name, used in some error messages.
 45   
      */
 46   
 
 47   
     private final String _name;
 48   
 
 49  1236
     public ListenerMethodInvokerImpl(String name, Method[] methods)
 50   
     {
 51  1236
         Defense.notNull(name, "name");
 52  1236
         Defense.notNull(methods, "methods");
 53   
 
 54  1236
         _name = name;
 55  1236
         _methods = methods;
 56   
     }
 57   
 
 58  59
     public void invokeListenerMethod(Object target, IRequestCycle cycle)
 59   
     {
 60  59
         Object[] listenerParameters = cycle.getListenerParameters();
 61   
 
 62   
         // method(parameters)
 63  59
         if (searchAndInvoke(target, false, true, cycle, listenerParameters))
 64  2
             return;
 65   
 
 66   
         // method(IRequestCycle, parameters)
 67  56
         if (searchAndInvoke(target, true, true, cycle, listenerParameters))
 68  41
             return;
 69   
 
 70   
         // method()
 71  13
         if (searchAndInvoke(target, false, false, cycle, listenerParameters))
 72  1
             return;
 73   
 
 74   
         // method(IRequestCycle)
 75  10
         if (searchAndInvoke(target, true, false, cycle, listenerParameters))
 76  9
             return;
 77   
 
 78  1
         throw new ApplicationRuntimeException(ListenerMessages.noListenerMethodFound(
 79   
                 _name,
 80   
                 listenerParameters,
 81   
                 target), target, null, null);
 82   
     }
 83   
 
 84  138
     private boolean searchAndInvoke(Object target, boolean includeCycle, boolean includeParameters,
 85   
             IRequestCycle cycle, Object[] listenerParameters)
 86   
     {
 87  138
         int listenerParameterCount = Tapestry.size(listenerParameters);
 88  138
         int methodParameterCount = includeParameters ? listenerParameterCount : 0;
 89   
 
 90  138
         if (includeCycle)
 91  66
             methodParameterCount++;
 92   
 
 93  138
         for (int i = 0; i < _methods.length; i++)
 94   
         {
 95  139
             Method m = _methods[i];
 96   
 
 97   
             // Since the methods are sorted, descending, by parameter count,
 98   
             // there's no point in searching past that point.
 99   
 
 100  139
             Class[] parameterTypes = m.getParameterTypes();
 101   
 
 102  139
             if (parameterTypes.length < methodParameterCount)
 103  20
                 break;
 104   
 
 105  119
             if (parameterTypes.length != methodParameterCount)
 106  56
                 continue;
 107   
 
 108  63
             boolean firstIsCycle = parameterTypes.length > 0
 109   
                     && parameterTypes[0] == IRequestCycle.class;
 110   
 
 111   
             // When we're searching for a "traditional" style listener method,
 112   
             // one which takes the request cycle as its first parameter,
 113   
             // then check that first parameter is *exactly* IRequestCycle
 114   
             // On the other hand, if we're looking for new style
 115   
             // listener methods (includeCycle is false), then ignore
 116   
             // any methods whose first parameter is the request cycle
 117   
             // (we'll catch those in a later search).
 118   
 
 119  63
             if (includeCycle != firstIsCycle)
 120  5
                 continue;
 121   
 
 122  58
             invokeListenerMethod(
 123   
                     m,
 124   
                     target,
 125   
                     includeCycle,
 126   
                     includeParameters,
 127   
                     cycle,
 128   
                     listenerParameters);
 129   
 
 130  53
             return true;
 131   
         }
 132   
 
 133  80
         return false;
 134   
     }
 135   
 
 136  58
     private void invokeListenerMethod(Method listenerMethod, Object target, boolean includeCycle,
 137   
             boolean includeParameters, IRequestCycle cycle, Object[] listenerParameters)
 138   
     {
 139  58
         Object[] parameters = new Object[listenerMethod.getParameterTypes().length];
 140  58
         int cursor = 0;
 141   
 
 142  58
         if (includeCycle)
 143  52
             parameters[cursor++] = cycle;
 144   
 
 145  58
         if (includeParameters)
 146  46
             for (int i = 0; i < Tapestry.size(listenerParameters); i++)
 147  26
                 parameters[cursor++] = listenerParameters[i];
 148   
 
 149  58
         try
 150   
         {
 151  58
             invokeTargetMethod(target, listenerMethod, parameters);
 152   
         }
 153   
         catch (InvocationTargetException ex)
 154   
         {
 155  4
             Throwable targetException = ex.getTargetException();
 156   
 
 157  4
             if (targetException instanceof ApplicationRuntimeException)
 158  3
                 throw (ApplicationRuntimeException) targetException;
 159   
 
 160  1
             throw new ApplicationRuntimeException(ListenerMessages.listenerMethodFailure(
 161   
                     listenerMethod,
 162   
                     target,
 163   
                     targetException), target, null, targetException);
 164   
         }
 165   
         catch (Exception ex)
 166   
         {
 167  1
             throw new ApplicationRuntimeException(ListenerMessages.listenerMethodFailure(
 168   
                     listenerMethod,
 169   
                     target,
 170   
                     ex), target, null, ex);
 171   
 
 172   
         }
 173   
     }
 174   
 
 175   
     /**
 176   
      * Provided as a hook so that subclasses can perform any additional work before or after
 177   
      * invoking the listener method.
 178   
      */
 179   
 
 180  58
     protected void invokeTargetMethod(Object target, Method listenerMethod, Object[] parameters)
 181   
             throws IllegalAccessException, InvocationTargetException
 182   
     {
 183  58
         listenerMethod.invoke(target, parameters);
 184   
     }
 185   
 }