1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.callbackparams.internal.template;
18
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Field;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Modifier;
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.ListIterator;
28 import org.callbackparams.factory.CallbackFactory;
29
30
31
32
33 public abstract class CallbackRef {
34
35 private final Class paramClass;
36 private final AnnotationSpecifiedCallbacks annotationSpecified;
37 private final CallbackFactory secondaryFactory;
38
39 public static CallbackRef newInstance(Method m, int paramIndex) {
40 return new CallbackRef(m, paramIndex) {};
41 }
42
43 static CallbackRef newInstance(Field f) {
44 return new CallbackRef(f) {};
45 }
46
47 interface CallbackFactoryFinder {
48 CallbackFactory find(Class interf);
49 }
50
51
52
53
54 private static final CallbackFactoryFinder FACTORY_FIELD_FINDER =
55 new CallbackFactoryFinder() {
56 public CallbackFactory find(Class interf) {
57
58 final Field[] fields = interf.getDeclaredFields();
59 for (int i = 0 ; i < fields.length ; ++i) {
60 final Field f = fields[i];
61
62 try {
63 f.setAccessible(true);
64 } catch (SecurityException ignore) {
65
66 }
67
68 if (CallbackFactory.class.isAssignableFrom(f.getType())) {
69 try {
70 return (CallbackFactory) f.get(null);
71 } catch (Exception x) {
72 throw new Error(x);
73 }
74 }
75 }
76 return null;
77 }
78 };
79
80 private static CallbackFactoryFinder findByInnerClassConstructor(
81 final Class[] constructorParamTypes,
82 final Object[] constructorArgs) {
83
84 return new CallbackFactoryFinder() {
85 public CallbackFactory find(Class interf) {
86
87 final Class[] nestedClasses = interf.getDeclaredClasses();
88 for (int i = 0 ; i < nestedClasses.length ; ++i) {
89 final Class nested = nestedClasses[i];
90 if (false == CallbackFactory.class.isAssignableFrom(nested)
91 || Modifier.isAbstract(nested.getModifiers())) {
92 continue;
93 }
94
95 Constructor constructor = null;
96 try {
97 constructor = nested
98 .getDeclaredConstructor(constructorParamTypes);
99 constructor.setAccessible(true);
100
101 } catch (NoSuchMethodException x) {
102 continue;
103 } catch (SecurityException ignore) {
104
105 }
106
107 try {
108 return (CallbackFactory) constructor
109 .newInstance(constructorArgs);
110
111 } catch (Exception noGood) {
112 Throwable toThrow;
113 if (noGood instanceof InvocationTargetException) {
114 toThrow = ((InvocationTargetException)noGood)
115 .getTargetException();
116 } else {
117 toThrow = noGood;
118 }
119 if (toThrow instanceof RuntimeException) {
120 throw (RuntimeException)toThrow;
121 } else {
122 throw new Error(toThrow);
123 }
124 }
125 }
126 return null;
127 }
128 };
129 }
130
131 private static final CallbackFactory NULL_FACTORY = new CallbackFactory() {
132 public Object asCallback(Object callbackRecordElement) {
133 return null;
134 }
135 };
136
137 private static Iterator interfaces(Class interf) {
138 final List interfaces = new ArrayList();
139 interfaces.add(interf);
140
141 return new Iterator() {
142 Iterator iter = interfaces.iterator();
143
144 public boolean hasNext() {
145 return false == interfaces.isEmpty();
146 }
147 public Object next() {
148 try {
149 return iter.next();
150 } finally {
151 if (false == iter.hasNext()) {
152 refreshInterfacesList();
153 iter = interfaces.iterator();
154 }
155 }
156 }
157 public void remove() {
158 throw new UnsupportedOperationException("Not supported yet.");
159 }
160
161 void refreshInterfacesList() {
162 ListIterator li = interfaces.listIterator();
163 while (li.hasNext()) {
164 final Class old = (Class) li.next();
165 li.remove();
166 Class[] superInterfaces = old.getInterfaces();
167 for (int i = 0; i < superInterfaces.length; ++i) {
168 li.add(superInterfaces[i]);
169 }
170 }
171 }
172 };
173 }
174
175 private CallbackFactory lookupDeclaredCallbackFactory(Field f) {
176 return lookupDeclaredCallbackFactory(findByInnerClassConstructor(
177 new Class[] {Field.class}, new Object[] {f}));
178 }
179
180 private CallbackFactory lookupDeclaredCallbackFactory(
181 Method m, int paramIndex) {
182 return lookupDeclaredCallbackFactory(findByInnerClassConstructor(
183 new Class[] {Method.class, int.class},
184 new Object[] {m, new Integer(paramIndex)}));
185 }
186
187 private CallbackFactory lookupDeclaredCallbackFactory(
188 CallbackFactoryFinder finderBackup) {
189 CallbackFactoryFinder[] finders = {
190 FACTORY_FIELD_FINDER, finderBackup
191 };
192
193 for (Iterator iter = interfaces(paramClass) ; iter.hasNext() ;) {
194 final Class interf = (Class) iter.next();
195
196 for (int i = 0 ; i < finders.length ; ++i) {
197 final CallbackFactoryFinder factoryFinder = finders[i];
198
199 CallbackFactory factory = factoryFinder.find(interf);
200 if (null != factory) {
201 return factory;
202 }
203 }
204 }
205
206 return NULL_FACTORY;
207 }
208
209 CallbackRef(Method m, int paramIndex) {
210 this.paramClass = m.getParameterTypes()[paramIndex];
211 possibleDeprecationWarning(m);
212 this.annotationSpecified =
213 AnnotationSpecifiedCallbacks.forCallbackRef(m, paramIndex);
214 this.secondaryFactory = lookupDeclaredCallbackFactory(m, paramIndex);
215 }
216
217 CallbackRef(Field f) {
218 this.paramClass = f.getType();
219 possibleDeprecationWarning(f);
220 this.annotationSpecified =
221 AnnotationSpecifiedCallbacks.forCallbackRef(f);
222 this.secondaryFactory = lookupDeclaredCallbackFactory(f);
223 }
224
225 private void possibleDeprecationWarning(java.lang.reflect.Member m) {
226 if (org.callbackparams.CallbackControlPanel.class == paramClass) {
227 System.err.println(m + org.callbackparams.CallbackControlPanel
228 .DEPRECATION_MESSAGE);
229 }
230 CallbackFieldWarning.possibleDeprecationWarning(m);
231 }
232
233 Object asCallback(Object callbackRecordElement) {
234
235 if (isCompatibleCallback(callbackRecordElement)) {
236 return callbackRecordElement;
237 }
238
239 if (callbackRecordElement instanceof org.callbackparams.CallbackFactory) {
240 Object suppliedCallback =
241 ((org.callbackparams.CallbackFactory)callbackRecordElement).getCallback();
242 if (isCompatibleCallback(suppliedCallback)) {
243 return suppliedCallback;
244 }
245 }
246
247 Object callback = annotationSpecified.asCallback(callbackRecordElement);
248 if (null != callback) {
249 return callback;
250 }
251
252
253 return this.secondaryFactory.asCallback(callbackRecordElement);
254 }
255
256 boolean isCompatibleCallback(Object possibleCallback) {
257 return this.paramClass.isInstance(possibleCallback);
258 }
259
260 Class getParamClass() {
261 return paramClass;
262 }
263 }