Coverage Report - org.apache.tapestry.listener.ListenerMapSourceImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
ListenerMapSourceImpl
96% 
100% 
1.8
 
 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 org.apache.hivemind.util.Defense;
 18  
 import org.apache.tapestry.IPage;
 19  
 import org.apache.tapestry.engine.ILink;
 20  
 import org.apache.tapestry.event.ResetEventListener;
 21  
 
 22  
 import java.lang.reflect.Method;
 23  
 import java.lang.reflect.Modifier;
 24  
 import java.util.*;
 25  
 
 26  
 /**
 27  
  * @author Howard M. Lewis Ship
 28  
  * @since 4.0
 29  
  */
 30  18
 public class ListenerMapSourceImpl implements ListenerMapSource, ResetEventListener
 31  
 {
 32  
 
 33  
     /**
 34  
      * Sorts {@link Method}s into descending order by parameter count.
 35  
      */
 36  
 
 37  24
     private static class ParameterCountComparator implements Comparator
 38  
     {
 39  
 
 40  
         public int compare(Object o1, Object o2)
 41  
         {
 42  1161
             Method m1 = (Method) o1;
 43  1161
             Method m2 = (Method) o2;
 44  
 
 45  1161
             return m2.getParameterTypes().length
 46  
                     - m1.getParameterTypes().length;
 47  
         }
 48  
 
 49  
     }
 50  
 
 51  
     /**
 52  
      * Keyed on Class, value is a Map. The inner Map is an invoker map ... keyed
 53  
      * on listener method name, value is
 54  
      * {@link org.apache.tapestry.listener.ListenerMethodInvoker}.
 55  
      */
 56  
 
 57  18
     private final Map _classToInvokerMap = new HashMap();
 58  
 
 59  
     public ListenerMap getListenerMapForObject(Object object)
 60  
     {
 61  12
         Defense.notNull(object, "object");
 62  
 
 63  12
         Class objectClass = object.getClass();
 64  
 
 65  12
         Map invokerMap = findInvokerMap(objectClass);
 66  
 
 67  12
         return new ListenerMapImpl(object, invokerMap);
 68  
     }
 69  
 
 70  
     public synchronized void resetEventDidOccur()
 71  
     {
 72  0
         _classToInvokerMap.clear();
 73  0
     }
 74  
 
 75  
     private synchronized Map findInvokerMap(Class targetClass)
 76  
     {
 77  12
         Map result = (Map) _classToInvokerMap.get(targetClass);
 78  
 
 79  12
         if (result == null)
 80  
         {
 81  12
             result = buildInvokerMapForClass(targetClass);
 82  12
             _classToInvokerMap.put(targetClass, result);
 83  
         }
 84  
 
 85  12
         return result;
 86  
     }
 87  
 
 88  
     private Map buildInvokerMapForClass(Class targetClass)
 89  
     {
 90  
         // map, keyed on method name, value is List of Method
 91  
         // only methods that return void, return String, or return
 92  
         // something assignable to IPage are kept.
 93  
 
 94  12
         Map map = new HashMap();
 95  
 
 96  12
         Method[] methods = targetClass.getMethods();
 97  
 
 98  
         // Sort all the arrays, just once, and the methods will be
 99  
         // added to the individual lists in the correct order
 100  
         // (descending by parameter count).
 101  
 
 102  12
         Arrays.sort(methods, new ParameterCountComparator());
 103  
 
 104  373
         for(int i = 0; i < methods.length; i++)
 105  
         {
 106  361
             Method m = methods[i];
 107  
 
 108  361
             if (!isAcceptibleListenerMethodReturnType(m)) continue;
 109  
 
 110  286
             if (Modifier.isStatic(m.getModifiers())) continue;
 111  
 
 112  286
             String name = m.getName();
 113  
 
 114  286
             addMethodToMappedList(map, m, name);
 115  
         }
 116  
 
 117  12
         return convertMethodListMapToInvokerMap(map);
 118  
     }
 119  
 
 120  
     boolean isAcceptibleListenerMethodReturnType(Method m)
 121  
     {
 122  367
         Class returnType = m.getReturnType();
 123  
 
 124  370
         if (returnType == void.class || returnType == String.class)
 125  252
             return true;
 126  
 
 127  115
         return IPage.class.isAssignableFrom(returnType)
 128  
                 || ILink.class.isAssignableFrom(returnType);
 129  
     }
 130  
 
 131  
     private Map convertMethodListMapToInvokerMap(Map map)
 132  
     {
 133  12
         Map result = new HashMap();
 134  
 
 135  12
         Iterator i = map.entrySet().iterator();
 136  262
         while(i.hasNext())
 137  
         {
 138  250
             Map.Entry e = (Map.Entry) i.next();
 139  
 
 140  250
             String name = (String) e.getKey();
 141  250
             List methodList = (List) e.getValue();
 142  
 
 143  250
             Method[] methods = convertMethodListToArray(methodList);
 144  
 
 145  250
             ListenerMethodInvoker invoker = createListenerMethodInvoker(name,
 146  
                     methods);
 147  
 
 148  250
             result.put(name, invoker);
 149  250
         }
 150  
 
 151  12
         return result;
 152  
     }
 153  
 
 154  
     /**
 155  
      * This implementation returns a new {@link ListenerMethodInvoker}.
 156  
      * Subclasses can override to provide their own implementation.
 157  
      */
 158  
 
 159  
     protected ListenerMethodInvoker createListenerMethodInvoker(String name,
 160  
             Method[] methods)
 161  
     {
 162  250
         return new ListenerMethodInvokerImpl(name, methods);
 163  
     }
 164  
 
 165  
     private Method[] convertMethodListToArray(List methodList)
 166  
     {
 167  250
         int size = methodList.size();
 168  250
         Method[] result = new Method[size];
 169  
 
 170  250
         return (Method[]) methodList.toArray(result);
 171  
     }
 172  
 
 173  
     private void addMethodToMappedList(Map map, Method m, String name)
 174  
     {
 175  286
         List l = (List) map.get(name);
 176  
 
 177  286
         if (l == null)
 178  
         {
 179  250
             l = new ArrayList();
 180  250
             map.put(name, l);
 181  
         }
 182  
 
 183  286
         l.add(m);
 184  286
     }
 185  
 }