View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.struts2.jasper.compiler;
19  
20  import org.apache.struts2.jasper.JasperException;
21  import org.apache.struts2.jasper.compiler.tagplugin.TagPluginContext;
22  import org.xml.sax.Attributes;
23  
24  import javax.servlet.jsp.tagext.*;
25  import java.util.ArrayList;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Vector;
29  
30  
31  /***
32   * An internal data representation of a JSP page or a JSP docuement (XML).
33   * Also included here is a visitor class for tranversing nodes.
34   *
35   * @author Kin-man Chung
36   * @author Jan Luehe
37   * @author Shawn Bayern
38   * @author Mark Roth
39   */
40  
41  abstract class Node implements TagConstants {
42  
43      private static final VariableInfo[] ZERO_VARIABLE_INFO = {};
44  
45      protected Attributes attrs;
46  
47      // xmlns attributes that represent tag libraries (only in XML syntax)
48      protected Attributes taglibAttrs;
49  
50      /*
51       * xmlns attributes that do not represent tag libraries
52       * (only in XML syntax)
53       */
54      protected Attributes nonTaglibXmlnsAttrs;
55  
56      protected Nodes body;
57      protected String text;
58      protected Mark startMark;
59      protected int beginJavaLine;
60      protected int endJavaLine;
61      protected Node parent;
62      protected Nodes namedAttributeNodes; // cached for performance
63      protected String qName;
64      protected String localName;
65      /*
66       * The name of the inner class to which the codes for this node and
67       * its body are generated.  For instance, for <jsp:body> in foo.jsp,
68       * this is "foo_jspHelper".  This is primarily used for communicating
69       * such info from Generator to Smap generator.
70       */
71      protected String innerClassName;
72  
73      private boolean isDummy;
74  
75      /***
76       * Zero-arg Constructor.
77       */
78      public Node() {
79          this.isDummy = true;
80      }
81  
82      /***
83       * Constructor.
84       *
85       * @param start  The location of the jsp page
86       * @param parent The enclosing node
87       */
88      public Node(Mark start, Node parent) {
89          this.startMark = start;
90          this.isDummy = (start == null);
91          addToParent(parent);
92      }
93  
94      /***
95       * Constructor.
96       *
97       * @param qName     The action's qualified name
98       * @param localName The action's local name
99       * @param start     The location of the jsp page
100      * @param parent    The enclosing node
101      */
102     public Node(String qName, String localName, Mark start, Node parent) {
103         this.qName = qName;
104         this.localName = localName;
105         this.startMark = start;
106         this.isDummy = (start == null);
107         addToParent(parent);
108     }
109 
110     /***
111      * Constructor for Nodes parsed from standard syntax.
112      *
113      * @param qName     The action's qualified name
114      * @param localName The action's local name
115      * @param attrs     The attributes for this node
116      * @param start     The location of the jsp page
117      * @param parent    The enclosing node
118      */
119     public Node(String qName, String localName, Attributes attrs, Mark start,
120                 Node parent) {
121         this.qName = qName;
122         this.localName = localName;
123         this.attrs = attrs;
124         this.startMark = start;
125         this.isDummy = (start == null);
126         addToParent(parent);
127     }
128 
129     /***
130      * Constructor for Nodes parsed from XML syntax.
131      *
132      * @param qName               The action's qualified name
133      * @param localName           The action's local name
134      * @param attrs               The action's attributes whose name does not start with
135      *                            xmlns
136      * @param nonTaglibXmlnsAttrs The action's xmlns attributes that do not
137      *                            represent tag libraries
138      * @param taglibAttrs         The action's xmlns attributes that represent tag
139      *                            libraries
140      * @param start               The location of the jsp page
141      * @param parent              The enclosing node
142      */
143     public Node(String qName, String localName, Attributes attrs,
144                 Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs,
145                 Mark start, Node parent) {
146         this.qName = qName;
147         this.localName = localName;
148         this.attrs = attrs;
149         this.nonTaglibXmlnsAttrs = nonTaglibXmlnsAttrs;
150         this.taglibAttrs = taglibAttrs;
151         this.startMark = start;
152         this.isDummy = (start == null);
153         addToParent(parent);
154     }
155 
156     /*
157      * Constructor.
158      *
159      * @param qName The action's qualified name
160      * @param localName The action's local name
161      * @param text The text associated with this node
162      * @param start The location of the jsp page
163      * @param parent The enclosing node
164      */
165     public Node(String qName, String localName, String text, Mark start,
166                 Node parent) {
167         this.qName = qName;
168         this.localName = localName;
169         this.text = text;
170         this.startMark = start;
171         this.isDummy = (start == null);
172         addToParent(parent);
173     }
174 
175     public String getQName() {
176         return this.qName;
177     }
178 
179     public String getLocalName() {
180         return this.localName;
181     }
182 
183     /*
184      * Gets this Node's attributes.
185      *
186      * In the case of a Node parsed from standard syntax, this method returns
187      * all the Node's attributes.
188      *
189      * In the case of a Node parsed from XML syntax, this method returns only
190      * those attributes whose name does not start with xmlns.
191      */
192     public Attributes getAttributes() {
193         return this.attrs;
194     }
195 
196     /*
197      * Gets this Node's xmlns attributes that represent tag libraries
198      * (only meaningful for Nodes parsed from XML syntax)
199      */
200     public Attributes getTaglibAttributes() {
201         return this.taglibAttrs;
202     }
203 
204     /*
205      * Gets this Node's xmlns attributes that do not represent tag libraries
206      * (only meaningful for Nodes parsed from XML syntax)
207      */
208     public Attributes getNonTaglibXmlnsAttributes() {
209         return this.nonTaglibXmlnsAttrs;
210     }
211 
212     public void setAttributes(Attributes attrs) {
213         this.attrs = attrs;
214     }
215 
216     public String getAttributeValue(String name) {
217         return (attrs == null) ? null : attrs.getValue(name);
218     }
219 
220     /***
221      * Get the attribute that is non request time expression, either
222      * from the attribute of the node, or from a jsp:attrbute
223      */
224     public String getTextAttribute(String name) {
225 
226         String attr = getAttributeValue(name);
227         if (attr != null) {
228             return attr;
229         }
230 
231         NamedAttribute namedAttribute = getNamedAttributeNode(name);
232         if (namedAttribute == null) {
233             return null;
234         }
235 
236         return namedAttribute.getText();
237     }
238 
239     /***
240      * Searches all subnodes of this node for jsp:attribute standard
241      * actions with the given name, and returns the NamedAttribute node
242      * of the matching named attribute, nor null if no such node is found.
243      * <p/>
244      * This should always be called and only be called for nodes that
245      * accept dynamic runtime attribute expressions.
246      */
247     public NamedAttribute getNamedAttributeNode(String name) {
248         NamedAttribute result = null;
249 
250         // Look for the attribute in NamedAttribute children
251         Nodes nodes = getNamedAttributeNodes();
252         int numChildNodes = nodes.size();
253         for (int i = 0; i < numChildNodes; i++) {
254             NamedAttribute na = (NamedAttribute) nodes.getNode(i);
255             boolean found = false;
256             int index = name.indexOf(':');
257             if (index != -1) {
258                 // qualified name
259                 found = na.getName().equals(name);
260             } else {
261                 found = na.getLocalName().equals(name);
262             }
263             if (found) {
264                 result = na;
265                 break;
266             }
267         }
268 
269         return result;
270     }
271 
272     /***
273      * Searches all subnodes of this node for jsp:attribute standard
274      * actions, and returns that set of nodes as a Node.Nodes object.
275      *
276      * @return Possibly empty Node.Nodes object containing any jsp:attribute
277      *         subnodes of this Node
278      */
279     public Node.Nodes getNamedAttributeNodes() {
280 
281         if (namedAttributeNodes != null) {
282             return namedAttributeNodes;
283         }
284 
285         Node.Nodes result = new Node.Nodes();
286 
287         // Look for the attribute in NamedAttribute children
288         Nodes nodes = getBody();
289         if (nodes != null) {
290             int numChildNodes = nodes.size();
291             for (int i = 0; i < numChildNodes; i++) {
292                 Node n = nodes.getNode(i);
293                 if (n instanceof NamedAttribute) {
294                     result.add(n);
295                 } else if (!(n instanceof Comment)) {
296                     // Nothing can come before jsp:attribute, and only
297                     // jsp:body can come after it.
298                     break;
299                 }
300             }
301         }
302 
303         namedAttributeNodes = result;
304         return result;
305     }
306 
307     public Nodes getBody() {
308         return body;
309     }
310 
311     public void setBody(Nodes body) {
312         this.body = body;
313     }
314 
315     public String getText() {
316         return text;
317     }
318 
319     public Mark getStart() {
320         return startMark;
321     }
322 
323     public Node getParent() {
324         return parent;
325     }
326 
327     public int getBeginJavaLine() {
328         return beginJavaLine;
329     }
330 
331     public void setBeginJavaLine(int begin) {
332         beginJavaLine = begin;
333     }
334 
335     public int getEndJavaLine() {
336         return endJavaLine;
337     }
338 
339     public void setEndJavaLine(int end) {
340         endJavaLine = end;
341     }
342 
343     public boolean isDummy() {
344         return isDummy;
345     }
346 
347     public Node.Root getRoot() {
348         Node n = this;
349         while (!(n instanceof Node.Root)) {
350             n = n.getParent();
351         }
352         return (Node.Root) n;
353     }
354 
355     public String getInnerClassName() {
356         return innerClassName;
357     }
358 
359     public void setInnerClassName(String icn) {
360         innerClassName = icn;
361     }
362 
363     /***
364      * Selects and invokes a method in the visitor class based on the node
365      * type.  This is abstract and should be overrode by the extending classes.
366      *
367      * @param v The visitor class
368      */
369     abstract void accept(Visitor v) throws JasperException;
370 
371 
372     //**********************************************************************
373     // Private utility methods
374 
375     /*
376      * Adds this Node to the body of the given parent.
377      */
378 
379     private void addToParent(Node parent) {
380         if (parent != null) {
381             this.parent = parent;
382             Nodes parentBody = parent.getBody();
383             if (parentBody == null) {
384                 parentBody = new Nodes();
385                 parent.setBody(parentBody);
386             }
387             parentBody.add(this);
388         }
389     }
390 
391 
392     /**********************************************************************
393      * Child classes
394      */
395 
396     /***
397      * Represents the root of a Jsp page or Jsp document
398      */
399     public static class Root extends Node {
400 
401         private Root parentRoot;
402         private boolean isXmlSyntax;
403 
404         // Source encoding of the page containing this Root
405         private String pageEnc;
406 
407         // Page encoding specified in JSP config element
408         private String jspConfigPageEnc;
409 
410         /*
411          * Flag indicating if the default page encoding is being used (only
412          * applicable with standard syntax).
413          *
414          * True if the page does not provide a page directive with a
415          * 'contentType' attribute (or the 'contentType' attribute doesn't
416          * have a CHARSET value), the page does not provide a page directive
417          * with a 'pageEncoding' attribute, and there is no JSP configuration
418          * element page-encoding whose URL pattern matches the page.
419          */
420         private boolean isDefaultPageEncoding;
421 
422         /*
423          * Indicates whether an encoding has been explicitly specified in the
424          * page's XML prolog (only used for pages in XML syntax).
425          * This information is used to decide whether a translation error must
426          * be reported for encoding conflicts.
427          */
428         private boolean isEncodingSpecifiedInProlog;
429 
430         /*
431          * Constructor.
432          */
433         Root(Mark start, Node parent, boolean isXmlSyntax) {
434             super(start, parent);
435             this.isXmlSyntax = isXmlSyntax;
436             this.qName = JSP_ROOT_ACTION;
437             this.localName = ROOT_ACTION;
438 
439             // Figure out and set the parent root
440             Node r = parent;
441             while ((r != null) && !(r instanceof Node.Root))
442                 r = r.getParent();
443             parentRoot = (Node.Root) r;
444         }
445 
446         public void accept(Visitor v) throws JasperException {
447             v.visit(this);
448         }
449 
450         public boolean isXmlSyntax() {
451             return isXmlSyntax;
452         }
453 
454         /*
455          * Sets the encoding specified in the JSP config element whose URL
456          * pattern matches the page containing this Root.
457          */
458         public void setJspConfigPageEncoding(String enc) {
459             jspConfigPageEnc = enc;
460         }
461 
462         /*
463          * Gets the encoding specified in the JSP config element whose URL
464          * pattern matches the page containing this Root.
465          */
466         public String getJspConfigPageEncoding() {
467             return jspConfigPageEnc;
468         }
469 
470         public void setPageEncoding(String enc) {
471             pageEnc = enc;
472         }
473 
474         public String getPageEncoding() {
475             return pageEnc;
476         }
477 
478         public void setIsDefaultPageEncoding(boolean isDefault) {
479             isDefaultPageEncoding = isDefault;
480         }
481 
482         public boolean isDefaultPageEncoding() {
483             return isDefaultPageEncoding;
484         }
485 
486         public void setIsEncodingSpecifiedInProlog(boolean isSpecified) {
487             isEncodingSpecifiedInProlog = isSpecified;
488         }
489 
490         public boolean isEncodingSpecifiedInProlog() {
491             return isEncodingSpecifiedInProlog;
492         }
493 
494         /***
495          * @return The enclosing root to this Root. Usually represents the
496          *         page that includes this one.
497          */
498         public Root getParentRoot() {
499             return parentRoot;
500         }
501     }
502 
503     /***
504      * Represents the root of a Jsp document (XML syntax)
505      */
506     public static class JspRoot extends Node {
507 
508         public JspRoot(String qName, Attributes attrs,
509                        Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs,
510                        Mark start, Node parent) {
511             super(qName, ROOT_ACTION, attrs, nonTaglibXmlnsAttrs, taglibAttrs,
512                     start, parent);
513         }
514 
515         public void accept(Visitor v) throws JasperException {
516             v.visit(this);
517         }
518     }
519 
520     /***
521      * Represents a page directive
522      */
523     public static class PageDirective extends Node {
524 
525         private Vector imports;
526 
527         public PageDirective(Attributes attrs, Mark start, Node parent) {
528             this(JSP_PAGE_DIRECTIVE_ACTION, attrs, null, null, start, parent);
529         }
530 
531         public PageDirective(String qName, Attributes attrs,
532                              Attributes nonTaglibXmlnsAttrs,
533                              Attributes taglibAttrs, Mark start, Node parent) {
534             super(qName, PAGE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs,
535                     taglibAttrs, start, parent);
536             imports = new Vector();
537         }
538 
539         public void accept(Visitor v) throws JasperException {
540             v.visit(this);
541         }
542 
543         /***
544          * Parses the comma-separated list of class or package names in the
545          * given attribute value and adds each component to this
546          * PageDirective's vector of imported classes and packages.
547          *
548          * @param value A comma-separated string of imports.
549          */
550         public void addImport(String value) {
551             int start = 0;
552             int index;
553             while ((index = value.indexOf(',', start)) != -1) {
554                 imports.add(value.substring(start, index).trim());
555                 start = index + 1;
556             }
557             if (start == 0) {
558                 // No comma found
559                 imports.add(value.trim());
560             } else {
561                 imports.add(value.substring(start).trim());
562             }
563         }
564 
565         public List getImports() {
566             return imports;
567         }
568     }
569 
570     /***
571      * Represents an include directive
572      */
573     public static class IncludeDirective extends Node {
574 
575         public IncludeDirective(Attributes attrs, Mark start, Node parent) {
576             this(JSP_INCLUDE_DIRECTIVE_ACTION, attrs, null, null, start,
577                     parent);
578         }
579 
580         public IncludeDirective(String qName, Attributes attrs,
581                                 Attributes nonTaglibXmlnsAttrs,
582                                 Attributes taglibAttrs, Mark start,
583                                 Node parent) {
584             super(qName, INCLUDE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs,
585                     taglibAttrs, start, parent);
586         }
587 
588         public void accept(Visitor v) throws JasperException {
589             v.visit(this);
590         }
591     }
592 
593     /***
594      * Represents a custom taglib directive
595      */
596     public static class TaglibDirective extends Node {
597 
598         public TaglibDirective(Attributes attrs, Mark start, Node parent) {
599             super(JSP_TAGLIB_DIRECTIVE_ACTION, TAGLIB_DIRECTIVE_ACTION, attrs,
600                     start, parent);
601         }
602 
603         public void accept(Visitor v) throws JasperException {
604             v.visit(this);
605         }
606     }
607 
608     /***
609      * Represents a tag directive
610      */
611     public static class TagDirective extends Node {
612         private Vector imports;
613 
614         public TagDirective(Attributes attrs, Mark start, Node parent) {
615             this(JSP_TAG_DIRECTIVE_ACTION, attrs, null, null, start, parent);
616         }
617 
618         public TagDirective(String qName, Attributes attrs,
619                             Attributes nonTaglibXmlnsAttrs,
620                             Attributes taglibAttrs, Mark start, Node parent) {
621             super(qName, TAG_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs,
622                     taglibAttrs, start, parent);
623             imports = new Vector();
624         }
625 
626         public void accept(Visitor v) throws JasperException {
627             v.visit(this);
628         }
629 
630         /***
631          * Parses the comma-separated list of class or package names in the
632          * given attribute value and adds each component to this
633          * PageDirective's vector of imported classes and packages.
634          *
635          * @param value A comma-separated string of imports.
636          */
637         public void addImport(String value) {
638             int start = 0;
639             int index;
640             while ((index = value.indexOf(',', start)) != -1) {
641                 imports.add(value.substring(start, index).trim());
642                 start = index + 1;
643             }
644             if (start == 0) {
645                 // No comma found
646                 imports.add(value.trim());
647             } else {
648                 imports.add(value.substring(start).trim());
649             }
650         }
651 
652         public List getImports() {
653             return imports;
654         }
655     }
656 
657     /***
658      * Represents an attribute directive
659      */
660     public static class AttributeDirective extends Node {
661 
662         public AttributeDirective(Attributes attrs, Mark start, Node parent) {
663             this(JSP_ATTRIBUTE_DIRECTIVE_ACTION, attrs, null, null, start,
664                     parent);
665         }
666 
667         public AttributeDirective(String qName, Attributes attrs,
668                                   Attributes nonTaglibXmlnsAttrs,
669                                   Attributes taglibAttrs, Mark start,
670                                   Node parent) {
671             super(qName, ATTRIBUTE_DIRECTIVE_ACTION, attrs,
672                     nonTaglibXmlnsAttrs, taglibAttrs, start, parent);
673         }
674 
675         public void accept(Visitor v) throws JasperException {
676             v.visit(this);
677         }
678     }
679 
680     /***
681      * Represents a variable directive
682      */
683     public static class VariableDirective extends Node {
684 
685         public VariableDirective(Attributes attrs, Mark start, Node parent) {
686             this(JSP_VARIABLE_DIRECTIVE_ACTION, attrs, null, null, start,
687                     parent);
688         }
689 
690         public VariableDirective(String qName, Attributes attrs,
691                                  Attributes nonTaglibXmlnsAttrs,
692                                  Attributes taglibAttrs,
693                                  Mark start, Node parent) {
694             super(qName, VARIABLE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs,
695                     taglibAttrs, start, parent);
696         }
697 
698         public void accept(Visitor v) throws JasperException {
699             v.visit(this);
700         }
701     }
702 
703     /***
704      * Represents a <jsp:invoke> tag file action
705      */
706     public static class InvokeAction extends Node {
707 
708         public InvokeAction(Attributes attrs, Mark start, Node parent) {
709             this(JSP_INVOKE_ACTION, attrs, null, null, start, parent);
710         }
711 
712         public InvokeAction(String qName, Attributes attrs,
713                             Attributes nonTaglibXmlnsAttrs,
714                             Attributes taglibAttrs, Mark start, Node parent) {
715             super(qName, INVOKE_ACTION, attrs, nonTaglibXmlnsAttrs,
716                     taglibAttrs, start, parent);
717         }
718 
719         public void accept(Visitor v) throws JasperException {
720             v.visit(this);
721         }
722     }
723 
724     /***
725      * Represents a <jsp:doBody> tag file action
726      */
727     public static class DoBodyAction extends Node {
728 
729         public DoBodyAction(Attributes attrs, Mark start, Node parent) {
730             this(JSP_DOBODY_ACTION, attrs, null, null, start, parent);
731         }
732 
733         public DoBodyAction(String qName, Attributes attrs,
734                             Attributes nonTaglibXmlnsAttrs,
735                             Attributes taglibAttrs, Mark start, Node parent) {
736             super(qName, DOBODY_ACTION, attrs, nonTaglibXmlnsAttrs,
737                     taglibAttrs, start, parent);
738         }
739 
740         public void accept(Visitor v) throws JasperException {
741             v.visit(this);
742         }
743     }
744 
745     /***
746      * Represents a Jsp comment
747      * Comments are kept for completeness.
748      */
749     public static class Comment extends Node {
750 
751         public Comment(String text, Mark start, Node parent) {
752             super(null, null, text, start, parent);
753         }
754 
755         public void accept(Visitor v) throws JasperException {
756             v.visit(this);
757         }
758     }
759 
760     /***
761      * Represents an expression, declaration, or scriptlet
762      */
763     public static abstract class ScriptingElement extends Node {
764 
765         public ScriptingElement(String qName, String localName, String text,
766                                 Mark start, Node parent) {
767             super(qName, localName, text, start, parent);
768         }
769 
770         public ScriptingElement(String qName, String localName,
771                                 Attributes nonTaglibXmlnsAttrs,
772                                 Attributes taglibAttrs, Mark start,
773                                 Node parent) {
774             super(qName, localName, null, nonTaglibXmlnsAttrs, taglibAttrs,
775                     start, parent);
776         }
777 
778         /***
779          * When this node was created from a JSP page in JSP syntax, its text
780          * was stored as a String in the "text" field, whereas when this node
781          * was created from a JSP document, its text was stored as one or more
782          * TemplateText nodes in its body. This method handles either case.
783          *
784          * @return The text string
785          */
786         public String getText() {
787             String ret = text;
788             if ((ret == null) && (body != null)) {
789                 StringBuffer buf = new StringBuffer();
790                 for (int i = 0; i < body.size(); i++) {
791                     buf.append(body.getNode(i).getText());
792                 }
793                 ret = buf.toString();
794             }
795             return ret;
796         }
797 
798         /***
799          * For the same reason as above, the source line information in the
800          * contained TemplateText node should be used.
801          */
802         public Mark getStart() {
803             if (text == null && body != null && body.size() > 0) {
804                 return body.getNode(0).getStart();
805             } else {
806                 return super.getStart();
807             }
808         }
809     }
810 
811     /***
812      * Represents a declaration
813      */
814     public static class Declaration extends ScriptingElement {
815 
816         public Declaration(String text, Mark start, Node parent) {
817             super(JSP_DECLARATION_ACTION, DECLARATION_ACTION, text, start,
818                     parent);
819         }
820 
821         public Declaration(String qName, Attributes nonTaglibXmlnsAttrs,
822                            Attributes taglibAttrs, Mark start,
823                            Node parent) {
824             super(qName, DECLARATION_ACTION, nonTaglibXmlnsAttrs,
825                     taglibAttrs, start, parent);
826         }
827 
828         public void accept(Visitor v) throws JasperException {
829             v.visit(this);
830         }
831     }
832 
833     /***
834      * Represents an expression.  Expressions in attributes are embedded
835      * in the attribute string and not here.
836      */
837     public static class Expression extends ScriptingElement {
838 
839         public Expression(String text, Mark start, Node parent) {
840             super(JSP_EXPRESSION_ACTION, EXPRESSION_ACTION, text, start,
841                     parent);
842         }
843 
844         public Expression(String qName, Attributes nonTaglibXmlnsAttrs,
845                           Attributes taglibAttrs, Mark start,
846                           Node parent) {
847             super(qName, EXPRESSION_ACTION, nonTaglibXmlnsAttrs, taglibAttrs,
848                     start, parent);
849         }
850 
851         public void accept(Visitor v) throws JasperException {
852             v.visit(this);
853         }
854     }
855 
856     /***
857      * Represents a scriptlet
858      */
859     public static class Scriptlet extends ScriptingElement {
860 
861         public Scriptlet(String text, Mark start, Node parent) {
862             super(JSP_SCRIPTLET_ACTION, SCRIPTLET_ACTION, text, start, parent);
863         }
864 
865         public Scriptlet(String qName, Attributes nonTaglibXmlnsAttrs,
866                          Attributes taglibAttrs, Mark start,
867                          Node parent) {
868             super(qName, SCRIPTLET_ACTION, nonTaglibXmlnsAttrs, taglibAttrs,
869                     start, parent);
870         }
871 
872         public void accept(Visitor v) throws JasperException {
873             v.visit(this);
874         }
875     }
876 
877     /***
878      * Represents an EL expression.  Expressions in attributes are embedded
879      * in the attribute string and not here.
880      */
881     public static class ELExpression extends Node {
882 
883         private ELNode.Nodes el;
884 
885         public ELExpression(String text, Mark start, Node parent) {
886             super(null, null, text, start, parent);
887         }
888 
889         public void accept(Visitor v) throws JasperException {
890             v.visit(this);
891         }
892 
893         public void setEL(ELNode.Nodes el) {
894             this.el = el;
895         }
896 
897         public ELNode.Nodes getEL() {
898             return el;
899         }
900     }
901 
902     /***
903      * Represents a param action
904      */
905     public static class ParamAction extends Node {
906 
907         JspAttribute value;
908 
909         public ParamAction(Attributes attrs, Mark start, Node parent) {
910             this(JSP_PARAM_ACTION, attrs, null, null, start, parent);
911         }
912 
913         public ParamAction(String qName, Attributes attrs,
914                            Attributes nonTaglibXmlnsAttrs,
915                            Attributes taglibAttrs, Mark start, Node parent) {
916             super(qName, PARAM_ACTION, attrs, nonTaglibXmlnsAttrs,
917                     taglibAttrs, start, parent);
918         }
919 
920         public void accept(Visitor v) throws JasperException {
921             v.visit(this);
922         }
923 
924         public void setValue(JspAttribute value) {
925             this.value = value;
926         }
927 
928         public JspAttribute getValue() {
929             return value;
930         }
931     }
932 
933     /***
934      * Represents a params action
935      */
936     public static class ParamsAction extends Node {
937 
938         public ParamsAction(Mark start, Node parent) {
939             this(JSP_PARAMS_ACTION, null, null, start, parent);
940         }
941 
942         public ParamsAction(String qName,
943                             Attributes nonTaglibXmlnsAttrs,
944                             Attributes taglibAttrs,
945                             Mark start, Node parent) {
946             super(qName, PARAMS_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs,
947                     start, parent);
948         }
949 
950         public void accept(Visitor v) throws JasperException {
951             v.visit(this);
952         }
953     }
954 
955     /***
956      * Represents a fallback action
957      */
958     public static class FallBackAction extends Node {
959 
960         public FallBackAction(Mark start, Node parent) {
961             this(JSP_FALLBACK_ACTION, null, null, start, parent);
962         }
963 
964         public FallBackAction(String qName,
965                               Attributes nonTaglibXmlnsAttrs,
966                               Attributes taglibAttrs, Mark start,
967                               Node parent) {
968             super(qName, FALLBACK_ACTION, null, nonTaglibXmlnsAttrs,
969                     taglibAttrs, start, parent);
970         }
971 
972         public void accept(Visitor v) throws JasperException {
973             v.visit(this);
974         }
975     }
976 
977     /***
978      * Represents an include action
979      */
980     public static class IncludeAction extends Node {
981 
982         private JspAttribute page;
983 
984         public IncludeAction(Attributes attrs, Mark start, Node parent) {
985             this(JSP_INCLUDE_ACTION, attrs, null, null, start, parent);
986         }
987 
988         public IncludeAction(String qName, Attributes attrs,
989                              Attributes nonTaglibXmlnsAttrs,
990                              Attributes taglibAttrs, Mark start, Node parent) {
991             super(qName, INCLUDE_ACTION, attrs, nonTaglibXmlnsAttrs,
992                     taglibAttrs, start, parent);
993         }
994 
995         public void accept(Visitor v) throws JasperException {
996             v.visit(this);
997         }
998 
999         public void setPage(JspAttribute page) {
1000             this.page = page;
1001         }
1002 
1003         public JspAttribute getPage() {
1004             return page;
1005         }
1006     }
1007 
1008     /***
1009      * Represents a forward action
1010      */
1011     public static class ForwardAction extends Node {
1012 
1013         private JspAttribute page;
1014 
1015         public ForwardAction(Attributes attrs, Mark start, Node parent) {
1016             this(JSP_FORWARD_ACTION, attrs, null, null, start, parent);
1017         }
1018 
1019         public ForwardAction(String qName, Attributes attrs,
1020                              Attributes nonTaglibXmlnsAttrs,
1021                              Attributes taglibAttrs, Mark start, Node parent) {
1022             super(qName, FORWARD_ACTION, attrs, nonTaglibXmlnsAttrs,
1023                     taglibAttrs, start, parent);
1024         }
1025 
1026         public void accept(Visitor v) throws JasperException {
1027             v.visit(this);
1028         }
1029 
1030         public void setPage(JspAttribute page) {
1031             this.page = page;
1032         }
1033 
1034         public JspAttribute getPage() {
1035             return page;
1036         }
1037     }
1038 
1039     /***
1040      * Represents a getProperty action
1041      */
1042     public static class GetProperty extends Node {
1043 
1044         public GetProperty(Attributes attrs, Mark start, Node parent) {
1045             this(JSP_GET_PROPERTY_ACTION, attrs, null, null, start, parent);
1046         }
1047 
1048         public GetProperty(String qName, Attributes attrs,
1049                            Attributes nonTaglibXmlnsAttrs,
1050                            Attributes taglibAttrs, Mark start, Node parent) {
1051             super(qName, GET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs,
1052                     taglibAttrs, start, parent);
1053         }
1054 
1055         public void accept(Visitor v) throws JasperException {
1056             v.visit(this);
1057         }
1058     }
1059 
1060     /***
1061      * Represents a setProperty action
1062      */
1063     public static class SetProperty extends Node {
1064 
1065         private JspAttribute value;
1066 
1067         public SetProperty(Attributes attrs, Mark start, Node parent) {
1068             this(JSP_SET_PROPERTY_ACTION, attrs, null, null, start, parent);
1069         }
1070 
1071         public SetProperty(String qName, Attributes attrs,
1072                            Attributes nonTaglibXmlnsAttrs,
1073                            Attributes taglibAttrs, Mark start, Node parent) {
1074             super(qName, SET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs,
1075                     taglibAttrs, start, parent);
1076         }
1077 
1078         public void accept(Visitor v) throws JasperException {
1079             v.visit(this);
1080         }
1081 
1082         public void setValue(JspAttribute value) {
1083             this.value = value;
1084         }
1085 
1086         public JspAttribute getValue() {
1087             return value;
1088         }
1089     }
1090 
1091     /***
1092      * Represents a useBean action
1093      */
1094     public static class UseBean extends Node {
1095 
1096         JspAttribute beanName;
1097 
1098         public UseBean(Attributes attrs, Mark start, Node parent) {
1099             this(JSP_USE_BEAN_ACTION, attrs, null, null, start, parent);
1100         }
1101 
1102         public UseBean(String qName, Attributes attrs,
1103                        Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs,
1104                        Mark start, Node parent) {
1105             super(qName, USE_BEAN_ACTION, attrs, nonTaglibXmlnsAttrs,
1106                     taglibAttrs, start, parent);
1107         }
1108 
1109         public void accept(Visitor v) throws JasperException {
1110             v.visit(this);
1111         }
1112 
1113         public void setBeanName(JspAttribute beanName) {
1114             this.beanName = beanName;
1115         }
1116 
1117         public JspAttribute getBeanName() {
1118             return beanName;
1119         }
1120     }
1121 
1122     /***
1123      * Represents a plugin action
1124      */
1125     public static class PlugIn extends Node {
1126 
1127         private JspAttribute width;
1128         private JspAttribute height;
1129 
1130         public PlugIn(Attributes attrs, Mark start, Node parent) {
1131             this(JSP_PLUGIN_ACTION, attrs, null, null, start, parent);
1132         }
1133 
1134         public PlugIn(String qName, Attributes attrs,
1135                       Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs,
1136                       Mark start, Node parent) {
1137             super(qName, PLUGIN_ACTION, attrs, nonTaglibXmlnsAttrs,
1138                     taglibAttrs, start, parent);
1139         }
1140 
1141         public void accept(Visitor v) throws JasperException {
1142             v.visit(this);
1143         }
1144 
1145         public void setHeight(JspAttribute height) {
1146             this.height = height;
1147         }
1148 
1149         public void setWidth(JspAttribute width) {
1150             this.width = width;
1151         }
1152 
1153         public JspAttribute getHeight() {
1154             return height;
1155         }
1156 
1157         public JspAttribute getWidth() {
1158             return width;
1159         }
1160     }
1161 
1162     /***
1163      * Represents an uninterpreted tag, from a Jsp document
1164      */
1165     public static class UninterpretedTag extends Node {
1166 
1167         private JspAttribute[] jspAttrs;
1168 
1169         public UninterpretedTag(String qName, String localName,
1170                                 Attributes attrs,
1171                                 Attributes nonTaglibXmlnsAttrs,
1172                                 Attributes taglibAttrs,
1173                                 Mark start, Node parent) {
1174             super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs,
1175                     start, parent);
1176         }
1177 
1178         public void accept(Visitor v) throws JasperException {
1179             v.visit(this);
1180         }
1181 
1182         public void setJspAttributes(JspAttribute[] jspAttrs) {
1183             this.jspAttrs = jspAttrs;
1184         }
1185 
1186         public JspAttribute[] getJspAttributes() {
1187             return jspAttrs;
1188         }
1189     }
1190 
1191     /***
1192      * Represents a <jsp:element>.
1193      */
1194     public static class JspElement extends Node {
1195 
1196         private JspAttribute[] jspAttrs;
1197         private JspAttribute nameAttr;
1198 
1199         public JspElement(Attributes attrs, Mark start, Node parent) {
1200             this(JSP_ELEMENT_ACTION, attrs, null, null, start, parent);
1201         }
1202 
1203         public JspElement(String qName, Attributes attrs,
1204                           Attributes nonTaglibXmlnsAttrs,
1205                           Attributes taglibAttrs, Mark start, Node parent) {
1206             super(qName, ELEMENT_ACTION, attrs, nonTaglibXmlnsAttrs,
1207                     taglibAttrs, start, parent);
1208         }
1209 
1210         public void accept(Visitor v) throws JasperException {
1211             v.visit(this);
1212         }
1213 
1214         public void setJspAttributes(JspAttribute[] jspAttrs) {
1215             this.jspAttrs = jspAttrs;
1216         }
1217 
1218         public JspAttribute[] getJspAttributes() {
1219             return jspAttrs;
1220         }
1221 
1222         /*
1223          * Sets the XML-style 'name' attribute
1224          */
1225         public void setNameAttribute(JspAttribute nameAttr) {
1226             this.nameAttr = nameAttr;
1227         }
1228 
1229         /*
1230          * Gets the XML-style 'name' attribute
1231          */
1232         public JspAttribute getNameAttribute() {
1233             return this.nameAttr;
1234         }
1235     }
1236 
1237     /***
1238      * Represents a <jsp:output>.
1239      */
1240     public static class JspOutput extends Node {
1241 
1242         public JspOutput(String qName, Attributes attrs,
1243                          Attributes nonTaglibXmlnsAttrs,
1244                          Attributes taglibAttrs,
1245                          Mark start, Node parent) {
1246             super(qName, OUTPUT_ACTION, attrs, nonTaglibXmlnsAttrs,
1247                     taglibAttrs, start, parent);
1248         }
1249 
1250         public void accept(Visitor v) throws JasperException {
1251             v.visit(this);
1252         }
1253     }
1254 
1255     /***
1256      * Collected information about child elements.  Used by nodes like
1257      * CustomTag, JspBody, and NamedAttribute.  The information is
1258      * set in the Collector.
1259      */
1260     public static class ChildInfo {
1261         private boolean scriptless;        // true if the tag and its body
1262         // contain no scripting elements.
1263         private boolean hasUseBean;
1264         private boolean hasIncludeAction;
1265         private boolean hasParamAction;
1266         private boolean hasSetProperty;
1267         private boolean hasScriptingVars;
1268 
1269         public void setScriptless(boolean s) {
1270             scriptless = s;
1271         }
1272 
1273         public boolean isScriptless() {
1274             return scriptless;
1275         }
1276 
1277         public void setHasUseBean(boolean u) {
1278             hasUseBean = u;
1279         }
1280 
1281         public boolean hasUseBean() {
1282             return hasUseBean;
1283         }
1284 
1285         public void setHasIncludeAction(boolean i) {
1286             hasIncludeAction = i;
1287         }
1288 
1289         public boolean hasIncludeAction() {
1290             return hasIncludeAction;
1291         }
1292 
1293         public void setHasParamAction(boolean i) {
1294             hasParamAction = i;
1295         }
1296 
1297         public boolean hasParamAction() {
1298             return hasParamAction;
1299         }
1300 
1301         public void setHasSetProperty(boolean s) {
1302             hasSetProperty = s;
1303         }
1304 
1305         public boolean hasSetProperty() {
1306             return hasSetProperty;
1307         }
1308 
1309         public void setHasScriptingVars(boolean s) {
1310             hasScriptingVars = s;
1311         }
1312 
1313         public boolean hasScriptingVars() {
1314             return hasScriptingVars;
1315         }
1316     }
1317 
1318     /***
1319      * Represents a custom tag
1320      */
1321     public static class CustomTag extends Node {
1322 
1323         private String uri;
1324         private String prefix;
1325         private JspAttribute[] jspAttrs;
1326         private TagData tagData;
1327         private String tagHandlerPoolName;
1328         private TagInfo tagInfo;
1329         private TagFileInfo tagFileInfo;
1330         private Class tagHandlerClass;
1331         private VariableInfo[] varInfos;
1332         private int customNestingLevel;
1333         private ChildInfo childInfo;
1334         private boolean implementsIterationTag;
1335         private boolean implementsBodyTag;
1336         private boolean implementsTryCatchFinally;
1337         private boolean implementsSimpleTag;
1338         private boolean implementsDynamicAttributes;
1339         private Vector atBeginScriptingVars;
1340         private Vector atEndScriptingVars;
1341         private Vector nestedScriptingVars;
1342         private Node.CustomTag customTagParent;
1343         private Integer numCount;
1344         private boolean useTagPlugin;
1345         private TagPluginContext tagPluginContext;
1346 
1347         /***
1348          * The following two fields are used for holding the Java
1349          * scriptlets that the tag plugins may generate.  Meaningful
1350          * only if useTagPlugin is true;
1351          * Could move them into TagPluginContextImpl, but we'll need
1352          * to cast tagPluginContext to TagPluginContextImpl all the time...
1353          */
1354         private Nodes atSTag;
1355         private Nodes atETag;
1356 
1357         /*
1358          * Constructor for custom action implemented by tag handler.
1359          */
1360         public CustomTag(String qName, String prefix, String localName,
1361                          String uri, Attributes attrs, Mark start, Node parent,
1362                          TagInfo tagInfo, Class tagHandlerClass) {
1363             this(qName, prefix, localName, uri, attrs, null, null, start,
1364                     parent, tagInfo, tagHandlerClass);
1365         }
1366 
1367         /*
1368          * Constructor for custom action implemented by tag handler.
1369          */
1370         public CustomTag(String qName, String prefix, String localName,
1371                          String uri, Attributes attrs,
1372                          Attributes nonTaglibXmlnsAttrs,
1373                          Attributes taglibAttrs,
1374                          Mark start, Node parent, TagInfo tagInfo,
1375                          Class tagHandlerClass) {
1376             super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs,
1377                     start, parent);
1378 
1379             this.uri = uri;
1380             this.prefix = prefix;
1381             this.tagInfo = tagInfo;
1382             this.tagHandlerClass = tagHandlerClass;
1383             this.customNestingLevel = makeCustomNestingLevel();
1384             this.childInfo = new ChildInfo();
1385 
1386             this.implementsIterationTag =
1387                     IterationTag.class.isAssignableFrom(tagHandlerClass);
1388             this.implementsBodyTag =
1389                     BodyTag.class.isAssignableFrom(tagHandlerClass);
1390             this.implementsTryCatchFinally =
1391                     TryCatchFinally.class.isAssignableFrom(tagHandlerClass);
1392             this.implementsSimpleTag =
1393                     SimpleTag.class.isAssignableFrom(tagHandlerClass);
1394             this.implementsDynamicAttributes =
1395                     DynamicAttributes.class.isAssignableFrom(tagHandlerClass);
1396         }
1397 
1398         /*
1399          * Constructor for custom action implemented by tag file.
1400          */
1401         public CustomTag(String qName, String prefix, String localName,
1402                          String uri, Attributes attrs, Mark start, Node parent,
1403                          TagFileInfo tagFileInfo) {
1404             this(qName, prefix, localName, uri, attrs, null, null, start,
1405                     parent, tagFileInfo);
1406         }
1407 
1408         /*
1409          * Constructor for custom action implemented by tag file.
1410          */
1411         public CustomTag(String qName, String prefix, String localName,
1412                          String uri, Attributes attrs,
1413                          Attributes nonTaglibXmlnsAttrs,
1414                          Attributes taglibAttrs,
1415                          Mark start, Node parent, TagFileInfo tagFileInfo) {
1416 
1417             super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs,
1418                     start, parent);
1419 
1420             this.uri = uri;
1421             this.prefix = prefix;
1422             this.tagFileInfo = tagFileInfo;
1423             this.tagInfo = tagFileInfo.getTagInfo();
1424             this.customNestingLevel = makeCustomNestingLevel();
1425             this.childInfo = new ChildInfo();
1426 
1427             this.implementsIterationTag = false;
1428             this.implementsBodyTag = false;
1429             this.implementsTryCatchFinally = false;
1430             this.implementsSimpleTag = true;
1431             this.implementsDynamicAttributes = tagInfo.hasDynamicAttributes();
1432         }
1433 
1434         public void accept(Visitor v) throws JasperException {
1435             v.visit(this);
1436         }
1437 
1438         /***
1439          * @return The URI namespace that this custom action belongs to
1440          */
1441         public String getURI() {
1442             return this.uri;
1443         }
1444 
1445         /***
1446          * @return The tag prefix
1447          */
1448         public String getPrefix() {
1449             return prefix;
1450         }
1451 
1452         public void setJspAttributes(JspAttribute[] jspAttrs) {
1453             this.jspAttrs = jspAttrs;
1454         }
1455 
1456         public JspAttribute[] getJspAttributes() {
1457             return jspAttrs;
1458         }
1459 
1460         public ChildInfo getChildInfo() {
1461             return childInfo;
1462         }
1463 
1464         public void setTagData(TagData tagData) {
1465             this.tagData = tagData;
1466             this.varInfos = tagInfo.getVariableInfo(tagData);
1467             if (this.varInfos == null) {
1468                 this.varInfos = ZERO_VARIABLE_INFO;
1469             }
1470         }
1471 
1472         public TagData getTagData() {
1473             return tagData;
1474         }
1475 
1476         public void setTagHandlerPoolName(String s) {
1477             tagHandlerPoolName = s;
1478         }
1479 
1480         public String getTagHandlerPoolName() {
1481             return tagHandlerPoolName;
1482         }
1483 
1484         public TagInfo getTagInfo() {
1485             return tagInfo;
1486         }
1487 
1488         public TagFileInfo getTagFileInfo() {
1489             return tagFileInfo;
1490         }
1491 
1492         /*
1493          * @return true if this custom action is supported by a tag file,
1494          * false otherwise
1495          */
1496         public boolean isTagFile() {
1497             return tagFileInfo != null;
1498         }
1499 
1500         public Class getTagHandlerClass() {
1501             return tagHandlerClass;
1502         }
1503 
1504         public void setTagHandlerClass(Class hc) {
1505             tagHandlerClass = hc;
1506         }
1507 
1508         public boolean implementsIterationTag() {
1509             return implementsIterationTag;
1510         }
1511 
1512         public boolean implementsBodyTag() {
1513             return implementsBodyTag;
1514         }
1515 
1516         public boolean implementsTryCatchFinally() {
1517             return implementsTryCatchFinally;
1518         }
1519 
1520         public boolean implementsSimpleTag() {
1521             return implementsSimpleTag;
1522         }
1523 
1524         public boolean implementsDynamicAttributes() {
1525             return implementsDynamicAttributes;
1526         }
1527 
1528         public TagVariableInfo[] getTagVariableInfos() {
1529             return tagInfo.getTagVariableInfos();
1530         }
1531 
1532         public VariableInfo[] getVariableInfos() {
1533             return varInfos;
1534         }
1535 
1536         public void setCustomTagParent(Node.CustomTag n) {
1537             this.customTagParent = n;
1538         }
1539 
1540         public Node.CustomTag getCustomTagParent() {
1541             return this.customTagParent;
1542         }
1543 
1544         public void setNumCount(Integer count) {
1545             this.numCount = count;
1546         }
1547 
1548         public Integer getNumCount() {
1549             return this.numCount;
1550         }
1551 
1552         public void setScriptingVars(Vector vec, int scope) {
1553             switch (scope) {
1554                 case VariableInfo.AT_BEGIN:
1555                     this.atBeginScriptingVars = vec;
1556                     break;
1557                 case VariableInfo.AT_END:
1558                     this.atEndScriptingVars = vec;
1559                     break;
1560                 case VariableInfo.NESTED:
1561                     this.nestedScriptingVars = vec;
1562                     break;
1563             }
1564         }
1565 
1566         /*
1567          * Gets the scripting variables for the given scope that need to be
1568          * declared.
1569          */
1570         public Vector getScriptingVars(int scope) {
1571             Vector vec = null;
1572 
1573             switch (scope) {
1574                 case VariableInfo.AT_BEGIN:
1575                     vec = this.atBeginScriptingVars;
1576                     break;
1577                 case VariableInfo.AT_END:
1578                     vec = this.atEndScriptingVars;
1579                     break;
1580                 case VariableInfo.NESTED:
1581                     vec = this.nestedScriptingVars;
1582                     break;
1583             }
1584 
1585             return vec;
1586         }
1587 
1588         /*
1589          * Gets this custom tag's custom nesting level, which is given as
1590          * the number of times this custom tag is nested inside itself.
1591          */
1592         public int getCustomNestingLevel() {
1593             return customNestingLevel;
1594         }
1595 
1596         /***
1597          * Checks to see if the attribute of the given name is of type
1598          * JspFragment.
1599          */
1600         public boolean checkIfAttributeIsJspFragment(String name) {
1601             boolean result = false;
1602 
1603             TagAttributeInfo[] attributes = tagInfo.getAttributes();
1604             for (int i = 0; i < attributes.length; i++) {
1605                 if (attributes[i].getName().equals(name) &&
1606                         attributes[i].isFragment()) {
1607                     result = true;
1608                     break;
1609                 }
1610             }
1611 
1612             return result;
1613         }
1614 
1615         public void setUseTagPlugin(boolean use) {
1616             useTagPlugin = use;
1617         }
1618 
1619         public boolean useTagPlugin() {
1620             return useTagPlugin;
1621         }
1622 
1623         public void setTagPluginContext(TagPluginContext tagPluginContext) {
1624             this.tagPluginContext = tagPluginContext;
1625         }
1626 
1627         public TagPluginContext getTagPluginContext() {
1628             return tagPluginContext;
1629         }
1630 
1631         public void setAtSTag(Nodes sTag) {
1632             atSTag = sTag;
1633         }
1634 
1635         public Nodes getAtSTag() {
1636             return atSTag;
1637         }
1638 
1639         public void setAtETag(Nodes eTag) {
1640             atETag = eTag;
1641         }
1642 
1643         public Nodes getAtETag() {
1644             return atETag;
1645         }
1646 
1647         /*
1648         * Computes this custom tag's custom nesting level, which corresponds
1649         * to the number of times this custom tag is nested inside itself.
1650         *
1651         * Example:
1652         *
1653         *  <g:h>
1654         *    <a:b> -- nesting level 0
1655         *      <c:d>
1656         *        <e:f>
1657         *          <a:b> -- nesting level 1
1658         *            <a:b> -- nesting level 2
1659         *            </a:b>
1660         *          </a:b>
1661         *          <a:b> -- nesting level 1
1662         *          </a:b>
1663         *        </e:f>
1664         *      </c:d>
1665         *    </a:b>
1666         *  </g:h>
1667         *
1668         * @return Custom tag's nesting level
1669         */
1670         private int makeCustomNestingLevel() {
1671             int n = 0;
1672             Node p = parent;
1673             while (p != null) {
1674                 if ((p instanceof Node.CustomTag)
1675                         && qName.equals(((Node.CustomTag) p).qName)) {
1676                     n++;
1677                 }
1678                 p = p.parent;
1679             }
1680             return n;
1681         }
1682 
1683         /***
1684          * Returns true if this custom action has an empty body, and false
1685          * otherwise.
1686          * <p/>
1687          * A custom action is considered to have an empty body if the
1688          * following holds true:
1689          * - getBody() returns null, or
1690          * - all immediate children are jsp:attribute actions, or
1691          * - the action's jsp:body is empty.
1692          */
1693         public boolean hasEmptyBody() {
1694             boolean hasEmptyBody = true;
1695             Nodes nodes = getBody();
1696             if (nodes != null) {
1697                 int numChildNodes = nodes.size();
1698                 for (int i = 0; i < numChildNodes; i++) {
1699                     Node n = nodes.getNode(i);
1700                     if (!(n instanceof NamedAttribute)) {
1701                         if (n instanceof JspBody) {
1702                             hasEmptyBody = (n.getBody() == null);
1703                         } else {
1704                             hasEmptyBody = false;
1705                         }
1706                         break;
1707                     }
1708                 }
1709             }
1710 
1711             return hasEmptyBody;
1712         }
1713     }
1714 
1715     /***
1716      * Used as a placeholder for the evaluation code of a custom action
1717      * attribute (used by the tag plugin machinery only).
1718      */
1719     public static class AttributeGenerator extends Node {
1720         String name;        // name of the attribute
1721         CustomTag tag;        // The tag this attribute belongs to
1722 
1723         public AttributeGenerator(Mark start, String name, CustomTag tag) {
1724             super(start, null);
1725             this.name = name;
1726             this.tag = tag;
1727         }
1728 
1729         public void accept(Visitor v) throws JasperException {
1730             v.visit(this);
1731         }
1732 
1733         public String getName() {
1734             return name;
1735         }
1736 
1737         public CustomTag getTag() {
1738             return tag;
1739         }
1740     }
1741 
1742     /***
1743      * Represents the body of a &lt;jsp:text&gt; element
1744      */
1745     public static class JspText extends Node {
1746 
1747         public JspText(String qName, Attributes nonTaglibXmlnsAttrs,
1748                        Attributes taglibAttrs, Mark start, Node parent) {
1749             super(qName, TEXT_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs,
1750                     start, parent);
1751         }
1752 
1753         public void accept(Visitor v) throws JasperException {
1754             v.visit(this);
1755         }
1756     }
1757 
1758     /***
1759      * Represents a Named Attribute (&lt;jsp:attribute&gt;)
1760      */
1761     public static class NamedAttribute extends Node {
1762 
1763         // A unique temporary variable name suitable for code generation
1764         private String temporaryVariableName;
1765 
1766         // True if this node is to be trimmed, or false otherwise
1767         private boolean trim = true;
1768 
1769         private ChildInfo childInfo;
1770         private String name;
1771         private String localName;
1772         private String prefix;
1773 
1774         public NamedAttribute(Attributes attrs, Mark start, Node parent) {
1775             this(JSP_ATTRIBUTE_ACTION, attrs, null, null, start, parent);
1776         }
1777 
1778         public NamedAttribute(String qName, Attributes attrs,
1779                               Attributes nonTaglibXmlnsAttrs,
1780                               Attributes taglibAttrs,
1781                               Mark start, Node parent) {
1782 
1783             super(qName, ATTRIBUTE_ACTION, attrs, nonTaglibXmlnsAttrs,
1784                     taglibAttrs, start, parent);
1785             if ("false".equals(this.getAttributeValue("trim"))) {
1786                 // (if null or true, leave default of true)
1787                 trim = false;
1788             }
1789             childInfo = new ChildInfo();
1790             name = this.getAttributeValue("name");
1791             if (name != null) {
1792                 // Mandatary attribute "name" will be checked in Validator
1793                 localName = name;
1794                 int index = name.indexOf(':');
1795                 if (index != -1) {
1796                     prefix = name.substring(0, index);
1797                     localName = name.substring(index + 1);
1798                 }
1799             }
1800         }
1801 
1802         public void accept(Visitor v) throws JasperException {
1803             v.visit(this);
1804         }
1805 
1806         public String getName() {
1807             return this.name;
1808         }
1809 
1810         public String getLocalName() {
1811             return this.localName;
1812         }
1813 
1814         public String getPrefix() {
1815             return this.prefix;
1816         }
1817 
1818         public ChildInfo getChildInfo() {
1819             return this.childInfo;
1820         }
1821 
1822         public boolean isTrim() {
1823             return trim;
1824         }
1825 
1826         /***
1827          * @return A unique temporary variable name to store the result in.
1828          *         (this probably could go elsewhere, but it's convenient here)
1829          */
1830         public String getTemporaryVariableName() {
1831             if (temporaryVariableName == null) {
1832                 temporaryVariableName = JspUtil.nextTemporaryVariableName();
1833             }
1834             return temporaryVariableName;
1835         }
1836 
1837         /*
1838          * Get the attribute value from this named attribute (<jsp:attribute>).
1839          * Since this method is only for attributes that are not rtexpr,
1840          * we can assume the body of the jsp:attribute is a template text.
1841          */
1842         public String getText() {
1843 
1844             class AttributeVisitor extends Visitor {
1845                 String attrValue = null;
1846 
1847                 public void visit(TemplateText txt) {
1848                     attrValue = new String(txt.getText());
1849                 }
1850 
1851                 public String getAttrValue() {
1852                     return attrValue;
1853                 }
1854             }
1855 
1856             // According to JSP 2.0, if the body of the <jsp:attribute>
1857             // action is empty, it is equivalent of specifying "" as the value
1858             // of the attribute.
1859             String text = "";
1860             if (getBody() != null) {
1861                 AttributeVisitor attributeVisitor = new AttributeVisitor();
1862                 try {
1863                     getBody().visit(attributeVisitor);
1864                 } catch (JasperException e) {
1865                 }
1866                 text = attributeVisitor.getAttrValue();
1867             }
1868 
1869             return text;
1870         }
1871     }
1872 
1873     /***
1874      * Represents a JspBody node (&lt;jsp:body&gt;)
1875      */
1876     public static class JspBody extends Node {
1877 
1878         private ChildInfo childInfo;
1879 
1880         public JspBody(Mark start, Node parent) {
1881             this(JSP_BODY_ACTION, null, null, start, parent);
1882         }
1883 
1884         public JspBody(String qName, Attributes nonTaglibXmlnsAttrs,
1885                        Attributes taglibAttrs, Mark start, Node parent) {
1886             super(qName, BODY_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs,
1887                     start, parent);
1888             this.childInfo = new ChildInfo();
1889         }
1890 
1891         public void accept(Visitor v) throws JasperException {
1892             v.visit(this);
1893         }
1894 
1895         public ChildInfo getChildInfo() {
1896             return childInfo;
1897         }
1898     }
1899 
1900     /***
1901      * Represents a template text string
1902      */
1903     public static class TemplateText extends Node {
1904 
1905         private ArrayList extraSmap = null;
1906 
1907         public TemplateText(String text, Mark start, Node parent) {
1908             super(null, null, text, start, parent);
1909         }
1910 
1911         public void accept(Visitor v) throws JasperException {
1912             v.visit(this);
1913         }
1914 
1915         /***
1916          * Trim all whitespace from the left of the template text
1917          */
1918         public void ltrim() {
1919             int index = 0;
1920             while ((index < text.length()) && (text.charAt(index) <= ' ')) {
1921                 index++;
1922             }
1923             text = text.substring(index);
1924         }
1925 
1926         public void setText(String text) {
1927             this.text = text;
1928         }
1929 
1930         /***
1931          * Trim all whitespace from the right of the template text
1932          */
1933         public void rtrim() {
1934             int index = text.length();
1935             while ((index > 0) && (text.charAt(index - 1) <= ' ')) {
1936                 index--;
1937             }
1938             text = text.substring(0, index);
1939         }
1940 
1941         /***
1942          * Returns true if this template text contains whitespace only.
1943          */
1944         public boolean isAllSpace() {
1945             boolean isAllSpace = true;
1946             for (int i = 0; i < text.length(); i++) {
1947                 if (!Character.isWhitespace(text.charAt(i))) {
1948                     isAllSpace = false;
1949                     break;
1950                 }
1951             }
1952             return isAllSpace;
1953         }
1954 
1955         /***
1956          * Add a source to Java line mapping
1957          *
1958          * @param srcLine The postion of the source line, relative to the line
1959          *                at the start of this node.  The corresponding java line is
1960          *                assumed to be consecutive, i.e. one more than the last.
1961          */
1962         public void addSmap(int srcLine) {
1963             if (extraSmap == null) {
1964                 extraSmap = new ArrayList();
1965             }
1966             extraSmap.add(new Integer(srcLine));
1967         }
1968 
1969         public ArrayList getExtraSmap() {
1970             return extraSmap;
1971         }
1972     }
1973 
1974     /**********************************************************************
1975      * Auxillary classes used in Node
1976      */
1977 
1978     /***
1979      * Represents attributes that can be request time expressions.
1980      * <p/>
1981      * Can either be a plain attribute, an attribute that represents a
1982      * request time expression value, or a named attribute (specified using
1983      * the jsp:attribute standard action).
1984      */
1985 
1986     public static class JspAttribute {
1987 
1988         private String qName;
1989         private String uri;
1990         private String localName;
1991         private String value;
1992         private boolean expression;
1993         private boolean dynamic;
1994         private ELNode.Nodes el;
1995 
1996         // If true, this JspAttribute represents a <jsp:attribute>
1997         private boolean namedAttribute;
1998         // The node in the parse tree for the NamedAttribute
1999         private NamedAttribute namedAttributeNode;
2000 
2001         JspAttribute(String qName, String uri, String localName, String value,
2002                      boolean expr, ELNode.Nodes el, boolean dyn) {
2003             this.qName = qName;
2004             this.uri = uri;
2005             this.localName = localName;
2006             this.value = value;
2007             this.namedAttributeNode = null;
2008             this.expression = expr;
2009             this.el = el;
2010             this.dynamic = dyn;
2011             this.namedAttribute = false;
2012         }
2013 
2014         /***
2015          * Use this constructor if the JspAttribute represents a
2016          * named attribute.  In this case, we have to store the nodes of
2017          * the body of the attribute.
2018          */
2019         JspAttribute(NamedAttribute na, boolean dyn) {
2020             this.qName = na.getName();
2021             this.localName = na.getLocalName();
2022             this.value = null;
2023             this.namedAttributeNode = na;
2024             this.expression = false;
2025             this.el = null;
2026             this.dynamic = dyn;
2027             this.namedAttribute = true;
2028         }
2029 
2030         /***
2031          * @return The name of the attribute
2032          */
2033         public String getName() {
2034             return qName;
2035         }
2036 
2037         /***
2038          * @return The local name of the attribute
2039          */
2040         public String getLocalName() {
2041             return localName;
2042         }
2043 
2044         /***
2045          * @return The namespace of the attribute, or null if in the default
2046          *         namespace
2047          */
2048         public String getURI() {
2049             return uri;
2050         }
2051 
2052         /***
2053          * Only makes sense if namedAttribute is false.
2054          *
2055          * @return the value for the attribute, or the expression string
2056          *         (stripped of "<%=", "%>", "%=", or "%"
2057          *         but containing "${" and "}" for EL expressions)
2058          */
2059         public String getValue() {
2060             return value;
2061         }
2062 
2063         /***
2064          * Only makes sense if namedAttribute is true.
2065          *
2066          * @return the nodes that evaluate to the body of this attribute.
2067          */
2068         public NamedAttribute getNamedAttributeNode() {
2069             return namedAttributeNode;
2070         }
2071 
2072         /***
2073          * @return true if the value represents a traditional rtexprvalue
2074          */
2075         public boolean isExpression() {
2076             return expression;
2077         }
2078 
2079         /***
2080          * @return true if the value represents a NamedAttribute value.
2081          */
2082         public boolean isNamedAttribute() {
2083             return namedAttribute;
2084         }
2085 
2086         /***
2087          * @return false for string literals or rtexprvalues that should
2088          *         not be interpreted or reevaluated
2089          */
2090         public boolean isELInterpreterInput() {
2091             return el != null;
2092         }
2093 
2094         /***
2095          * @return true if the value is a string literal known at translation
2096          *         time.
2097          */
2098         public boolean isLiteral() {
2099             return !expression && (el != null) && !namedAttribute;
2100         }
2101 
2102         /***
2103          * XXX
2104          */
2105         public boolean isDynamic() {
2106             return dynamic;
2107         }
2108 
2109         public ELNode.Nodes getEL() {
2110             return el;
2111         }
2112     }
2113 
2114     /***
2115      * An ordered list of Node, used to represent the body of an element, or
2116      * a jsp page of jsp document.
2117      */
2118     public static class Nodes {
2119 
2120         private List list;
2121         private Node.Root root;                // null if this is not a page
2122         private boolean generatedInBuffer;
2123 
2124         public Nodes() {
2125             list = new Vector();
2126         }
2127 
2128         public Nodes(Node.Root root) {
2129             this.root = root;
2130             list = new Vector();
2131             list.add(root);
2132         }
2133 
2134         /***
2135          * Appends a node to the list
2136          *
2137          * @param n The node to add
2138          */
2139         public void add(Node n) {
2140             list.add(n);
2141             root = null;
2142         }
2143 
2144         /***
2145          * Removes the given node from the list.
2146          *
2147          * @param n The node to be removed
2148          */
2149         public void remove(Node n) {
2150             list.remove(n);
2151         }
2152 
2153         /***
2154          * Visit the nodes in the list with the supplied visitor
2155          *
2156          * @param v The visitor used
2157          */
2158         public void visit(Visitor v) throws JasperException {
2159             Iterator iter = list.iterator();
2160             while (iter.hasNext()) {
2161                 Node n = (Node) iter.next();
2162                 n.accept(v);
2163             }
2164         }
2165 
2166         public int size() {
2167             return list.size();
2168         }
2169 
2170         public Node getNode(int index) {
2171             Node n = null;
2172             try {
2173                 n = (Node) list.get(index);
2174             } catch (ArrayIndexOutOfBoundsException e) {
2175             }
2176             return n;
2177         }
2178 
2179         public Node.Root getRoot() {
2180             return root;
2181         }
2182 
2183         public boolean isGeneratedInBuffer() {
2184             return generatedInBuffer;
2185         }
2186 
2187         public void setGeneratedInBuffer(boolean g) {
2188             generatedInBuffer = g;
2189         }
2190     }
2191 
2192     /***
2193      * A visitor class for visiting the node.  This class also provides the
2194      * default action (i.e. nop) for each of the child class of the Node.
2195      * An actual visitor should extend this class and supply the visit
2196      * method for the nodes that it cares.
2197      */
2198     public static class Visitor {
2199 
2200         /***
2201          * This method provides a place to put actions that are common to
2202          * all nodes. Override this in the child visitor class if need to.
2203          */
2204         protected void doVisit(Node n) throws JasperException {
2205         }
2206 
2207         /***
2208          * Visit the body of a node, using the current visitor
2209          */
2210         protected void visitBody(Node n) throws JasperException {
2211             if (n.getBody() != null) {
2212                 n.getBody().visit(this);
2213             }
2214         }
2215 
2216         public void visit(Root n) throws JasperException {
2217             doVisit(n);
2218             visitBody(n);
2219         }
2220 
2221         public void visit(JspRoot n) throws JasperException {
2222             doVisit(n);
2223             visitBody(n);
2224         }
2225 
2226         public void visit(PageDirective n) throws JasperException {
2227             doVisit(n);
2228         }
2229 
2230         public void visit(TagDirective n) throws JasperException {
2231             doVisit(n);
2232         }
2233 
2234         public void visit(IncludeDirective n) throws JasperException {
2235             doVisit(n);
2236             visitBody(n);
2237         }
2238 
2239         public void visit(TaglibDirective n) throws JasperException {
2240             doVisit(n);
2241         }
2242 
2243         public void visit(AttributeDirective n) throws JasperException {
2244             doVisit(n);
2245         }
2246 
2247         public void visit(VariableDirective n) throws JasperException {
2248             doVisit(n);
2249         }
2250 
2251         public void visit(Comment n) throws JasperException {
2252             doVisit(n);
2253         }
2254 
2255         public void visit(Declaration n) throws JasperException {
2256             doVisit(n);
2257         }
2258 
2259         public void visit(Expression n) throws JasperException {
2260             doVisit(n);
2261         }
2262 
2263         public void visit(Scriptlet n) throws JasperException {
2264             doVisit(n);
2265         }
2266 
2267         public void visit(ELExpression n) throws JasperException {
2268             doVisit(n);
2269         }
2270 
2271         public void visit(IncludeAction n) throws JasperException {
2272             doVisit(n);
2273             visitBody(n);
2274         }
2275 
2276         public void visit(ForwardAction n) throws JasperException {
2277             doVisit(n);
2278             visitBody(n);
2279         }
2280 
2281         public void visit(GetProperty n) throws JasperException {
2282             doVisit(n);
2283             visitBody(n);
2284         }
2285 
2286         public void visit(SetProperty n) throws JasperException {
2287             doVisit(n);
2288             visitBody(n);
2289         }
2290 
2291         public void visit(ParamAction n) throws JasperException {
2292             doVisit(n);
2293             visitBody(n);
2294         }
2295 
2296         public void visit(ParamsAction n) throws JasperException {
2297             doVisit(n);
2298             visitBody(n);
2299         }
2300 
2301         public void visit(FallBackAction n) throws JasperException {
2302             doVisit(n);
2303             visitBody(n);
2304         }
2305 
2306         public void visit(UseBean n) throws JasperException {
2307             doVisit(n);
2308             visitBody(n);
2309         }
2310 
2311         public void visit(PlugIn n) throws JasperException {
2312             doVisit(n);
2313             visitBody(n);
2314         }
2315 
2316         public void visit(CustomTag n) throws JasperException {
2317             doVisit(n);
2318             visitBody(n);
2319         }
2320 
2321         public void visit(UninterpretedTag n) throws JasperException {
2322             doVisit(n);
2323             visitBody(n);
2324         }
2325 
2326         public void visit(JspElement n) throws JasperException {
2327             doVisit(n);
2328             visitBody(n);
2329         }
2330 
2331         public void visit(JspText n) throws JasperException {
2332             doVisit(n);
2333             visitBody(n);
2334         }
2335 
2336         public void visit(NamedAttribute n) throws JasperException {
2337             doVisit(n);
2338             visitBody(n);
2339         }
2340 
2341         public void visit(JspBody n) throws JasperException {
2342             doVisit(n);
2343             visitBody(n);
2344         }
2345 
2346         public void visit(InvokeAction n) throws JasperException {
2347             doVisit(n);
2348             visitBody(n);
2349         }
2350 
2351         public void visit(DoBodyAction n) throws JasperException {
2352             doVisit(n);
2353             visitBody(n);
2354         }
2355 
2356         public void visit(TemplateText n) throws JasperException {
2357             doVisit(n);
2358         }
2359 
2360         public void visit(JspOutput n) throws JasperException {
2361             doVisit(n);
2362         }
2363 
2364         public void visit(AttributeGenerator n) throws JasperException {
2365             doVisit(n);
2366         }
2367     }
2368 }