1
17 package org.apache.tomcat.util.descriptor.tld;
18
19 import java.lang.reflect.Method;
20
21 import javax.servlet.jsp.tagext.TagAttributeInfo;
22 import javax.servlet.jsp.tagext.TagVariableInfo;
23 import javax.servlet.jsp.tagext.VariableInfo;
24
25 import org.apache.tomcat.util.digester.Digester;
26 import org.apache.tomcat.util.digester.Rule;
27 import org.apache.tomcat.util.digester.RuleSet;
28 import org.xml.sax.Attributes;
29
30
33 public class TldRuleSet implements RuleSet {
34 private static final String PREFIX = "taglib";
35 private static final String VALIDATOR_PREFIX = PREFIX + "/validator";
36 private static final String TAG_PREFIX = PREFIX + "/tag";
37 private static final String TAGFILE_PREFIX = PREFIX + "/tag-file";
38 private static final String FUNCTION_PREFIX = PREFIX + "/function";
39
40 @Override
41 public void addRuleInstances(Digester digester) {
42
43 digester.addCallMethod(PREFIX + "/tlibversion", "setTlibVersion", 0);
44 digester.addCallMethod(PREFIX + "/tlib-version", "setTlibVersion", 0);
45 digester.addCallMethod(PREFIX + "/jspversion", "setJspVersion", 0);
46 digester.addCallMethod(PREFIX + "/jsp-version", "setJspVersion", 0);
47 digester.addRule(PREFIX, new Rule() {
48
49 @Override
50 public void begin(String namespace, String name, Attributes attributes) {
51 TaglibXml taglibXml = (TaglibXml) digester.peek();
52 taglibXml.setJspVersion(attributes.getValue("version"));
53 }
54 });
55 digester.addCallMethod(PREFIX + "/shortname", "setShortName", 0);
56 digester.addCallMethod(PREFIX + "/short-name", "setShortName", 0);
57
58
59 digester.addCallMethod(PREFIX + "/uri", "setUri", 0);
60 digester.addCallMethod(PREFIX + "/info", "setInfo", 0);
61 digester.addCallMethod(PREFIX + "/description", "setInfo", 0);
62 digester.addCallMethod(PREFIX + "/listener/listener-class", "addListener", 0);
63
64
65 digester.addObjectCreate(VALIDATOR_PREFIX, ValidatorXml.class.getName());
66 digester.addCallMethod(VALIDATOR_PREFIX + "/validator-class", "setValidatorClass", 0);
67 digester.addCallMethod(VALIDATOR_PREFIX + "/init-param", "addInitParam", 2);
68 digester.addCallParam(VALIDATOR_PREFIX + "/init-param/param-name", 0);
69 digester.addCallParam(VALIDATOR_PREFIX + "/init-param/param-value", 1);
70 digester.addSetNext(VALIDATOR_PREFIX, "setValidator", ValidatorXml.class.getName());
71
72
73
74 digester.addObjectCreate(TAG_PREFIX, TagXml.class.getName());
75 addDescriptionGroup(digester, TAG_PREFIX);
76 digester.addCallMethod(TAG_PREFIX + "/name", "setName", 0);
77 digester.addCallMethod(TAG_PREFIX + "/tagclass", "setTagClass", 0);
78 digester.addCallMethod(TAG_PREFIX + "/tag-class", "setTagClass", 0);
79 digester.addCallMethod(TAG_PREFIX + "/teiclass", "setTeiClass", 0);
80 digester.addCallMethod(TAG_PREFIX + "/tei-class", "setTeiClass", 0);
81 digester.addCallMethod(TAG_PREFIX + "/bodycontent", "setBodyContent", 0);
82 digester.addCallMethod(TAG_PREFIX + "/body-content", "setBodyContent", 0);
83
84 digester.addRule(TAG_PREFIX + "/variable", new ScriptVariableRule());
85 digester.addCallMethod(TAG_PREFIX + "/variable/name-given", "setNameGiven", 0);
86 digester.addCallMethod(TAG_PREFIX + "/variable/name-from-attribute",
87 "setNameFromAttribute", 0);
88 digester.addCallMethod(TAG_PREFIX + "/variable/variable-class", "setClassName", 0);
89 digester.addRule(TAG_PREFIX + "/variable/declare",
90 new GenericBooleanRule(Variable.class, "setDeclare"));
91 digester.addCallMethod(TAG_PREFIX + "/variable/scope", "setScope", 0);
92
93 digester.addRule(TAG_PREFIX + "/attribute", new TagAttributeRule());
94 digester.addCallMethod(TAG_PREFIX + "/attribute/description", "setDescription", 0);
95 digester.addCallMethod(TAG_PREFIX + "/attribute/name", "setName", 0);
96 digester.addRule(TAG_PREFIX + "/attribute/required",
97 new GenericBooleanRule(Attribute.class, "setRequired"));
98 digester.addRule(TAG_PREFIX + "/attribute/rtexprvalue",
99 new GenericBooleanRule(Attribute.class, "setRequestTime"));
100 digester.addCallMethod(TAG_PREFIX + "/attribute/type", "setType", 0);
101 digester.addCallMethod(TAG_PREFIX + "/attribute/deferred-value", "setDeferredValue");
102 digester.addCallMethod(TAG_PREFIX + "/attribute/deferred-value/type",
103 "setExpectedTypeName", 0);
104 digester.addCallMethod(TAG_PREFIX + "/attribute/deferred-method", "setDeferredMethod");
105 digester.addCallMethod(TAG_PREFIX + "/attribute/deferred-method/method-signature",
106 "setMethodSignature", 0);
107 digester.addRule(TAG_PREFIX + "/attribute/fragment",
108 new GenericBooleanRule(Attribute.class, "setFragment"));
109
110 digester.addRule(TAG_PREFIX + "/dynamic-attributes",
111 new GenericBooleanRule(TagXml.class, "setDynamicAttributes"));
112 digester.addSetNext(TAG_PREFIX, "addTag", TagXml.class.getName());
113
114
115 digester.addObjectCreate(TAGFILE_PREFIX, TagFileXml.class.getName());
116 addDescriptionGroup(digester, TAGFILE_PREFIX);
117 digester.addCallMethod(TAGFILE_PREFIX + "/name", "setName", 0);
118 digester.addCallMethod(TAGFILE_PREFIX + "/path", "setPath", 0);
119 digester.addSetNext(TAGFILE_PREFIX, "addTagFile", TagFileXml.class.getName());
120
121
122 digester.addCallMethod(FUNCTION_PREFIX, "addFunction", 3);
123 digester.addCallParam(FUNCTION_PREFIX + "/name", 0);
124 digester.addCallParam(FUNCTION_PREFIX + "/function-class", 1);
125 digester.addCallParam(FUNCTION_PREFIX + "/function-signature", 2);
126 }
127
128 private void addDescriptionGroup(Digester digester, String prefix) {
129 digester.addCallMethod(prefix + "/info", "setInfo", 0);
130 digester.addCallMethod(prefix + "small-icon", "setSmallIcon", 0);
131 digester.addCallMethod(prefix + "large-icon", "setLargeIcon", 0);
132
133 digester.addCallMethod(prefix + "/description", "setInfo", 0);
134 digester.addCallMethod(prefix + "/display-name", "setDisplayName", 0);
135 digester.addCallMethod(prefix + "/icon/small-icon", "setSmallIcon", 0);
136 digester.addCallMethod(prefix + "/icon/large-icon", "setLargeIcon", 0);
137 }
138
139 private static class TagAttributeRule extends Rule {
140 @Override
141 public void begin(String namespace, String name, Attributes attributes) throws Exception {
142 TaglibXml taglibXml = (TaglibXml) digester.peek(digester.getCount() - 1);
143 digester.push(new Attribute("1.2".equals(taglibXml.getJspVersion())));
144 }
145
146 @Override
147 public void end(String namespace, String name) throws Exception {
148 Attribute attribute = (Attribute) digester.pop();
149 TagXml tag = (TagXml) digester.peek();
150 tag.getAttributes().add(attribute.toTagAttributeInfo());
151 }
152 }
153
154 public static class Attribute {
155 private final boolean allowShortNames;
156 private String name;
157 private boolean required;
158 private String type;
159 private boolean requestTime;
160 private boolean fragment;
161 private String description;
162 private boolean deferredValue;
163 private boolean deferredMethod;
164 private String expectedTypeName;
165 private String methodSignature;
166
167 private Attribute(boolean allowShortNames) {
168 this.allowShortNames = allowShortNames;
169 }
170
171 public void setName(String name) {
172 this.name = name;
173 }
174
175 public void setRequired(boolean required) {
176 this.required = required;
177 }
178
179 public void setType(String type) {
180 if (allowShortNames) {
181 switch (type) {
182 case "Boolean":
183 this.type = "java.lang.Boolean";
184 break;
185 case "Character":
186 this.type = "java.lang.Character";
187 break;
188 case "Byte":
189 this.type = "java.lang.Byte";
190 break;
191 case "Short":
192 this.type = "java.lang.Short";
193 break;
194 case "Integer":
195 this.type = "java.lang.Integer";
196 break;
197 case "Long":
198 this.type = "java.lang.Long";
199 break;
200 case "Float":
201 this.type = "java.lang.Float";
202 break;
203 case "Double":
204 this.type = "java.lang.Double";
205 break;
206 case "String":
207 this.type = "java.lang.String";
208 break;
209 case "Object":
210 this.type = "java.lang.Object";
211 break;
212 default:
213 this.type = type;
214 break;
215 }
216 } else {
217 this.type = type;
218 }
219 }
220
221 public void setRequestTime(boolean requestTime) {
222 this.requestTime = requestTime;
223 }
224
225 public void setFragment(boolean fragment) {
226 this.fragment = fragment;
227 }
228
229 public void setDescription(String description) {
230 this.description = description;
231 }
232
233 public void setDeferredValue() {
234 this.deferredValue = true;
235 }
236
237 public void setDeferredMethod() {
238 this.deferredMethod = true;
239 }
240
241 public void setExpectedTypeName(String expectedTypeName) {
242 this.expectedTypeName = expectedTypeName;
243 }
244
245 public void setMethodSignature(String methodSignature) {
246 this.methodSignature = methodSignature;
247 }
248
249 public TagAttributeInfo toTagAttributeInfo() {
250 if (fragment) {
251
252 type = "javax.servlet.jsp.tagext.JspFragment";
253 requestTime = true;
254 } else if (deferredValue) {
255 type = "javax.el.ValueExpression";
256 if (expectedTypeName == null) {
257 expectedTypeName = "java.lang.Object";
258 }
259 } else if (deferredMethod) {
260 type = "javax.el.MethodExpression";
261 if (methodSignature == null) {
262 methodSignature = "java.lang.Object method()";
263 }
264 }
265
266
267
268 if (!requestTime && type == null) {
269 type = "java.lang.String";
270 }
271
272 return new TagAttributeInfo(
273 name,
274 required,
275 type,
276 requestTime,
277 fragment,
278 description,
279 deferredValue,
280 deferredMethod,
281 expectedTypeName,
282 methodSignature);
283 }
284 }
285
286 private static class ScriptVariableRule extends Rule {
287 @Override
288 public void begin(String namespace, String name, Attributes attributes) throws Exception {
289 digester.push(new Variable());
290 }
291
292 @Override
293 public void end(String namespace, String name) throws Exception {
294 Variable variable = (Variable) digester.pop();
295 TagXml tag = (TagXml) digester.peek();
296 tag.getVariables().add(variable.toTagVariableInfo());
297 }
298 }
299
300 public static class Variable {
301 private String nameGiven;
302 private String nameFromAttribute;
303 private String className = "java.lang.String";
304 private boolean declare = true;
305 private int scope = VariableInfo.NESTED;
306
307 public void setNameGiven(String nameGiven) {
308 this.nameGiven = nameGiven;
309 }
310
311 public void setNameFromAttribute(String nameFromAttribute) {
312 this.nameFromAttribute = nameFromAttribute;
313 }
314
315 public void setClassName(String className) {
316 this.className = className;
317 }
318
319 public void setDeclare(boolean declare) {
320 this.declare = declare;
321 }
322
323 public void setScope(String scopeName) {
324 switch (scopeName) {
325 case "NESTED":
326 scope = VariableInfo.NESTED;
327 break;
328 case "AT_BEGIN":
329 scope = VariableInfo.AT_BEGIN;
330 break;
331 case "AT_END":
332 scope = VariableInfo.AT_END;
333 break;
334 }
335 }
336
337 public TagVariableInfo toTagVariableInfo() {
338 return new TagVariableInfo(nameGiven, nameFromAttribute, className, declare, scope);
339 }
340 }
341
342 private static class GenericBooleanRule extends Rule {
343 private final Method setter;
344
345 private GenericBooleanRule(Class<?> type, String setterName) {
346 try {
347 this.setter = type.getMethod(setterName, Boolean.TYPE);
348 } catch (NoSuchMethodException e) {
349 throw new IllegalArgumentException(e);
350 }
351 }
352
353 @Override
354 public void body(String namespace, String name, String text) throws Exception {
355 if(null != text)
356 text = text.trim();
357 boolean value = "true".equalsIgnoreCase(text) || "yes".equalsIgnoreCase(text);
358 setter.invoke(digester.peek(), Boolean.valueOf(value));
359 }
360 }
361 }
362