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