KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > util > xml > HandlerMethod


1 /*
2  * Copyright 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.util.xml;
17
18 import com.google.gwt.core.ext.UnableToCompleteException;
19
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.List JavaDoc;
24
25 /**
26  * Represents metadata about a handler method in a class derived from {@link Schema}.
27  */

28 public final class HandlerMethod {
29
30   private static final HandlerParam[] EMPTY_HANDLERPARAMS = new HandlerParam[0];
31
32   // A schema level that ignores everything.
33
private static final Schema sArbitraryChildHandler = new Schema() {
34
35     public void onBadAttributeValue(int lineNumber, String JavaDoc elemName,
36         String JavaDoc attrName, String JavaDoc attrValue, Class JavaDoc paramType) {
37       // Ignore
38
}
39
40     public void onHandlerException(int lineNumber, String JavaDoc elemLocalName,
41         Method JavaDoc method, Throwable JavaDoc e) {
42       // Ignore
43
}
44
45     public void onMissingAttribute(int lineNumber, String JavaDoc elemName,
46         String JavaDoc argName) {
47       // Ignore
48
}
49
50     public void onUnexpectedAttribute(int lineNumber, String JavaDoc elemName,
51         String JavaDoc attrName, String JavaDoc attrValue) {
52       // Ignore
53
}
54
55     public void onUnexpectedChild(int lineNumber, String JavaDoc elemName) {
56       // Ignore
57
}
58
59     public void onUnexpectedElement(int lineNumber, String JavaDoc elemName) {
60       // Ignore
61
}
62   };
63
64   private static final int TYPE_NONE = 0;
65   private static final int TYPE_BEGIN = 1;
66   private static final int TYPE_END = 2;
67   private static final int TYPE_TEXT = 3;
68
69   static {
70     ReflectiveParser.registerSchemaLevel(sArbitraryChildHandler.getClass());
71   }
72
73   /**
74    * Attempts to create a handler method from any method. You can pass in any
75    * method at all, but an exception will be thrown if the method is clearly a
76    * handler but the containing class does not have the proper parameter
77    * metafields.
78    */

79   public static HandlerMethod tryCreate(Method JavaDoc method) {
80     String JavaDoc methodName = method.getName();
81     String JavaDoc normalizedTagName = null;
82     try {
83       int type = TYPE_NONE;
84
85       if (methodName.startsWith("__")) {
86         if (methodName.endsWith("_begin")) {
87           type = TYPE_BEGIN;
88           normalizedTagName = methodName.substring(0, methodName.length()
89               - "_begin".length());
90         } else if (methodName.endsWith("_end")) {
91           type = TYPE_END;
92           normalizedTagName = methodName.substring(0, methodName.length()
93               - "_end".length());
94         } else if (methodName.equals("__text")) {
95           type = TYPE_TEXT;
96         }
97       }
98
99       if (type == TYPE_NONE) {
100         // This was not a handler method.
101
// Exit early.
102
//
103
return null;
104       }
105
106       assert (type == TYPE_BEGIN || type == TYPE_END || type == TYPE_TEXT);
107
108       // Can the corresponding element have arbitrary children?
109
//
110
Class JavaDoc returnType = method.getReturnType();
111       boolean arbitraryChildren = false;
112       if (type == TYPE_BEGIN) {
113         if (Schema.class.isAssignableFrom(returnType)) {
114           arbitraryChildren = false;
115
116           // Also, we need to register this schema type.
117
//
118
ReflectiveParser.registerSchemaLevel(returnType);
119
120         } else if (returnType.equals(Void.TYPE)) {
121           arbitraryChildren = true;
122         } else {
123           throw new IllegalArgumentException JavaDoc(
124               "The return type of begin handlers must be 'void' or assignable to 'SchemaLevel'");
125         }
126       } else if (!Void.TYPE.equals(returnType)) {
127         throw new IllegalArgumentException JavaDoc(
128             "Only 'void' may be specified as a return type for 'end' and 'text' handlers");
129       }
130
131       // Create handler args.
132
//
133
if (type == TYPE_TEXT) {
134         Class JavaDoc[] paramTypes = method.getParameterTypes();
135         if (paramTypes.length != 1 || !String JavaDoc.class.equals(paramTypes[0])) {
136           throw new IllegalArgumentException JavaDoc(
137               "__text handlers must have exactly one String parameter");
138         }
139
140         // We pretend it doesn't have any param since they're always
141
// pre-determined.
142
//
143
return new HandlerMethod(method, type, false, EMPTY_HANDLERPARAMS);
144       } else {
145         Class JavaDoc[] paramTypes = method.getParameterTypes();
146         List JavaDoc handlerParams = new ArrayList JavaDoc();
147         for (int i = 0, n = paramTypes.length; i < n; ++i) {
148           HandlerParam handlerParam = HandlerParam.create(method,
149               normalizedTagName, i);
150           if (handlerParam != null) {
151             handlerParams.add(handlerParam);
152           } else {
153             throw new IllegalArgumentException JavaDoc("In method '" + method.getName()
154                 + "', parameter " + (i + 1) + " is an unsupported type");
155           }
156         }
157
158         HandlerParam[] hpa = (HandlerParam[]) handlerParams.toArray(EMPTY_HANDLERPARAMS);
159         return new HandlerMethod(method, type, arbitraryChildren, hpa);
160       }
161     } catch (Exception JavaDoc e) {
162       throw new RuntimeException JavaDoc("Unable to use method '" + methodName
163           + "' as a handler", e);
164     }
165   }
166
167   private final boolean arbitraryChildren;
168
169   private final HandlerParam[] handlerParams;
170
171   private final Method JavaDoc method;
172
173   private final int methodType;
174
175   private HandlerMethod(Method JavaDoc method, int type, boolean arbitraryChildren,
176       HandlerParam[] hpa) {
177     this.method = method;
178     this.methodType = type;
179     this.arbitraryChildren = arbitraryChildren;
180     this.handlerParams = (HandlerParam[]) hpa.clone();
181
182     this.method.setAccessible(true);
183   }
184
185   public HandlerArgs createArgs(Schema schema, int lineNumber, String JavaDoc elemName) {
186     return new HandlerArgs(schema, lineNumber, elemName, handlerParams);
187   }
188
189   public String JavaDoc getNormalizedName() {
190     String JavaDoc name = method.getName();
191     if (isStartMethod()) {
192       return name.substring(2, name.length() - "_begin".length());
193     } else if (isEndMethod()) {
194       return name.substring(2, name.length() - "_end".length());
195     } else {
196       throw new IllegalStateException JavaDoc("Unexpected method name");
197     }
198   }
199
200   public HandlerParam getParam(int i) {
201     return handlerParams[i];
202   }
203
204   public int getParamCount() {
205     return handlerParams.length;
206   }
207
208   public Schema invokeBegin(int lineNumber, String JavaDoc elemLocalName,
209       Schema target, HandlerArgs args, Object JavaDoc[] outInvokeArgs)
210       throws UnableToCompleteException {
211     assert (outInvokeArgs.length == args.getArgCount());
212
213     for (int i = 0, n = args.getArgCount(); i < n; ++i) {
214       Object JavaDoc invokeArg = args.convertToArg(i);
215       outInvokeArgs[i] = invokeArg;
216     }
217
218     Schema nextSchemaLevel = null;
219
220     Throwable JavaDoc caught = null;
221     try {
222       target.setLineNumber(lineNumber);
223       nextSchemaLevel = (Schema) method.invoke(target, outInvokeArgs);
224     } catch (IllegalArgumentException JavaDoc e) {
225       caught = e;
226     } catch (IllegalAccessException JavaDoc e) {
227       caught = e;
228     } catch (InvocationTargetException JavaDoc e) {
229       caught = e.getTargetException();
230     }
231
232     if (caught != null) {
233       target.onHandlerException(lineNumber, elemLocalName, method, caught);
234     }
235
236     // Prepare a resulting schema level that allows the reflective parser
237
// to simply perform its normal logic, even while there are some
238
// special cases.
239
//
240
// Four cases:
241
// (1) childSchemaLevel is non-null, in which case it becomes the new
242
// schema used for child elements
243
// (2) the handler method has return type "SchemaLevel" but the result
244
// was null, meaning that it cannot have child elements;
245
// we return null to indicate this
246
// (3) the handler method has return type "void", meaning that child
247
// elements are simply ignored; we push null to detect this
248
// (4) the method failed or could not be called, which is treated the same
249
// as case (3)
250
//
251
if (nextSchemaLevel != null) {
252       return nextSchemaLevel;
253     } else if (arbitraryChildren) {
254       return sArbitraryChildHandler;
255     } else {
256       return null;
257     }
258   }
259
260   public void invokeEnd(int lineNumber, String JavaDoc elem, Schema target,
261       Object JavaDoc[] args) throws UnableToCompleteException {
262     Throwable JavaDoc caught = null;
263     try {
264       target.setLineNumber(lineNumber);
265       method.invoke(target, args);
266       return;
267     } catch (IllegalArgumentException JavaDoc e) {
268       caught = e;
269     } catch (IllegalAccessException JavaDoc e) {
270       caught = e;
271     } catch (InvocationTargetException JavaDoc e) {
272       caught = e.getTargetException();
273     }
274     target.onHandlerException(lineNumber, elem, method, caught);
275   }
276
277   public void invokeText(int lineNumber, String JavaDoc text, Schema target)
278       throws UnableToCompleteException {
279     Throwable JavaDoc caught = null;
280     try {
281       target.setLineNumber(lineNumber);
282       method.invoke(target, new Object JavaDoc[] {text});
283       return;
284     } catch (IllegalArgumentException JavaDoc e) {
285       caught = e;
286     } catch (IllegalAccessException JavaDoc e) {
287       caught = e;
288     } catch (InvocationTargetException JavaDoc e) {
289       caught = e.getTargetException();
290     }
291     target.onHandlerException(lineNumber, "#text", method, caught);
292   }
293
294   public boolean isEndMethod() {
295     return methodType == TYPE_END;
296   }
297
298   public boolean isStartMethod() {
299     return methodType == TYPE_BEGIN;
300   }
301 }
302
Popular Tags