1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts2.jasper.compiler;
19
20 import com.opensymphony.xwork2.util.logging.Logger;
21 import com.opensymphony.xwork2.util.logging.LoggerFactory;
22 import org.apache.struts2.jasper.JasperException;
23 import org.apache.struts2.jasper.JspCompilationContext;
24 import org.apache.struts2.jasper.xmlparser.ParserUtils;
25 import org.apache.struts2.jasper.xmlparser.TreeNode;
26
27 import javax.servlet.jsp.tagext.*;
28 import java.io.*;
29 import java.net.JarURLConnection;
30 import java.net.URL;
31 import java.util.*;
32 import java.util.jar.JarFile;
33 import java.util.zip.ZipEntry;
34
35 /***
36 * Implementation of the TagLibraryInfo class from the JSP spec.
37 *
38 * @author Anil K. Vijendran
39 * @author Mandar Raje
40 * @author Pierre Delisle
41 * @author Kin-man Chung
42 * @author Jan Luehe
43 */
44 class TagLibraryInfoImpl extends TagLibraryInfo implements TagConstants {
45
46
47 private Logger log = LoggerFactory.getLogger(TagLibraryInfoImpl.class);
48
49 private Hashtable jarEntries;
50 private JspCompilationContext ctxt;
51 private ErrorDispatcher err;
52 private ParserController parserController;
53
54 private final void print(String name, String value, PrintWriter w) {
55 if (value != null) {
56 w.print(name + " = {\n\t");
57 w.print(value);
58 w.print("\n}\n");
59 }
60 }
61
62 public String toString() {
63 StringWriter sw = new StringWriter();
64 PrintWriter out = new PrintWriter(sw);
65 print("tlibversion", tlibversion, out);
66 print("jspversion", jspversion, out);
67 print("shortname", shortname, out);
68 print("urn", urn, out);
69 print("info", info, out);
70 print("uri", uri, out);
71 print("tagLibraryValidator", "" + tagLibraryValidator, out);
72
73 for (int i = 0; i < tags.length; i++)
74 out.println(tags[i].toString());
75
76 for (int i = 0; i < tagFiles.length; i++)
77 out.println(tagFiles[i].toString());
78
79 for (int i = 0; i < functions.length; i++)
80 out.println(functions[i].toString());
81
82 return sw.toString();
83 }
84
85
86
87
88
89 private InputStream getResourceAsStream(String uri)
90 throws FileNotFoundException {
91 try {
92
93 String real = ctxt.getRealPath(uri);
94 if (real == null) {
95 return ctxt.getResourceAsStream(uri);
96 } else {
97 return new FileInputStream(real);
98 }
99 }
100 catch (FileNotFoundException ex) {
101
102
103 return ctxt.getResourceAsStream(uri);
104 }
105
106 }
107
108 /***
109 * Constructor.
110 */
111 public TagLibraryInfoImpl(JspCompilationContext ctxt,
112 ParserController pc,
113 String prefix,
114 String uriIn,
115 String[] location,
116 ErrorDispatcher err) throws JasperException {
117 super(prefix, uriIn);
118
119 this.ctxt = ctxt;
120 this.parserController = pc;
121 this.err = err;
122 InputStream in = null;
123 JarFile jarFile = null;
124
125 if (location == null) {
126
127
128 location = generateTLDLocation(uri, ctxt);
129 }
130
131 try {
132 if (!location[0].endsWith("jar")) {
133
134 try {
135 in = getResourceAsStream(location[0]);
136 if (in == null) {
137 throw new FileNotFoundException(location[0]);
138 }
139 } catch (FileNotFoundException ex) {
140 err.jspError("jsp.error.file.not.found", location[0]);
141 }
142
143 parseTLD(ctxt, location[0], in, null);
144
145 PageInfo pageInfo = ctxt.createCompiler().getPageInfo();
146 if (pageInfo != null) {
147 pageInfo.addDependant(location[0]);
148 }
149 } else {
150
151 try {
152 URL jarFileUrl = new URL("jar:" + location[0] + "!/");
153 JarURLConnection conn =
154 (JarURLConnection) jarFileUrl.openConnection();
155 conn.setUseCaches(false);
156 conn.connect();
157 jarFile = conn.getJarFile();
158 ZipEntry jarEntry = jarFile.getEntry(location[1]);
159 in = jarFile.getInputStream(jarEntry);
160 parseTLD(ctxt, location[0], in, jarFileUrl);
161 } catch (Exception ex) {
162 err.jspError("jsp.error.tld.unable_to_read", location[0],
163 location[1], ex.toString());
164 }
165 }
166 } finally {
167 if (in != null) {
168 try {
169 in.close();
170 } catch (Throwable t) {
171 }
172 }
173 if (jarFile != null) {
174 try {
175 jarFile.close();
176 } catch (Throwable t) {
177 }
178 }
179 }
180
181 }
182
183
184
185
186
187
188
189
190 private void parseTLD(JspCompilationContext ctxt,
191 String uri, InputStream in, URL jarFileUrl)
192 throws JasperException {
193 Vector tagVector = new Vector();
194 Vector tagFileVector = new Vector();
195 Hashtable functionTable = new Hashtable();
196
197
198 ParserUtils pu = new ParserUtils();
199 TreeNode tld = pu.parseXMLDocument(uri, in);
200
201
202
203
204 this.jspversion = tld.findAttribute("version");
205
206
207 Iterator list = tld.findChildren();
208
209 while (list.hasNext()) {
210 TreeNode element = (TreeNode) list.next();
211 String tname = element.getName();
212
213 if ("tlibversion".equals(tname)
214 || "tlib-version".equals(tname)) {
215 this.tlibversion = element.getBody();
216 } else if ("jspversion".equals(tname)
217 || "jsp-version".equals(tname)) {
218 this.jspversion = element.getBody();
219 } else if ("shortname".equals(tname) ||
220 "short-name".equals(tname))
221 this.shortname = element.getBody();
222 else if ("uri".equals(tname))
223 this.urn = element.getBody();
224 else if ("info".equals(tname) ||
225 "description".equals(tname))
226 this.info = element.getBody();
227 else if ("validator".equals(tname))
228 this.tagLibraryValidator = createValidator(element);
229 else if ("tag".equals(tname))
230 tagVector.addElement(createTagInfo(element, jspversion));
231 else if ("tag-file".equals(tname)) {
232 TagFileInfo tagFileInfo = createTagFileInfo(element, uri,
233 jarFileUrl);
234 tagFileVector.addElement(tagFileInfo);
235 } else if ("function".equals(tname)) {
236 FunctionInfo funcInfo = createFunctionInfo(element);
237 String funcName = funcInfo.getName();
238 if (functionTable.containsKey(funcName)) {
239 err.jspError("jsp.error.tld.fn.duplicate.name",
240 funcName, uri);
241
242 }
243 functionTable.put(funcName, funcInfo);
244 } else if ("display-name".equals(tname) ||
245 "small-icon".equals(tname) ||
246 "large-icon".equals(tname) ||
247 "listener".equals(tname)) {
248 ;
249 } else if ("taglib-extension".equals(tname)) {
250
251 } else {
252 if (log.isWarnEnabled()) {
253 log.warn(Localizer.getMessage(
254 "jsp.warning.unknown.element.in.taglib", tname));
255 }
256 }
257
258 }
259
260 if (tlibversion == null) {
261 err.jspError("jsp.error.tld.mandatory.element.missing",
262 "tlib-version");
263 }
264 if (jspversion == null) {
265 err.jspError("jsp.error.tld.mandatory.element.missing",
266 "jsp-version");
267 }
268
269 this.tags = new TagInfo[tagVector.size()];
270 tagVector.copyInto(this.tags);
271
272 this.tagFiles = new TagFileInfo[tagFileVector.size()];
273 tagFileVector.copyInto(this.tagFiles);
274
275 this.functions = new FunctionInfo[functionTable.size()];
276 int i = 0;
277 Enumeration enumeration = functionTable.elements();
278 while (enumeration.hasMoreElements()) {
279 this.functions[i++] = (FunctionInfo) enumeration.nextElement();
280 }
281 }
282
283
284
285
286
287
288
289
290
291
292 private String[] generateTLDLocation(String uri,
293 JspCompilationContext ctxt)
294 throws JasperException {
295
296 int uriType = TldLocationsCache.uriType(uri);
297 if (uriType == TldLocationsCache.ABS_URI) {
298 err.jspError("jsp.error.taglibDirective.absUriCannotBeResolved",
299 uri);
300 } else if (uriType == TldLocationsCache.NOROOT_REL_URI) {
301
302
303 }
304
305 String[] location = new String[2];
306 location[0] = uri;
307 if (location[0].endsWith("jar")) {
308 URL url = null;
309 try {
310 url = ctxt.getResource(location[0]);
311 } catch (Exception ex) {
312 err.jspError("jsp.error.tld.unable_to_get_jar", location[0],
313 ex.toString());
314 }
315 if (url == null) {
316 err.jspError("jsp.error.tld.missing_jar", location[0]);
317 }
318 location[0] = url.toString();
319 location[1] = "META-INF/taglib.tld";
320 }
321
322 return location;
323 }
324
325 private TagInfo createTagInfo(TreeNode elem, String jspVersion)
326 throws JasperException {
327
328 String tagName = null;
329 String tagClassName = null;
330 String teiClassName = null;
331
332
333
334
335
336
337 String bodycontent = "JSP";
338
339 String info = null;
340 String displayName = null;
341 String smallIcon = null;
342 String largeIcon = null;
343 boolean dynamicAttributes = false;
344
345 Vector attributeVector = new Vector();
346 Vector variableVector = new Vector();
347 Iterator list = elem.findChildren();
348 while (list.hasNext()) {
349 TreeNode element = (TreeNode) list.next();
350 String tname = element.getName();
351
352 if ("name".equals(tname)) {
353 tagName = element.getBody();
354 } else if ("tagclass".equals(tname) ||
355 "tag-class".equals(tname)) {
356 tagClassName = element.getBody();
357 } else if ("teiclass".equals(tname) ||
358 "tei-class".equals(tname)) {
359 teiClassName = element.getBody();
360 } else if ("bodycontent".equals(tname) ||
361 "body-content".equals(tname)) {
362 bodycontent = element.getBody();
363 } else if ("display-name".equals(tname)) {
364 displayName = element.getBody();
365 } else if ("small-icon".equals(tname)) {
366 smallIcon = element.getBody();
367 } else if ("large-icon".equals(tname)) {
368 largeIcon = element.getBody();
369 } else if ("icon".equals(tname)) {
370 TreeNode icon = element.findChild("small-icon");
371 if (icon != null) {
372 smallIcon = icon.getBody();
373 }
374 icon = element.findChild("large-icon");
375 if (icon != null) {
376 largeIcon = icon.getBody();
377 }
378 } else if ("info".equals(tname) ||
379 "description".equals(tname)) {
380 info = element.getBody();
381 } else if ("variable".equals(tname)) {
382 variableVector.addElement(createVariable(element));
383 } else if ("attribute".equals(tname)) {
384 attributeVector.addElement(createAttribute(element, jspVersion));
385 } else if ("dynamic-attributes".equals(tname)) {
386 dynamicAttributes = JspUtil.booleanValue(element.getBody());
387 } else if ("example".equals(tname)) {
388
389 } else if ("tag-extension".equals(tname)) {
390
391 } else {
392 if (log.isWarnEnabled()) {
393 log.warn(Localizer.getMessage(
394 "jsp.warning.unknown.element.in.tag", tname));
395 }
396 }
397 }
398
399 TagExtraInfo tei = null;
400 if (teiClassName != null && !teiClassName.equals("")) {
401 try {
402 Class teiClass = ctxt.getClassLoader().loadClass(teiClassName);
403 tei = (TagExtraInfo) teiClass.newInstance();
404 } catch (Exception e) {
405 err.jspError("jsp.error.teiclass.instantiation", teiClassName,
406 e);
407 }
408 }
409
410 TagAttributeInfo[] tagAttributeInfo
411 = new TagAttributeInfo[attributeVector.size()];
412 attributeVector.copyInto(tagAttributeInfo);
413
414 TagVariableInfo[] tagVariableInfos
415 = new TagVariableInfo[variableVector.size()];
416 variableVector.copyInto(tagVariableInfos);
417
418 TagInfo taginfo = new TagInfo(tagName,
419 tagClassName,
420 bodycontent,
421 info,
422 this,
423 tei,
424 tagAttributeInfo,
425 displayName,
426 smallIcon,
427 largeIcon,
428 tagVariableInfos,
429 dynamicAttributes);
430 return taginfo;
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444 private TagFileInfo createTagFileInfo(TreeNode elem, String uri,
445 URL jarFileUrl)
446 throws JasperException {
447
448 String name = null;
449 String path = null;
450
451 Iterator list = elem.findChildren();
452 while (list.hasNext()) {
453 TreeNode child = (TreeNode) list.next();
454 String tname = child.getName();
455 if ("name".equals(tname)) {
456 name = child.getBody();
457 } else if ("path".equals(tname)) {
458 path = child.getBody();
459 } else if ("example".equals(tname)) {
460
461 } else if ("tag-extension".equals(tname)) {
462
463 } else if ("icon".equals(tname) ||
464 "display-name".equals(tname) ||
465 "description".equals(tname)) {
466
467 } else {
468 if (log.isWarnEnabled()) {
469 log.warn(Localizer.getMessage(
470 "jsp.warning.unknown.element.in.tagfile", tname));
471 }
472 }
473 }
474
475 if (path.startsWith("/META-INF/tags")) {
476
477
478
479 if (jarFileUrl != null) {
480 ctxt.getTagFileJarUrls().put(path, jarFileUrl);
481 }
482 } else if (!path.startsWith("/WEB-INF/tags")) {
483 err.jspError("jsp.error.tagfile.illegalPath", path);
484 }
485
486 TagInfo tagInfo
487 = TagFileProcessor.parseTagFileDirectives(parserController, name,
488 path, this);
489 return new TagFileInfo(name, path, tagInfo);
490 }
491
492 TagAttributeInfo createAttribute(TreeNode elem, String jspVersion) {
493 String name = null;
494 String type = null;
495 boolean required = false, rtexprvalue = false, reqTime = false,
496 isFragment = false;
497
498 Iterator list = elem.findChildren();
499 while (list.hasNext()) {
500 TreeNode element = (TreeNode) list.next();
501 String tname = element.getName();
502
503 if ("name".equals(tname)) {
504 name = element.getBody();
505 } else if ("required".equals(tname)) {
506 String s = element.getBody();
507 if (s != null)
508 required = JspUtil.booleanValue(s);
509 } else if ("rtexprvalue".equals(tname)) {
510 String s = element.getBody();
511 if (s != null)
512 rtexprvalue = JspUtil.booleanValue(s);
513 } else if ("type".equals(tname)) {
514 type = element.getBody();
515 if ("1.2".equals(jspVersion)
516 && (type.equals("Boolean")
517 || type.equals("Byte")
518 || type.equals("Character")
519 || type.equals("Double")
520 || type.equals("Float")
521 || type.equals("Integer")
522 || type.equals("Long")
523 || type.equals("Object")
524 || type.equals("Short")
525 || type.equals("String"))) {
526 type = "java.lang." + type;
527 }
528 } else if ("fragment".equals(tname)) {
529 String s = element.getBody();
530 if (s != null) {
531 isFragment = JspUtil.booleanValue(s);
532 }
533 } else if ("description".equals(tname) ||
534 false) {
535 ;
536 } else {
537 if (log.isWarnEnabled()) {
538 log.warn(Localizer.getMessage(
539 "jsp.warning.unknown.element.in.attribute", tname));
540 }
541 }
542 }
543
544 if (isFragment) {
545
546
547
548
549
550
551
552
553 type = "javax.servlet.jsp.tagext.JspFragment";
554 rtexprvalue = true;
555 }
556
557 if (!rtexprvalue) {
558
559
560 type = "java.lang.String";
561 }
562
563 return new TagAttributeInfo(name, required, type, rtexprvalue,
564 isFragment);
565 }
566
567 TagVariableInfo createVariable(TreeNode elem) {
568 String nameGiven = null;
569 String nameFromAttribute = null;
570 String className = "java.lang.String";
571 boolean declare = true;
572 int scope = VariableInfo.NESTED;
573
574 Iterator list = elem.findChildren();
575 while (list.hasNext()) {
576 TreeNode element = (TreeNode) list.next();
577 String tname = element.getName();
578 if ("name-given".equals(tname))
579 nameGiven = element.getBody();
580 else if ("name-from-attribute".equals(tname))
581 nameFromAttribute = element.getBody();
582 else if ("variable-class".equals(tname))
583 className = element.getBody();
584 else if ("declare".equals(tname)) {
585 String s = element.getBody();
586 if (s != null)
587 declare = JspUtil.booleanValue(s);
588 } else if ("scope".equals(tname)) {
589 String s = element.getBody();
590 if (s != null) {
591 if ("NESTED".equals(s)) {
592 scope = VariableInfo.NESTED;
593 } else if ("AT_BEGIN".equals(s)) {
594 scope = VariableInfo.AT_BEGIN;
595 } else if ("AT_END".equals(s)) {
596 scope = VariableInfo.AT_END;
597 }
598 }
599 } else if ("description".equals(tname) ||
600 false) {
601 } else {
602 if (log.isWarnEnabled()) {
603 log.warn(Localizer.getMessage(
604 "jsp.warning.unknown.element.in.variable", tname));
605 }
606 }
607 }
608 return new TagVariableInfo(nameGiven, nameFromAttribute,
609 className, declare, scope);
610 }
611
612 private TagLibraryValidator createValidator(TreeNode elem)
613 throws JasperException {
614
615 String validatorClass = null;
616 Map initParams = new Hashtable();
617
618 Iterator list = elem.findChildren();
619 while (list.hasNext()) {
620 TreeNode element = (TreeNode) list.next();
621 String tname = element.getName();
622 if ("validator-class".equals(tname))
623 validatorClass = element.getBody();
624 else if ("init-param".equals(tname)) {
625 String[] initParam = createInitParam(element);
626 initParams.put(initParam[0], initParam[1]);
627 } else if ("description".equals(tname) ||
628 false) {
629 } else {
630 if (log.isWarnEnabled()) {
631 log.warn(Localizer.getMessage(
632 "jsp.warning.unknown.element.in.validator", tname));
633 }
634 }
635 }
636
637 TagLibraryValidator tlv = null;
638 if (validatorClass != null && !validatorClass.equals("")) {
639 try {
640 Class tlvClass =
641 ctxt.getClassLoader().loadClass(validatorClass);
642 tlv = (TagLibraryValidator) tlvClass.newInstance();
643 } catch (Exception e) {
644 err.jspError("jsp.error.tlvclass.instantiation",
645 validatorClass, e);
646 }
647 }
648 if (tlv != null) {
649 tlv.setInitParameters(initParams);
650 }
651 return tlv;
652 }
653
654 String[] createInitParam(TreeNode elem) {
655 String[] initParam = new String[2];
656
657 Iterator list = elem.findChildren();
658 while (list.hasNext()) {
659 TreeNode element = (TreeNode) list.next();
660 String tname = element.getName();
661 if ("param-name".equals(tname)) {
662 initParam[0] = element.getBody();
663 } else if ("param-value".equals(tname)) {
664 initParam[1] = element.getBody();
665 } else if ("description".equals(tname)) {
666 ;
667 } else {
668 if (log.isWarnEnabled()) {
669 log.warn(Localizer.getMessage(
670 "jsp.warning.unknown.element.in.initParam", tname));
671 }
672 }
673 }
674 return initParam;
675 }
676
677 FunctionInfo createFunctionInfo(TreeNode elem) {
678
679 String name = null;
680 String klass = null;
681 String signature = null;
682
683 Iterator list = elem.findChildren();
684 while (list.hasNext()) {
685 TreeNode element = (TreeNode) list.next();
686 String tname = element.getName();
687
688 if ("name".equals(tname)) {
689 name = element.getBody();
690 } else if ("function-class".equals(tname)) {
691 klass = element.getBody();
692 } else if ("function-signature".equals(tname)) {
693 signature = element.getBody();
694 } else if ("display-name".equals(tname) ||
695 "small-icon".equals(tname) ||
696 "large-icon".equals(tname) ||
697 "description".equals(tname) ||
698 "example".equals(tname)) {
699 } else {
700 if (log.isWarnEnabled()) {
701 log.warn(Localizer.getMessage(
702 "jsp.warning.unknown.element.in.function", tname));
703 }
704 }
705 }
706
707 return new FunctionInfo(name, klass, signature);
708 }
709
710
711 //**********************************************************************
712 // Until javax.servlet.jsp.tagext.TagLibraryInfo is fixed
713
714 /**
715 * The instance (if any) for the TagLibraryValidator class.
716 *
717 * @return The TagLibraryValidator instance, if any.
718 */
719 public TagLibraryValidator getTagLibraryValidator() {
720 return tagLibraryValidator;
721 }
722
723 /***
724 * Translation-time validation of the XML document
725 * associated with the JSP page.
726 * This is a convenience method on the associated
727 * TagLibraryValidator class.
728 *
729 * @param thePage The JSP page object
730 * @return A string indicating whether the page is valid or not.
731 */
732 public ValidationMessage[] validate(PageData thePage) {
733 TagLibraryValidator tlv = getTagLibraryValidator();
734 if (tlv == null) return null;
735
736 String uri = getURI();
737 if (uri.startsWith("/")) {
738 uri = URN_JSPTLD + uri;
739 }
740
741 return tlv.validate(getPrefixString(), uri, thePage);
742 }
743
744 protected TagLibraryValidator tagLibraryValidator;
745 }