KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jasper > compiler > Generator


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.jasper.compiler;
19
20 import java.beans.BeanInfo JavaDoc;
21 import java.beans.IntrospectionException JavaDoc;
22 import java.beans.Introspector JavaDoc;
23 import java.beans.PropertyDescriptor JavaDoc;
24 import java.lang.reflect.Method JavaDoc;
25 import java.lang.reflect.Modifier JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Arrays JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.Hashtable JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Vector JavaDoc;
35
36 import javax.el.MethodExpression;
37 import javax.el.ValueExpression;
38 import javax.servlet.jsp.tagext.TagAttributeInfo JavaDoc;
39 import javax.servlet.jsp.tagext.TagInfo JavaDoc;
40 import javax.servlet.jsp.tagext.TagVariableInfo JavaDoc;
41 import javax.servlet.jsp.tagext.VariableInfo JavaDoc;
42
43 import org.apache.jasper.Constants;
44 import org.apache.jasper.JasperException;
45 import org.apache.jasper.JspCompilationContext;
46 import org.apache.jasper.runtime.JspRuntimeLibrary;
47 import org.xml.sax.Attributes JavaDoc;
48
49 /**
50  * Generate Java source from Nodes
51  *
52  * @author Anil K. Vijendran
53  * @author Danno Ferrin
54  * @author Mandar Raje
55  * @author Rajiv Mordani
56  * @author Pierre Delisle
57  *
58  * Tomcat 4.1.x and Tomcat 5:
59  * @author Kin-man Chung
60  * @author Jan Luehe
61  * @author Shawn Bayern
62  * @author Mark Roth
63  * @author Denis Benoit
64  *
65  * Tomcat 6.x
66  * @author Jacob Hookom
67  * @author Remy Maucherat
68  */

69
70 class Generator {
71
72     private static final Class JavaDoc[] OBJECT_CLASS = { Object JavaDoc.class };
73
74     private static final String JavaDoc VAR_EXPRESSIONFACTORY =
75         System.getProperty("org.apache.jasper.compiler.Generator.VAR_EXPRESSIONFACTORY", "_el_expressionfactory");
76     private static final String JavaDoc VAR_ANNOTATIONPROCESSOR =
77         System.getProperty("org.apache.jasper.compiler.Generator.VAR_ANNOTATIONPROCESSOR", "_jsp_annotationprocessor");
78
79     private ServletWriter out;
80
81     private ArrayList JavaDoc methodsBuffered;
82
83     private FragmentHelperClass fragmentHelperClass;
84
85     private ErrorDispatcher err;
86
87     private BeanRepository beanInfo;
88
89     private JspCompilationContext ctxt;
90
91     private boolean isPoolingEnabled;
92
93     private boolean breakAtLF;
94
95     private String JavaDoc jspIdPrefix;
96
97     private int jspId;
98
99     private PageInfo pageInfo;
100
101     private Vector JavaDoc<String JavaDoc> tagHandlerPoolNames;
102
103     private GenBuffer charArrayBuffer;
104
105     /**
106      * @param s
107      * the input string
108      * @return quoted and escaped string, per Java rule
109      */

110     static String JavaDoc quote(String JavaDoc s) {
111
112         if (s == null)
113             return "null";
114
115         return '"' + escape(s) + '"';
116     }
117
118     /**
119      * @param s
120      * the input string
121      * @return escaped string, per Java rule
122      */

123     static String JavaDoc escape(String JavaDoc s) {
124
125         if (s == null)
126             return "";
127
128         StringBuffer JavaDoc b = new StringBuffer JavaDoc();
129         for (int i = 0; i < s.length(); i++) {
130             char c = s.charAt(i);
131             if (c == '"')
132                 b.append('\\').append('"');
133             else if (c == '\\')
134                 b.append('\\').append('\\');
135             else if (c == '\n')
136                 b.append('\\').append('n');
137             else if (c == '\r')
138                 b.append('\\').append('r');
139             else
140                 b.append(c);
141         }
142         return b.toString();
143     }
144
145     /**
146      * Single quote and escape a character
147      */

148     static String JavaDoc quote(char c) {
149
150         StringBuffer JavaDoc b = new StringBuffer JavaDoc();
151         b.append('\'');
152         if (c == '\'')
153             b.append('\\').append('\'');
154         else if (c == '\\')
155             b.append('\\').append('\\');
156         else if (c == '\n')
157             b.append('\\').append('n');
158         else if (c == '\r')
159             b.append('\\').append('r');
160         else
161             b.append(c);
162         b.append('\'');
163         return b.toString();
164     }
165
166     private String JavaDoc createJspId() throws JasperException {
167         if (this.jspIdPrefix == null) {
168             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(32);
169             String JavaDoc name = ctxt.getServletJavaFileName();
170             sb.append("jsp_").append(Math.abs(name.hashCode())).append('_');
171             this.jspIdPrefix = sb.toString();
172         }
173         return this.jspIdPrefix + (this.jspId++);
174     }
175
176     /**
177      * Generates declarations. This includes "info" of the page directive, and
178      * scriptlet declarations.
179      */

180     private void generateDeclarations(Node.Nodes page) throws JasperException {
181
182         class DeclarationVisitor extends Node.Visitor {
183
184             private boolean getServletInfoGenerated = false;
185
186             /*
187              * Generates getServletInfo() method that returns the value of the
188              * page directive's 'info' attribute, if present.
189              *
190              * The Validator has already ensured that if the translation unit
191              * contains more than one page directive with an 'info' attribute,
192              * their values match.
193              */

194             public void visit(Node.PageDirective n) throws JasperException {
195
196                 if (getServletInfoGenerated) {
197                     return;
198                 }
199
200                 String JavaDoc info = n.getAttributeValue("info");
201                 if (info == null)
202                     return;
203
204                 getServletInfoGenerated = true;
205                 out.printil("public String getServletInfo() {");
206                 out.pushIndent();
207                 out.printin("return ");
208                 out.print(quote(info));
209                 out.println(";");
210                 out.popIndent();
211                 out.printil("}");
212                 out.println();
213             }
214
215             public void visit(Node.Declaration n) throws JasperException {
216                 n.setBeginJavaLine(out.getJavaLine());
217                 out.printMultiLn(new String JavaDoc(n.getText()));
218                 out.println();
219                 n.setEndJavaLine(out.getJavaLine());
220             }
221
222             // Custom Tags may contain declarations from tag plugins.
223
public void visit(Node.CustomTag n) throws JasperException {
224                 if (n.useTagPlugin()) {
225                     if (n.getAtSTag() != null) {
226                         n.getAtSTag().visit(this);
227                     }
228                     visitBody(n);
229                     if (n.getAtETag() != null) {
230                         n.getAtETag().visit(this);
231                     }
232                 } else {
233                     visitBody(n);
234                 }
235             }
236         }
237
238         out.println();
239         page.visit(new DeclarationVisitor());
240     }
241
242     /**
243      * Compiles list of tag handler pool names.
244      */

245     private void compileTagHandlerPoolList(Node.Nodes page)
246             throws JasperException {
247
248         class TagHandlerPoolVisitor extends Node.Visitor {
249
250             private Vector JavaDoc names;
251
252             /*
253              * Constructor
254              *
255              * @param v Vector of tag handler pool names to populate
256              */

257             TagHandlerPoolVisitor(Vector JavaDoc v) {
258                 names = v;
259             }
260
261             /*
262              * Gets the name of the tag handler pool for the given custom tag
263              * and adds it to the list of tag handler pool names unless it is
264              * already contained in it.
265              */

266             public void visit(Node.CustomTag n) throws JasperException {
267
268                 if (!n.implementsSimpleTag()) {
269                     String JavaDoc name = createTagHandlerPoolName(n.getPrefix(), n
270                             .getLocalName(), n.getAttributes(), n
271                             .hasEmptyBody());
272                     n.setTagHandlerPoolName(name);
273                     if (!names.contains(name)) {
274                         names.add(name);
275                     }
276                 }
277                 visitBody(n);
278             }
279
280             /*
281              * Creates the name of the tag handler pool whose tag handlers may
282              * be (re)used to service this action.
283              *
284              * @return The name of the tag handler pool
285              */

286             private String JavaDoc createTagHandlerPoolName(String JavaDoc prefix,
287                     String JavaDoc shortName, Attributes JavaDoc attrs, boolean hasEmptyBody) {
288                 String JavaDoc poolName = null;
289
290                 poolName = "_jspx_tagPool_" + prefix + "_" + shortName;
291                 if (attrs != null) {
292                     String JavaDoc[] attrNames = new String JavaDoc[attrs.getLength()];
293                     for (int i = 0; i < attrNames.length; i++) {
294                         attrNames[i] = attrs.getQName(i);
295                     }
296                     Arrays.sort(attrNames, Collections.reverseOrder());
297                     for (int i = 0; i < attrNames.length; i++) {
298                         poolName = poolName + "_" + attrNames[i];
299                     }
300                 }
301                 if (hasEmptyBody) {
302                     poolName = poolName + "_nobody";
303                 }
304                 return JspUtil.makeJavaIdentifier(poolName);
305             }
306         }
307
308         page.visit(new TagHandlerPoolVisitor(tagHandlerPoolNames));
309     }
310
311     private void declareTemporaryScriptingVars(Node.Nodes page)
312             throws JasperException {
313
314         class ScriptingVarVisitor extends Node.Visitor {
315
316             private Vector JavaDoc vars;
317
318             ScriptingVarVisitor() {
319                 vars = new Vector JavaDoc();
320             }
321
322             public void visit(Node.CustomTag n) throws JasperException {
323
324                 if (n.getCustomNestingLevel() > 0) {
325                     TagVariableInfo JavaDoc[] tagVarInfos = n.getTagVariableInfos();
326                     VariableInfo JavaDoc[] varInfos = n.getVariableInfos();
327
328                     if (varInfos.length > 0) {
329                         for (int i = 0; i < varInfos.length; i++) {
330                             String JavaDoc varName = varInfos[i].getVarName();
331                             String JavaDoc tmpVarName = "_jspx_" + varName + "_"
332                                     + n.getCustomNestingLevel();
333                             if (!vars.contains(tmpVarName)) {
334                                 vars.add(tmpVarName);
335                                 out.printin(varInfos[i].getClassName());
336                                 out.print(" ");
337                                 out.print(tmpVarName);
338                                 out.print(" = ");
339                                 out.print(null);
340                                 out.println(";");
341                             }
342                         }
343                     } else {
344                         for (int i = 0; i < tagVarInfos.length; i++) {
345                             String JavaDoc varName = tagVarInfos[i].getNameGiven();
346                             if (varName == null) {
347                                 varName = n.getTagData().getAttributeString(
348                                         tagVarInfos[i].getNameFromAttribute());
349                             } else if (tagVarInfos[i].getNameFromAttribute() != null) {
350                                 // alias
351
continue;
352                             }
353                             String JavaDoc tmpVarName = "_jspx_" + varName + "_"
354                                     + n.getCustomNestingLevel();
355                             if (!vars.contains(tmpVarName)) {
356                                 vars.add(tmpVarName);
357                                 out.printin(tagVarInfos[i].getClassName());
358                                 out.print(" ");
359                                 out.print(tmpVarName);
360                                 out.print(" = ");
361                                 out.print(null);
362                                 out.println(";");
363                             }
364                         }
365                     }
366                 }
367
368                 visitBody(n);
369             }
370         }
371
372         page.visit(new ScriptingVarVisitor());
373     }
374
375     /**
376      * Generates the _jspInit() method for instantiating the tag handler pools.
377      * For tag file, _jspInit has to be invoked manually, and the ServletConfig
378      * object explicitly passed.
379      *
380      * In JSP 2.1, we also instantiate an ExpressionFactory
381      */

382     private void generateInit() {
383
384         if (ctxt.isTagFile()) {
385             out.printil("private void _jspInit(ServletConfig config) {");
386         } else {
387             out.printil("public void _jspInit() {");
388         }
389
390         out.pushIndent();
391         if (isPoolingEnabled) {
392             for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
393                 out.printin(tagHandlerPoolNames.elementAt(i));
394                 out.print(" = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(");
395                 if (ctxt.isTagFile()) {
396                     out.print("config");
397                 } else {
398                     out.print("getServletConfig()");
399                 }
400                 out.println(");");
401             }
402         }
403         
404         out.printin(VAR_EXPRESSIONFACTORY);
405         out.print(" = JspFactory.getDefaultFactory().getJspApplicationContext(");
406         if (ctxt.isTagFile()) {
407             out.print("config");
408         } else {
409             out.print("getServletConfig()");
410         }
411         out.println(".getServletContext()).getExpressionFactory();");
412
413         out.printin(VAR_ANNOTATIONPROCESSOR);
414         out.print(" = (org.apache.AnnotationProcessor) ");
415         if (ctxt.isTagFile()) {
416             out.print("config");
417         } else {
418             out.print("getServletConfig()");
419         }
420         out.println(".getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());");
421
422         out.popIndent();
423         out.printil("}");
424         out.println();
425     }
426
427     /**
428      * Generates the _jspDestroy() method which is responsible for calling the
429      * release() method on every tag handler in any of the tag handler pools.
430      */

431     private void generateDestroy() {
432
433         out.printil("public void _jspDestroy() {");
434         out.pushIndent();
435         
436         if (isPoolingEnabled) {
437             for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
438                                 out.printin((String JavaDoc) tagHandlerPoolNames.elementAt(i));
439                                 out.println(".release();");
440             }
441         }
442         
443         out.popIndent();
444         out.printil("}");
445         out.println();
446     }
447
448     /**
449      * Generate preamble package name (shared by servlet and tag handler
450      * preamble generation)
451      */

452     private void genPreamblePackage(String JavaDoc packageName) throws JasperException {
453         if (!"".equals(packageName) && packageName != null) {
454             out.printil("package " + packageName + ";");
455             out.println();
456         }
457     }
458
459     /**
460      * Generate preamble imports (shared by servlet and tag handler preamble
461      * generation)
462      */

463     private void genPreambleImports() throws JasperException {
464         Iterator JavaDoc iter = pageInfo.getImports().iterator();
465         while (iter.hasNext()) {
466             out.printin("import ");
467             out.print((String JavaDoc) iter.next());
468             out.println(";");
469         }
470
471         out.println();
472     }
473
474     /**
475      * Generation of static initializers in preamble. For example, dependant
476      * list, el function map, prefix map. (shared by servlet and tag handler
477      * preamble generation)
478      */

479     private void genPreambleStaticInitializers() throws JasperException {
480         // Static data for getDependants()
481
out.printil("private static java.util.List _jspx_dependants;");
482         out.println();
483         List JavaDoc dependants = pageInfo.getDependants();
484         Iterator JavaDoc iter = dependants.iterator();
485         if (!dependants.isEmpty()) {
486             out.printil("static {");
487             out.pushIndent();
488             out.printin("_jspx_dependants = new java.util.ArrayList(");
489             out.print("" + dependants.size());
490             out.println(");");
491             while (iter.hasNext()) {
492                 out.printin("_jspx_dependants.add(\"");
493                 out.print((String JavaDoc) iter.next());
494                 out.println("\");");
495             }
496             out.popIndent();
497             out.printil("}");
498             out.println();
499         }
500     }
501
502     /**
503      * Declare tag handler pools (tags of the same type and with the same
504      * attribute set share the same tag handler pool) (shared by servlet and tag
505      * handler preamble generation)
506      *
507      * In JSP 2.1, we also scope an instance of ExpressionFactory
508      */

509     private void genPreambleClassVariableDeclarations(String JavaDoc className)
510             throws JasperException {
511         if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
512             for (int i = 0; i < tagHandlerPoolNames.size(); i++) {
513                 out.printil("private org.apache.jasper.runtime.TagHandlerPool "
514                         + tagHandlerPoolNames.elementAt(i) + ";");
515             }
516             out.println();
517         }
518         out.printin("private javax.el.ExpressionFactory ");
519         out.print(VAR_EXPRESSIONFACTORY);
520         out.println(";");
521         out.printin("private org.apache.AnnotationProcessor ");
522         out.print(VAR_ANNOTATIONPROCESSOR);
523         out.println(";");
524         out.println();
525     }
526
527     /**
528      * Declare general-purpose methods (shared by servlet and tag handler
529      * preamble generation)
530      */

531     private void genPreambleMethods() throws JasperException {
532         // Method used to get compile time file dependencies
533
out.printil("public Object getDependants() {");
534         out.pushIndent();
535         out.printil("return _jspx_dependants;");
536         out.popIndent();
537         out.printil("}");
538         out.println();
539         
540         generateInit();
541         generateDestroy();
542     }
543
544     /**
545      * Generates the beginning of the static portion of the servlet.
546      */

547     private void generatePreamble(Node.Nodes page) throws JasperException {
548
549         String JavaDoc servletPackageName = ctxt.getServletPackageName();
550         String JavaDoc servletClassName = ctxt.getServletClassName();
551         String JavaDoc serviceMethodName = Constants.SERVICE_METHOD_NAME;
552
553         // First the package name:
554
genPreamblePackage(servletPackageName);
555
556         // Generate imports
557
genPreambleImports();
558
559         // Generate class declaration
560
out.printin("public final class ");
561         out.print(servletClassName);
562         out.print(" extends ");
563         out.println(pageInfo.getExtends());
564         out.printin(" implements org.apache.jasper.runtime.JspSourceDependent");
565         if (!pageInfo.isThreadSafe()) {
566             out.println(",");
567             out.printin(" SingleThreadModel");
568         }
569         out.println(" {");
570         out.pushIndent();
571
572         // Class body begins here
573
generateDeclarations(page);
574
575         // Static initializations here
576
genPreambleStaticInitializers();
577
578         // Class variable declarations
579
genPreambleClassVariableDeclarations(servletClassName);
580
581         // Constructor
582
// generateConstructor(className);
583

584         // Methods here
585
genPreambleMethods();
586
587         // Now the service method
588
out.printin("public void ");
589         out.print(serviceMethodName);
590         out.println("(HttpServletRequest request, HttpServletResponse response)");
591         out.println(" throws java.io.IOException, ServletException {");
592
593         out.pushIndent();
594         out.println();
595
596         // Local variable declarations
597
out.printil("JspFactory _jspxFactory = null;");
598         out.printil("PageContext pageContext = null;");
599
600         if (pageInfo.isSession())
601             out.printil("HttpSession session = null;");
602
603         if (pageInfo.isErrorPage()) {
604             out.printil("Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);");
605             out.printil("if (exception != null) {");
606             out.pushIndent();
607             out.printil("response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);");
608             out.popIndent();
609             out.printil("}");
610         }
611
612         out.printil("ServletContext application = null;");
613         out.printil("ServletConfig config = null;");
614         out.printil("JspWriter out = null;");
615         out.printil("Object page = this;");
616
617         out.printil("JspWriter _jspx_out = null;");
618         out.printil("PageContext _jspx_page_context = null;");
619         out.println();
620
621         declareTemporaryScriptingVars(page);
622         out.println();
623
624         out.printil("try {");
625         out.pushIndent();
626
627         out.printil("_jspxFactory = JspFactory.getDefaultFactory();");
628
629         out.printin("response.setContentType(");
630         out.print(quote(pageInfo.getContentType()));
631         out.println(");");
632
633         if (ctxt.getOptions().isXpoweredBy()) {
634             out.printil("response.addHeader(\"X-Powered-By\", \"JSP/2.0\");");
635         }
636
637         out
638                 .printil("pageContext = _jspxFactory.getPageContext(this, request, response,");
639         out.printin("\t\t\t");
640         out.print(quote(pageInfo.getErrorPage()));
641         out.print(", " + pageInfo.isSession());
642         out.print(", " + pageInfo.getBuffer());
643         out.print(", " + pageInfo.isAutoFlush());
644         out.println(");");
645         out.printil("_jspx_page_context = pageContext;");
646
647         out.printil("application = pageContext.getServletContext();");
648         out.printil("config = pageContext.getServletConfig();");
649
650         if (pageInfo.isSession())
651             out.printil("session = pageContext.getSession();");
652         out.printil("out = pageContext.getOut();");
653         out.printil("_jspx_out = out;");
654         out.println();
655     }
656
657     /**
658      * Generates an XML Prolog, which includes an XML declaration and an XML
659      * doctype declaration.
660      */

661     private void generateXmlProlog(Node.Nodes page) {
662
663         /*
664          * An XML declaration is generated under the following conditions: -
665          * 'omit-xml-declaration' attribute of <jsp:output> action is set to
666          * "no" or "false" - JSP document without a <jsp:root>
667          */

668         String JavaDoc omitXmlDecl = pageInfo.getOmitXmlDecl();
669         if ((omitXmlDecl != null && !JspUtil.booleanValue(omitXmlDecl))
670                 || (omitXmlDecl == null && page.getRoot().isXmlSyntax()
671                         && !pageInfo.hasJspRoot() && !ctxt.isTagFile())) {
672             String JavaDoc cType = pageInfo.getContentType();
673             String JavaDoc charSet = cType.substring(cType.indexOf("charset=") + 8);
674             out.printil("out.write(\"<?xml version=\\\"1.0\\\" encoding=\\\""
675                     + charSet + "\\\"?>\\n\");");
676         }
677
678         /*
679          * Output a DOCTYPE declaration if the doctype-root-element appears. If
680          * doctype-public appears: <!DOCTYPE name PUBLIC "doctypePublic"
681          * "doctypeSystem"> else <!DOCTYPE name SYSTEM "doctypeSystem" >
682          */

683
684         String JavaDoc doctypeName = pageInfo.getDoctypeName();
685         if (doctypeName != null) {
686             String JavaDoc doctypePublic = pageInfo.getDoctypePublic();
687             String JavaDoc doctypeSystem = pageInfo.getDoctypeSystem();
688             out.printin("out.write(\"<!DOCTYPE ");
689             out.print(doctypeName);
690             if (doctypePublic == null) {
691                 out.print(" SYSTEM \\\"");
692             } else {
693                 out.print(" PUBLIC \\\"");
694                 out.print(doctypePublic);
695                 out.print("\\\" \\\"");
696             }
697             out.print(doctypeSystem);
698             out.println("\\\">\\n\");");
699         }
700     }
701
702     /*
703      * Generates the constructor. (shared by servlet and tag handler preamble
704      * generation)
705      */

706     private void generateConstructor(String JavaDoc className) {
707         out.printil("public " + className + "() {");
708         out.printil("}");
709         out.println();
710     }
711
712     /**
713      * A visitor that generates codes for the elements in the page.
714      */

715     class GenerateVisitor extends Node.Visitor {
716
717         /*
718          * Hashtable containing introspection information on tag handlers:
719          * <key>: tag prefix <value>: hashtable containing introspection on tag
720          * handlers: <key>: tag short name <value>: introspection info of tag
721          * handler for <prefix:shortName> tag
722          */

723         private Hashtable JavaDoc handlerInfos;
724
725         private Hashtable JavaDoc tagVarNumbers;
726
727         private String JavaDoc parent;
728
729         private boolean isSimpleTagParent; // Is parent a SimpleTag?
730

731         private String JavaDoc pushBodyCountVar;
732
733         private String JavaDoc simpleTagHandlerVar;
734
735         private boolean isSimpleTagHandler;
736
737         private boolean isFragment;
738
739         private boolean isTagFile;
740
741         private ServletWriter out;
742
743         private ArrayList JavaDoc methodsBuffered;
744
745         private FragmentHelperClass fragmentHelperClass;
746
747         private int methodNesting;
748
749         private TagInfo JavaDoc tagInfo;
750
751         private ClassLoader JavaDoc loader;
752
753         private int charArrayCount;
754
755         private HashMap JavaDoc textMap;
756
757         /**
758          * Constructor.
759          */

760         public GenerateVisitor(boolean isTagFile, ServletWriter out,
761                 ArrayList JavaDoc methodsBuffered,
762                 FragmentHelperClass fragmentHelperClass, ClassLoader JavaDoc loader,
763                 TagInfo JavaDoc tagInfo) {
764
765             this.isTagFile = isTagFile;
766             this.out = out;
767             this.methodsBuffered = methodsBuffered;
768             this.fragmentHelperClass = fragmentHelperClass;
769             this.loader = loader;
770             this.tagInfo = tagInfo;
771             methodNesting = 0;
772             handlerInfos = new Hashtable JavaDoc();
773             tagVarNumbers = new Hashtable JavaDoc();
774             textMap = new HashMap JavaDoc();
775         }
776
777         /**
778          * Returns an attribute value, optionally URL encoded. If the value is a
779          * runtime expression, the result is the expression itself, as a string.
780          * If the result is an EL expression, we insert a call to the
781          * interpreter. If the result is a Named Attribute we insert the
782          * generated variable name. Otherwise the result is a string literal,
783          * quoted and escaped.
784          *
785          * @param attr
786          * An JspAttribute object
787          * @param encode
788          * true if to be URL encoded
789          * @param expectedType
790          * the expected type for an EL evaluation (ignored for
791          * attributes that aren't EL expressions)
792          */

793         private String JavaDoc attributeValue(Node.JspAttribute attr, boolean encode,
794                 Class JavaDoc expectedType) {
795             String JavaDoc v = attr.getValue();
796             if (!attr.isNamedAttribute() && (v == null))
797                 return "";
798
799             if (attr.isExpression()) {
800                 if (encode) {
801                     return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(String.valueOf("
802                             + v + "), request.getCharacterEncoding())";
803                 }
804                 return v;
805             } else if (attr.isELInterpreterInput()) {
806                 boolean replaceESC = v.indexOf(Constants.ESC) > 0;
807                 v = JspUtil.interpreterCall(this.isTagFile, v, expectedType,
808                         attr.getEL().getMapName(), false);
809                 // XXX ESC replacement hack
810
if (replaceESC) {
811                     v = "(" + v + ").replace(" + Constants.ESCStr + ", '$')";
812                 }
813                 if (encode) {
814                     return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
815                             + v + ", request.getCharacterEncoding())";
816                 }
817                 return v;
818             } else if (attr.isNamedAttribute()) {
819                 return attr.getNamedAttributeNode().getTemporaryVariableName();
820             } else {
821                 if (encode) {
822                     return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
823                             + quote(v) + ", request.getCharacterEncoding())";
824                 }
825                 return quote(v);
826             }
827         }
828
829         /**
830          * Prints the attribute value specified in the param action, in the form
831          * of name=value string.
832          *
833          * @param n
834          * the parent node for the param action nodes.
835          */

836         private void printParams(Node n, String JavaDoc pageParam, boolean literal)
837                 throws JasperException {
838
839             class ParamVisitor extends Node.Visitor {
840                 String JavaDoc separator;
841
842                 ParamVisitor(String JavaDoc separator) {
843                     this.separator = separator;
844                 }
845
846                 public void visit(Node.ParamAction n) throws JasperException {
847
848                     out.print(" + ");
849                     out.print(separator);
850                     out.print(" + ");
851                     out.print("org.apache.jasper.runtime.JspRuntimeLibrary."
852                             + "URLEncode(" + quote(n.getTextAttribute("name"))
853                             + ", request.getCharacterEncoding())");
854                     out.print("+ \"=\" + ");
855                     out.print(attributeValue(n.getValue(), true, String JavaDoc.class));
856
857                     // The separator is '&' after the second use
858
separator = "\"&\"";
859                 }
860             }
861
862             String JavaDoc sep;
863             if (literal) {
864                 sep = pageParam.indexOf('?') > 0 ? "\"&\"" : "\"?\"";
865             } else {
866                 sep = "((" + pageParam + ").indexOf('?')>0? '&': '?')";
867             }
868             if (n.getBody() != null) {
869                 n.getBody().visit(new ParamVisitor(sep));
870             }
871         }
872
873         public void visit(Node.Expression n) throws JasperException {
874             n.setBeginJavaLine(out.getJavaLine());
875             out.printin("out.print(");
876             out.printMultiLn(n.getText());
877             out.println(");");
878             n.setEndJavaLine(out.getJavaLine());
879         }
880
881         public void visit(Node.Scriptlet n) throws JasperException {
882             n.setBeginJavaLine(out.getJavaLine());
883             out.printMultiLn(n.getText());
884             out.println();
885             n.setEndJavaLine(out.getJavaLine());
886         }
887
888         public void visit(Node.ELExpression n) throws JasperException {
889             n.setBeginJavaLine(out.getJavaLine());
890             if (!pageInfo.isELIgnored() && (n.getEL() != null)) {
891                 out.printil("out.write("
892                         + JspUtil.interpreterCall(this.isTagFile, n.getType() + "{"
893                                 + new String JavaDoc(n.getText()) + "}", String JavaDoc.class,
894                                 n.getEL().getMapName(), false) + ");");
895             } else {
896                 out.printil("out.write("
897                         + quote(n.getType() + "{" + new String JavaDoc(n.getText()) + "}") + ");");
898             }
899             n.setEndJavaLine(out.getJavaLine());
900         }
901
902         public void visit(Node.IncludeAction n) throws JasperException {
903
904             String JavaDoc flush = n.getTextAttribute("flush");
905             Node.JspAttribute page = n.getPage();
906
907             boolean isFlush = false; // default to false;
908
if ("true".equals(flush))
909                 isFlush = true;
910
911             n.setBeginJavaLine(out.getJavaLine());
912
913             String JavaDoc pageParam;
914             if (page.isNamedAttribute()) {
915                 // If the page for jsp:include was specified via
916
// jsp:attribute, first generate code to evaluate
917
// that body.
918
pageParam = generateNamedAttributeValue(page
919                         .getNamedAttributeNode());
920             } else {
921                 pageParam = attributeValue(page, false, String JavaDoc.class);
922             }
923
924             // If any of the params have their values specified by
925
// jsp:attribute, prepare those values first.
926
Node jspBody = findJspBody(n);
927             if (jspBody != null) {
928                 prepareParams(jspBody);
929             } else {
930                 prepareParams(n);
931             }
932
933             out
934                     .printin("org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, "
935                             + pageParam);
936             printParams(n, pageParam, page.isLiteral());
937             out.println(", out, " + isFlush + ");");
938
939             n.setEndJavaLine(out.getJavaLine());
940         }
941
942         /**
943          * Scans through all child nodes of the given parent for <param>
944          * subelements. For each <param> element, if its value is specified via
945          * a Named Attribute (<jsp:attribute>), generate the code to evaluate
946          * those bodies first.
947          * <p>
948          * If parent is null, simply returns.
949          */

950         private void prepareParams(Node parent) throws JasperException {
951             if (parent == null)
952                 return;
953
954             Node.Nodes subelements = parent.getBody();
955             if (subelements != null) {
956                 for (int i = 0; i < subelements.size(); i++) {
957                     Node n = subelements.getNode(i);
958                     if (n instanceof Node.ParamAction) {
959                         Node.Nodes paramSubElements = n.getBody();
960                         for (int j = 0; (paramSubElements != null)
961                                 && (j < paramSubElements.size()); j++) {
962                             Node m = paramSubElements.getNode(j);
963                             if (m instanceof Node.NamedAttribute) {
964                                 generateNamedAttributeValue((Node.NamedAttribute) m);
965                             }
966                         }
967                     }
968                 }
969             }
970         }
971
972         /**
973          * Finds the <jsp:body> subelement of the given parent node. If not
974          * found, null is returned.
975          */

976         private Node.JspBody findJspBody(Node parent) throws JasperException {
977             Node.JspBody result = null;
978
979             Node.Nodes subelements = parent.getBody();
980             for (int i = 0; (subelements != null) && (i < subelements.size()); i++) {
981                 Node n = subelements.getNode(i);
982                 if (n instanceof Node.JspBody) {
983                     result = (Node.JspBody) n;
984                     break;
985                 }
986             }
987
988             return result;
989         }
990
991         public void visit(Node.ForwardAction n) throws JasperException {
992             Node.JspAttribute page = n.getPage();
993
994             n.setBeginJavaLine(out.getJavaLine());
995
996             out.printil("if (true) {"); // So that javac won't complain about
997
out.pushIndent(); // codes after "return"
998

999             String JavaDoc pageParam;
1000            if (page.isNamedAttribute()) {
1001                // If the page for jsp:forward was specified via
1002
// jsp:attribute, first generate code to evaluate
1003
// that body.
1004
pageParam = generateNamedAttributeValue(page
1005                        .getNamedAttributeNode());
1006            } else {
1007                pageParam = attributeValue(page, false, String JavaDoc.class);
1008            }
1009
1010            // If any of the params have their values specified by
1011
// jsp:attribute, prepare those values first.
1012
Node jspBody = findJspBody(n);
1013            if (jspBody != null) {
1014                prepareParams(jspBody);
1015            } else {
1016                prepareParams(n);
1017            }
1018
1019            out.printin("_jspx_page_context.forward(");
1020            out.print(pageParam);
1021            printParams(n, pageParam, page.isLiteral());
1022            out.println(");");
1023            if (isTagFile || isFragment) {
1024                out.printil("throw new SkipPageException();");
1025            } else {
1026                out.printil((methodNesting > 0) ? "return true;" : "return;");
1027            }
1028            out.popIndent();
1029            out.printil("}");
1030
1031            n.setEndJavaLine(out.getJavaLine());
1032            // XXX Not sure if we can eliminate dead codes after this.
1033
}
1034
1035        public void visit(Node.GetProperty n) throws JasperException {
1036            String JavaDoc name = n.getTextAttribute("name");
1037            String JavaDoc property = n.getTextAttribute("property");
1038
1039            n.setBeginJavaLine(out.getJavaLine());
1040
1041            if (beanInfo.checkVariable(name)) {
1042                // Bean is defined using useBean, introspect at compile time
1043
Class JavaDoc bean = beanInfo.getBeanType(name);
1044                String JavaDoc beanName = JspUtil.getCanonicalName(bean);
1045                java.lang.reflect.Method JavaDoc meth = JspRuntimeLibrary
1046                        .getReadMethod(bean, property);
1047                String JavaDoc methodName = meth.getName();
1048                out
1049                        .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString("
1050                                + "((("
1051                                + beanName
1052                                + ")_jspx_page_context.findAttribute("
1053                                + "\""
1054                                + name + "\"))." + methodName + "())));");
1055            } else {
1056                // The object could be a custom action with an associated
1057
// VariableInfo entry for this name.
1058
// Get the class name and then introspect at runtime.
1059
out
1060                        .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString"
1061                                + "(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty"
1062                                + "(_jspx_page_context.getAttribute(\""
1063                                + name
1064                                + "\", PageContext.PAGE_SCOPE), \""
1065                                + property
1066                                + "\")));");
1067            }
1068
1069            n.setEndJavaLine(out.getJavaLine());
1070        }
1071
1072        public void visit(Node.SetProperty n) throws JasperException {
1073            String JavaDoc name = n.getTextAttribute("name");
1074            String JavaDoc property = n.getTextAttribute("property");
1075            String JavaDoc param = n.getTextAttribute("param");
1076            Node.JspAttribute value = n.getValue();
1077
1078            n.setBeginJavaLine(out.getJavaLine());
1079
1080            if ("*".equals(property)) {
1081                out
1082                        .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspect("
1083                                + "_jspx_page_context.findAttribute("
1084                                + "\""
1085                                + name + "\"), request);");
1086            } else if (value == null) {
1087                if (param == null)
1088                    param = property; // default to same as property
1089
out
1090                        .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
1091                                + "_jspx_page_context.findAttribute(\""
1092                                + name
1093                                + "\"), \""
1094                                + property
1095                                + "\", request.getParameter(\""
1096                                + param
1097                                + "\"), "
1098                                + "request, \""
1099                                + param
1100                                + "\", false);");
1101            } else if (value.isExpression()) {
1102                out
1103                        .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetProperty("
1104                                + "_jspx_page_context.findAttribute(\""
1105                                + name
1106                                + "\"), \"" + property + "\",");
1107                out.print(attributeValue(value, false, null));
1108                out.println(");");
1109            } else if (value.isELInterpreterInput()) {
1110                // We've got to resolve the very call to the interpreter
1111
// at runtime since we don't know what type to expect
1112
// in the general case; we thus can't hard-wire the call
1113
// into the generated code. (XXX We could, however,
1114
// optimize the case where the bean is exposed with
1115
// <jsp:useBean>, much as the code here does for
1116
// getProperty.)
1117

1118                // The following holds true for the arguments passed to
1119
// JspRuntimeLibrary.handleSetPropertyExpression():
1120
// - 'pageContext' is a VariableResolver.
1121
// - 'this' (either the generated Servlet or the generated tag
1122
// handler for Tag files) is a FunctionMapper.
1123
out
1124                        .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetPropertyExpression("
1125                                + "_jspx_page_context.findAttribute(\""
1126                                + name
1127                                + "\"), \""
1128                                + property
1129                                + "\", "
1130                                + quote(value.getValue())
1131                                + ", "
1132                                + "_jspx_page_context, "
1133                                + value.getEL().getMapName() + ");");
1134            } else if (value.isNamedAttribute()) {
1135                // If the value for setProperty was specified via
1136
// jsp:attribute, first generate code to evaluate
1137
// that body.
1138
String JavaDoc valueVarName = generateNamedAttributeValue(value
1139                        .getNamedAttributeNode());
1140                out
1141                        .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
1142                                + "_jspx_page_context.findAttribute(\""
1143                                + name
1144                                + "\"), \""
1145                                + property
1146                                + "\", "
1147                                + valueVarName
1148                                + ", null, null, false);");
1149            } else {
1150                out
1151                        .printin("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper("
1152                                + "_jspx_page_context.findAttribute(\""
1153                                + name
1154                                + "\"), \"" + property + "\", ");
1155                out.print(attributeValue(value, false, null));
1156                out.println(", null, null, false);");
1157            }
1158
1159            n.setEndJavaLine(out.getJavaLine());
1160        }
1161
1162        public void visit(Node.UseBean n) throws JasperException {
1163
1164            String JavaDoc name = n.getTextAttribute("id");
1165            String JavaDoc scope = n.getTextAttribute("scope");
1166            String JavaDoc klass = n.getTextAttribute("class");
1167            String JavaDoc type = n.getTextAttribute("type");
1168            Node.JspAttribute beanName = n.getBeanName();
1169
1170            // If "class" is specified, try an instantiation at compile time
1171
boolean generateNew = false;
1172            String JavaDoc canonicalName = null; // Canonical name for klass
1173
if (klass != null) {
1174                try {
1175                    Class JavaDoc bean = ctxt.getClassLoader().loadClass(klass);
1176                    if (klass.indexOf('$') >= 0) {
1177                        // Obtain the canonical type name
1178
canonicalName = JspUtil.getCanonicalName(bean);
1179                    } else {
1180                        canonicalName = klass;
1181                    }
1182                    int modifiers = bean.getModifiers();
1183                    if (!Modifier.isPublic(modifiers)
1184                            || Modifier.isInterface(modifiers)
1185                            || Modifier.isAbstract(modifiers)) {
1186                        throw new Exception JavaDoc("Invalid bean class modifier");
1187                    }
1188                    // Check that there is a 0 arg constructor
1189
bean.getConstructor(new Class JavaDoc[] {});
1190                    // At compile time, we have determined that the bean class
1191
// exists, with a public zero constructor, new() can be
1192
// used for bean instantiation.
1193
generateNew = true;
1194                } catch (Exception JavaDoc e) {
1195                    // Cannot instantiate the specified class, either a
1196
// compilation error or a runtime error will be raised,
1197
// depending on a compiler flag.
1198
if (ctxt.getOptions()
1199                            .getErrorOnUseBeanInvalidClassAttribute()) {
1200                        err.jspError(n, "jsp.error.invalid.bean", klass);
1201                    }
1202                    if (canonicalName == null) {
1203                        // Doing our best here to get a canonical name
1204
// from the binary name, should work 99.99% of time.
1205
canonicalName = klass.replace('$', '.');
1206                    }
1207                }
1208                if (type == null) {
1209                    // if type is unspecified, use "class" as type of bean
1210
type = canonicalName;
1211                }
1212            }
1213
1214            String JavaDoc scopename = "PageContext.PAGE_SCOPE"; // Default to page
1215
String JavaDoc lock = "_jspx_page_context";
1216
1217            if ("request".equals(scope)) {
1218                scopename = "PageContext.REQUEST_SCOPE";
1219                lock = "request";
1220            } else if ("session".equals(scope)) {
1221                scopename = "PageContext.SESSION_SCOPE";
1222                lock = "session";
1223            } else if ("application".equals(scope)) {
1224                scopename = "PageContext.APPLICATION_SCOPE";
1225                lock = "application";
1226            }
1227
1228            n.setBeginJavaLine(out.getJavaLine());
1229
1230            // Declare bean
1231
out.printin(type);
1232            out.print(' ');
1233            out.print(name);
1234            out.println(" = null;");
1235
1236            // Lock while getting or creating bean
1237
out.printin("synchronized (");
1238            out.print(lock);
1239            out.println(") {");
1240            out.pushIndent();
1241
1242            // Locate bean from context
1243
out.printin(name);
1244            out.print(" = (");
1245            out.print(type);
1246            out.print(") _jspx_page_context.getAttribute(");
1247            out.print(quote(name));
1248            out.print(", ");
1249            out.print(scopename);
1250            out.println(");");
1251
1252            // Create bean
1253
/*
1254             * Check if bean is alredy there
1255             */

1256            out.printin("if (");
1257            out.print(name);
1258            out.println(" == null){");
1259            out.pushIndent();
1260            if (klass == null && beanName == null) {
1261                /*
1262                 * If both class name and beanName is not specified, the bean
1263                 * must be found locally, otherwise it's an error
1264                 */

1265                out
1266                        .printin("throw new java.lang.InstantiationException(\"bean ");
1267                out.print(name);
1268                out.println(" not found within scope\");");
1269            } else {
1270                /*
1271                 * Instantiate the bean if it is not in the specified scope.
1272                 */

1273                if (!generateNew) {
1274                    String JavaDoc binaryName;
1275                    if (beanName != null) {
1276                        if (beanName.isNamedAttribute()) {
1277                            // If the value for beanName was specified via
1278
// jsp:attribute, first generate code to evaluate
1279
// that body.
1280
binaryName = generateNamedAttributeValue(beanName
1281                                    .getNamedAttributeNode());
1282                        } else {
1283                            binaryName = attributeValue(beanName, false,
1284                                    String JavaDoc.class);
1285                        }
1286                    } else {
1287                        // Implies klass is not null
1288
binaryName = quote(klass);
1289                    }
1290                    out.printil("try {");
1291                    out.pushIndent();
1292                    out.printin(name);
1293                    out.print(" = (");
1294                    out.print(type);
1295                    out.print(") java.beans.Beans.instantiate(");
1296                    out.print("this.getClass().getClassLoader(), ");
1297                    out.print(binaryName);
1298                    out.println(");");
1299                    out.popIndent();
1300                    /*
1301                     * Note: Beans.instantiate throws ClassNotFoundException if
1302                     * the bean class is abstract.
1303                     */

1304                    out.printil("} catch (ClassNotFoundException exc) {");
1305                    out.pushIndent();
1306                    out
1307                            .printil("throw new InstantiationException(exc.getMessage());");
1308                    out.popIndent();
1309                    out.printil("} catch (Exception exc) {");
1310                    out.pushIndent();
1311                    out.printin("throw new ServletException(");
1312                    out.print("\"Cannot create bean of class \" + ");
1313                    out.print(binaryName);
1314                    out.println(", exc);");
1315                    out.popIndent();
1316                    out.printil("}"); // close of try
1317
} else {
1318                    // Implies klass is not null
1319
// Generate codes to instantiate the bean class
1320
out.printin(name);
1321                    out.print(" = new ");
1322                    out.print(canonicalName);
1323                    out.println("();");
1324                }
1325                /*
1326                 * Set attribute for bean in the specified scope
1327                 */

1328                out.printin("_jspx_page_context.setAttribute(");
1329                out.print(quote(name));
1330                out.print(", ");
1331                out.print(name);
1332                out.print(", ");
1333                out.print(scopename);
1334                out.println(");");
1335
1336                // Only visit the body when bean is instantiated
1337
visitBody(n);
1338            }
1339            out.popIndent();
1340            out.printil("}");
1341
1342            // End of lock block
1343
out.popIndent();
1344            out.printil("}");
1345
1346            n.setEndJavaLine(out.getJavaLine());
1347        }
1348
1349        /**
1350         * @return a string for the form 'attr = "value"'
1351         */

1352        private String JavaDoc makeAttr(String JavaDoc attr, String JavaDoc value) {
1353            if (value == null)
1354                return "";
1355
1356            return " " + attr + "=\"" + value + '\"';
1357        }
1358
1359        public void visit(Node.PlugIn n) throws JasperException {
1360
1361            /**
1362             * A visitor to handle <jsp:param> in a plugin
1363             */

1364            class ParamVisitor extends Node.Visitor {
1365
1366                private boolean ie;
1367
1368                ParamVisitor(boolean ie) {
1369                    this.ie = ie;
1370                }
1371
1372                public void visit(Node.ParamAction n) throws JasperException {
1373
1374                    String JavaDoc name = n.getTextAttribute("name");
1375                    if (name.equalsIgnoreCase("object"))
1376                        name = "java_object";
1377                    else if (name.equalsIgnoreCase("type"))
1378                        name = "java_type";
1379
1380                    n.setBeginJavaLine(out.getJavaLine());
1381                    // XXX - Fixed a bug here - value used to be output
1382
// inline, which is only okay if value is not an EL
1383
// expression. Also, key/value pairs for the
1384
// embed tag were not being generated correctly.
1385
// Double check that this is now the correct behavior.
1386
if (ie) {
1387                        // We want something of the form
1388
// out.println( "<PARAM name=\"blah\"
1389
// value=\"" + ... + "\">" );
1390
out.printil("out.write( \"<PARAM name=\\\""
1391                                + escape(name)
1392                                + "\\\" value=\\\"\" + "
1393                                + attributeValue(n.getValue(), false,
1394                                        String JavaDoc.class) + " + \"\\\">\" );");
1395                        out.printil("out.write(\"\\n\");");
1396                    } else {
1397                        // We want something of the form
1398
// out.print( " blah=\"" + ... + "\"" );
1399
out.printil("out.write( \" "
1400                                + escape(name)
1401                                + "=\\\"\" + "
1402                                + attributeValue(n.getValue(), false,
1403                                        String JavaDoc.class) + " + \"\\\"\" );");
1404                    }
1405
1406                    n.setEndJavaLine(out.getJavaLine());
1407                }
1408            }
1409
1410            String JavaDoc type = n.getTextAttribute("type");
1411            String JavaDoc code = n.getTextAttribute("code");
1412            String JavaDoc name = n.getTextAttribute("name");
1413            Node.JspAttribute height = n.getHeight();
1414            Node.JspAttribute width = n.getWidth();
1415            String JavaDoc hspace = n.getTextAttribute("hspace");
1416            String JavaDoc vspace = n.getTextAttribute("vspace");
1417            String JavaDoc align = n.getTextAttribute("align");
1418            String JavaDoc iepluginurl = n.getTextAttribute("iepluginurl");
1419            String JavaDoc nspluginurl = n.getTextAttribute("nspluginurl");
1420            String JavaDoc codebase = n.getTextAttribute("codebase");
1421            String JavaDoc archive = n.getTextAttribute("archive");
1422            String JavaDoc jreversion = n.getTextAttribute("jreversion");
1423
1424            String JavaDoc widthStr = null;
1425            if (width != null) {
1426                if (width.isNamedAttribute()) {
1427                    widthStr = generateNamedAttributeValue(width
1428                            .getNamedAttributeNode());
1429                } else {
1430                    widthStr = attributeValue(width, false, String JavaDoc.class);
1431                }
1432            }
1433
1434            String JavaDoc heightStr = null;
1435            if (height != null) {
1436                if (height.isNamedAttribute()) {
1437                    heightStr = generateNamedAttributeValue(height
1438                            .getNamedAttributeNode());
1439                } else {
1440                    heightStr = attributeValue(height, false, String JavaDoc.class);
1441                }
1442            }
1443
1444            if (iepluginurl == null)
1445                iepluginurl = Constants.IE_PLUGIN_URL;
1446            if (nspluginurl == null)
1447                nspluginurl = Constants.NS_PLUGIN_URL;
1448
1449            n.setBeginJavaLine(out.getJavaLine());
1450
1451            // If any of the params have their values specified by
1452
// jsp:attribute, prepare those values first.
1453
// Look for a params node and prepare its param subelements:
1454
Node.JspBody jspBody = findJspBody(n);
1455            if (jspBody != null) {
1456                Node.Nodes subelements = jspBody.getBody();
1457                if (subelements != null) {
1458                    for (int i = 0; i < subelements.size(); i++) {
1459                        Node m = subelements.getNode(i);
1460                        if (m instanceof Node.ParamsAction) {
1461                            prepareParams(m);
1462                            break;
1463                        }
1464                    }
1465                }
1466            }
1467
1468            // XXX - Fixed a bug here - width and height can be set
1469
// dynamically. Double-check if this generation is correct.
1470

1471            // IE style plugin
1472
// <OBJECT ...>
1473
// First compose the runtime output string
1474
String JavaDoc s0 = "<OBJECT"
1475                    + makeAttr("classid", ctxt.getOptions().getIeClassId())
1476                    + makeAttr("name", name);
1477
1478            String JavaDoc s1 = "";
1479            if (width != null) {
1480                s1 = " + \" width=\\\"\" + " + widthStr + " + \"\\\"\"";
1481            }
1482
1483            String JavaDoc s2 = "";
1484            if (height != null) {
1485                s2 = " + \" height=\\\"\" + " + heightStr + " + \"\\\"\"";
1486            }
1487
1488            String JavaDoc s3 = makeAttr("hspace", hspace) + makeAttr("vspace", vspace)
1489                    + makeAttr("align", align)
1490                    + makeAttr("codebase", iepluginurl) + '>';
1491
1492            // Then print the output string to the java file
1493
out.printil("out.write(" + quote(s0) + s1 + s2 + " + " + quote(s3)
1494                    + ");");
1495            out.printil("out.write(\"\\n\");");
1496
1497            // <PARAM > for java_code
1498
s0 = "<PARAM name=\"java_code\"" + makeAttr("value", code) + '>';
1499            out.printil("out.write(" + quote(s0) + ");");
1500            out.printil("out.write(\"\\n\");");
1501
1502            // <PARAM > for java_codebase
1503
if (codebase != null) {
1504                s0 = "<PARAM name=\"java_codebase\""
1505                        + makeAttr("value", codebase) + '>';
1506                out.printil("out.write(" + quote(s0) + ");");
1507                out.printil("out.write(\"\\n\");");
1508            }
1509
1510            // <PARAM > for java_archive
1511
if (archive != null) {
1512                s0 = "<PARAM name=\"java_archive\""
1513                        + makeAttr("value", archive) + '>';
1514                out.printil("out.write(" + quote(s0) + ");");
1515                out.printil("out.write(\"\\n\");");
1516            }
1517
1518            // <PARAM > for type
1519
s0 = "<PARAM name=\"type\""
1520                    + makeAttr("value", "application/x-java-"
1521                            + type
1522                            + ";"
1523                            + ((jreversion == null) ? "" : "version="
1524                                    + jreversion)) + '>';
1525            out.printil("out.write(" + quote(s0) + ");");
1526            out.printil("out.write(\"\\n\");");
1527
1528            /*
1529             * generate a <PARAM> for each <jsp:param> in the plugin body
1530             */

1531            if (n.getBody() != null)
1532                n.getBody().visit(new ParamVisitor(true));
1533
1534            /*
1535             * Netscape style plugin part
1536             */

1537            out.printil("out.write(" + quote("<COMMENT>") + ");");
1538            out.printil("out.write(\"\\n\");");
1539            s0 = "<EMBED"
1540                    + makeAttr("type", "application/x-java-"
1541                            + type
1542                            + ";"
1543                            + ((jreversion == null) ? "" : "version="
1544                                    + jreversion)) + makeAttr("name", name);
1545
1546            // s1 and s2 are the same as before.
1547

1548            s3 = makeAttr("hspace", hspace) + makeAttr("vspace", vspace)
1549                    + makeAttr("align", align)
1550                    + makeAttr("pluginspage", nspluginurl)
1551                    + makeAttr("java_code", code)
1552                    + makeAttr("java_codebase", codebase)
1553                    + makeAttr("java_archive", archive);
1554            out.printil("out.write(" + quote(s0) + s1 + s2 + " + " + quote(s3)
1555                    + ");");
1556
1557            /*
1558             * Generate a 'attr = "value"' for each <jsp:param> in plugin body
1559             */

1560            if (n.getBody() != null)
1561                n.getBody().visit(new ParamVisitor(false));
1562
1563            out.printil("out.write(" + quote("/>") + ");");
1564            out.printil("out.write(\"\\n\");");
1565
1566            out.printil("out.write(" + quote("<NOEMBED>") + ");");
1567            out.printil("out.write(\"\\n\");");
1568
1569            /*
1570             * Fallback
1571             */

1572            if (n.getBody() != null) {
1573                visitBody(n);
1574                out.printil("out.write(\"\\n\");");
1575            }
1576
1577            out.printil("out.write(" + quote("</NOEMBED>") + ");");
1578            out.printil("out.write(\"\\n\");");
1579
1580            out.printil("out.write(" + quote("</COMMENT>") + ");");
1581            out.printil("out.write(\"\\n\");");
1582
1583            out.printil("out.write(" + quote("</OBJECT>") + ");");
1584            out.printil("out.write(\"\\n\");");
1585
1586            n.setEndJavaLine(out.getJavaLine());
1587        }
1588
1589        public void visit(Node.NamedAttribute n) throws JasperException {
1590            // Don't visit body of this tag - we already did earlier.
1591
}
1592
1593        public void visit(Node.CustomTag n) throws JasperException {
1594
1595            // Use plugin to generate more efficient code if there is one.
1596
if (n.useTagPlugin()) {
1597                generateTagPlugin(n);
1598                return;
1599            }
1600
1601            TagHandlerInfo handlerInfo = getTagHandlerInfo(n);
1602
1603            // Create variable names
1604
String JavaDoc baseVar = createTagVarName(n.getQName(), n.getPrefix(), n
1605                    .getLocalName());
1606            String JavaDoc tagEvalVar = "_jspx_eval_" + baseVar;
1607            String JavaDoc tagHandlerVar = "_jspx_th_" + baseVar;
1608            String JavaDoc tagPushBodyCountVar = "_jspx_push_body_count_" + baseVar;
1609
1610            // If the tag contains no scripting element, generate its codes
1611
// to a method.
1612
ServletWriter outSave = null;
1613            Node.ChildInfo ci = n.getChildInfo();
1614            if (ci.isScriptless() && !ci.hasScriptingVars()) {
1615                // The tag handler and its body code can reside in a separate
1616
// method if it is scriptless and does not have any scripting
1617
// variable defined.
1618

1619                String JavaDoc tagMethod = "_jspx_meth_" + baseVar;
1620
1621                // Generate a call to this method
1622
out.printin("if (");
1623                out.print(tagMethod);
1624                out.print("(");
1625                if (parent != null) {
1626                    out.print(parent);
1627                    out.print(", ");
1628                }
1629                out.print("_jspx_page_context");
1630                if (pushBodyCountVar != null) {
1631                    out.print(", ");
1632                    out.print(pushBodyCountVar);
1633                }
1634                out.println("))");
1635                out.pushIndent();
1636                out.printil((methodNesting > 0) ? "return true;" : "return;");
1637                out.popIndent();
1638
1639                // Set up new buffer for the method
1640
outSave = out;
1641                /*
1642                 * For fragments, their bodies will be generated in fragment
1643                 * helper classes, and the Java line adjustments will be done
1644                 * there, hence they are set to null here to avoid double
1645                 * adjustments.
1646                 */

1647                GenBuffer genBuffer = new GenBuffer(n,
1648                        n.implementsSimpleTag() ? null : n.getBody());
1649                methodsBuffered.add(genBuffer);
1650                out = genBuffer.getOut();
1651
1652                methodNesting++;
1653                // Generate code for method declaration
1654
out.println();
1655                out.pushIndent();
1656                out.printin("private boolean ");
1657                out.print(tagMethod);
1658                out.print("(");
1659                if (parent != null) {
1660                    out.print("javax.servlet.jsp.tagext.JspTag ");
1661                    out.print(parent);
1662                    out.print(", ");
1663                }
1664                out.print("PageContext _jspx_page_context");
1665                if (pushBodyCountVar != null) {
1666                    out.print(", int[] ");
1667                    out.print(pushBodyCountVar);
1668                }
1669                out.println(")");
1670                out.printil(" throws Throwable {");
1671                out.pushIndent();
1672
1673                // Initilaize local variables used in this method.
1674
if (!isTagFile) {
1675                    out
1676                            .printil("PageContext pageContext = _jspx_page_context;");
1677                }
1678                out.printil("JspWriter out = _jspx_page_context.getOut();");
1679                generateLocalVariables(out, n);
1680            }
1681
1682            if (n.implementsSimpleTag()) {
1683                generateCustomDoTag(n, handlerInfo, tagHandlerVar);
1684            } else {
1685                /*
1686                 * Classic tag handler: Generate code for start element, body,
1687                 * and end element
1688                 */

1689                generateCustomStart(n, handlerInfo, tagHandlerVar, tagEvalVar,
1690                        tagPushBodyCountVar);
1691
1692                // visit body
1693
String JavaDoc tmpParent = parent;
1694                parent = tagHandlerVar;
1695                boolean isSimpleTagParentSave = isSimpleTagParent;
1696                isSimpleTagParent = false;
1697                String JavaDoc tmpPushBodyCountVar = null;
1698                if (n.implementsTryCatchFinally()) {
1699                    tmpPushBodyCountVar = pushBodyCountVar;
1700                    pushBodyCountVar = tagPushBodyCountVar;
1701                }
1702                boolean tmpIsSimpleTagHandler = isSimpleTagHandler;
1703                isSimpleTagHandler = false;
1704
1705                visitBody(n);
1706
1707                parent = tmpParent;
1708                isSimpleTagParent = isSimpleTagParentSave;
1709                if (n.implementsTryCatchFinally()) {
1710                    pushBodyCountVar = tmpPushBodyCountVar;
1711                }
1712                isSimpleTagHandler = tmpIsSimpleTagHandler;
1713
1714                generateCustomEnd(n, tagHandlerVar, tagEvalVar,
1715                        tagPushBodyCountVar);
1716            }
1717
1718            if (ci.isScriptless() && !ci.hasScriptingVars()) {
1719                // Generate end of method
1720
if (methodNesting > 0) {
1721                    out.printil("return false;");
1722                }
1723                out.popIndent();
1724                out.printil("}");
1725                out.popIndent();
1726
1727                methodNesting--;
1728
1729                // restore previous writer
1730
out = outSave;
1731            }
1732        }
1733
1734        private static final String JavaDoc SINGLE_QUOTE = "'";
1735
1736        private static final String JavaDoc DOUBLE_QUOTE = "\\\"";
1737
1738        public void visit(Node.UninterpretedTag n) throws JasperException {
1739
1740            n.setBeginJavaLine(out.getJavaLine());
1741
1742            /*
1743             * Write begin tag
1744             */

1745            out.printin("out.write(\"<");
1746            out.print(n.getQName());
1747
1748            Attributes JavaDoc attrs = n.getNonTaglibXmlnsAttributes();
1749            int attrsLen = (attrs == null) ? 0 : attrs.getLength();
1750            for (int i = 0; i < attrsLen; i++) {
1751                out.print(" ");
1752                out.print(attrs.getQName(i));
1753                out.print("=");
1754                String JavaDoc quote = DOUBLE_QUOTE;
1755                String JavaDoc value = attrs.getValue(i);
1756                if (value.indexOf('"') != -1) {
1757                    quote = SINGLE_QUOTE;
1758                }
1759                out.print(quote);
1760                out.print(value);
1761                out.print(quote);
1762            }
1763
1764            attrs = n.getAttributes();
1765            attrsLen = (attrs == null) ? 0 : attrs.getLength();
1766            Node.JspAttribute[] jspAttrs = n.getJspAttributes();
1767            for (int i = 0; i < attrsLen; i++) {
1768                out.print(" ");
1769                out.print(attrs.getQName(i));
1770                out.print("=");
1771                if (jspAttrs[i].isELInterpreterInput()) {
1772                    out.print("\\\"\" + ");
1773                    out.print(attributeValue(jspAttrs[i], false, String JavaDoc.class));
1774                    out.print(" + \"\\\"");
1775                } else {
1776                    String JavaDoc quote = DOUBLE_QUOTE;
1777                    String JavaDoc value = attrs.getValue(i);
1778                    if (value.indexOf('"') != -1) {
1779                        quote = SINGLE_QUOTE;
1780                    }
1781                    out.print(quote);
1782                    out.print(value);
1783                    out.print(quote);
1784                }
1785            }
1786
1787            if (n.getBody() != null) {
1788                out.println(">\");");
1789
1790                // Visit tag body
1791
visitBody(n);
1792
1793                /*
1794                 * Write end tag
1795                 */

1796                out.printin("out.write(\"</");
1797                out.print(n.getQName());
1798                out.println(">\");");
1799            } else {
1800                out.println("/>\");");
1801            }
1802
1803            n.setEndJavaLine(out.getJavaLine());
1804        }
1805
1806        public void visit(Node.JspElement n) throws JasperException {
1807
1808            n.setBeginJavaLine(out.getJavaLine());
1809
1810            // Compute attribute value string for XML-style and named
1811
// attributes
1812
Hashtable JavaDoc map = new Hashtable JavaDoc();
1813            Node.JspAttribute[] attrs = n.getJspAttributes();
1814            for (int i = 0; attrs != null && i < attrs.length; i++) {
1815                String JavaDoc attrStr = null;
1816                if (attrs[i].isNamedAttribute()) {
1817                    attrStr = generateNamedAttributeValue(attrs[i]
1818                            .getNamedAttributeNode());
1819                } else {
1820                    attrStr = attributeValue(attrs[i], false, Object JavaDoc.class);
1821                }
1822                String JavaDoc s = " + \" " + attrs[i].getName() + "=\\\"\" + "
1823                        + attrStr + " + \"\\\"\"";
1824                map.put(attrs[i].getName(), s);
1825            }
1826
1827            // Write begin tag, using XML-style 'name' attribute as the
1828
// element name
1829
String JavaDoc elemName = attributeValue(n.getNameAttribute(), false,
1830                    String JavaDoc.class);
1831            out.printin("out.write(\"<\"");
1832            out.print(" + " + elemName);
1833
1834            // Write remaining attributes
1835
Enumeration JavaDoc enumeration = map.keys();
1836            while (enumeration.hasMoreElements()) {
1837                String JavaDoc attrName = (String JavaDoc) enumeration.nextElement();
1838                out.print((String JavaDoc) map.get(attrName));
1839            }
1840
1841            // Does the <jsp:element> have nested tags other than
1842
// <jsp:attribute>
1843
boolean hasBody = false;
1844            Node.Nodes subelements = n.getBody();
1845            if (subelements != null) {
1846                for (int i = 0; i < subelements.size(); i++) {
1847                    Node subelem = subelements.getNode(i);
1848                    if (!(subelem instanceof Node.NamedAttribute)) {
1849                        hasBody = true;
1850                        break;
1851                    }
1852                }
1853            }
1854            if (hasBody) {
1855                out.println(" + \">\");");
1856
1857                // Smap should not include the body
1858
n.setEndJavaLine(out.getJavaLine());
1859
1860                // Visit tag body
1861
visitBody(n);
1862
1863                // Write end tag
1864
out.printin("out.write(\"</\"");
1865                out.print(" + " + elemName);
1866                out.println(" + \">\");");
1867            } else {
1868                out.println(" + \"/>\");");
1869                n.setEndJavaLine(out.getJavaLine());
1870            }
1871        }
1872
1873        public void visit(Node.TemplateText n) throws JasperException {
1874
1875            String JavaDoc text = n.getText();
1876
1877            int textSize = text.length();
1878            if (textSize == 0) {
1879                return;
1880            }
1881
1882            if (textSize <= 3) {
1883                // Special case small text strings
1884
n.setBeginJavaLine(out.getJavaLine());
1885                int lineInc = 0;
1886                for (int i = 0; i < textSize; i++) {
1887                    char ch = text.charAt(i);
1888                    out.printil("out.write(" + quote(ch) + ");");
1889                    if (i > 0) {
1890                        n.addSmap(lineInc);
1891                    }
1892                    if (ch == '\n') {
1893                        lineInc++;
1894                    }
1895                }
1896                n.setEndJavaLine(out.getJavaLine());
1897                return;
1898            }
1899
1900            if (ctxt.getOptions().genStringAsCharArray()) {
1901                // Generate Strings as char arrays, for performance
1902
ServletWriter caOut;
1903                if (charArrayBuffer == null) {
1904                    charArrayBuffer = new GenBuffer();
1905                    caOut = charArrayBuffer.getOut();
1906                    caOut.pushIndent();
1907                    textMap = new HashMap JavaDoc();
1908                } else {
1909                    caOut = charArrayBuffer.getOut();
1910                }
1911                String JavaDoc charArrayName = (String JavaDoc) textMap.get(text);
1912                if (charArrayName == null) {
1913                    charArrayName = "_jspx_char_array_" + charArrayCount++;
1914                    textMap.put(text, charArrayName);
1915                    caOut.printin("static char[] ");
1916                    caOut.print(charArrayName);
1917                    caOut.print(" = ");
1918                    caOut.print(quote(text));
1919                    caOut.println(".toCharArray();");
1920                }
1921
1922                n.setBeginJavaLine(out.getJavaLine());
1923                out.printil("out.write(" + charArrayName + ");");
1924                n.setEndJavaLine(out.getJavaLine());
1925                return;
1926            }
1927
1928            n.setBeginJavaLine(out.getJavaLine());
1929
1930            out.printin();
1931            StringBuffer JavaDoc sb = new StringBuffer JavaDoc("out.write(\"");
1932            int initLength = sb.length();
1933            int count = JspUtil.CHUNKSIZE;
1934            int srcLine = 0; // relative to starting srouce line
1935
for (int i = 0; i < text.length(); i++) {
1936                char ch = text.charAt(i);
1937                --count;
1938                switch (ch) {
1939                case '"':
1940                    sb.append('\\').append('\"');
1941                    break;
1942                case '\\':
1943                    sb.append('\\').append('\\');
1944                    break;
1945                case '\r':
1946                    sb.append('\\').append('r');
1947                    break;
1948                case '\n':
1949                    sb.append('\\').append('n');
1950                    srcLine++;
1951
1952                    if (breakAtLF || count < 0) {
1953                        // Generate an out.write() when see a '\n' in template
1954
sb.append("\");");
1955                        out.println(sb.toString());
1956                        if (i < text.length() - 1) {
1957                            out.printin();
1958                        }
1959                        sb.setLength(initLength);
1960                        count = JspUtil.CHUNKSIZE;
1961                    }
1962                    // add a Smap for this line
1963
n.addSmap(srcLine);
1964                    break;
1965                case '\t': // Not sure we need this
1966
sb.append('\\').append('t');
1967                    break;
1968                default:
1969                    sb.append(ch);
1970                }
1971            }
1972
1973            if (sb.length() > initLength) {
1974                sb.append("\");");
1975                out.println(sb.toString());
1976            }
1977
1978            n.setEndJavaLine(out.getJavaLine());
1979        }
1980
1981        public void visit(Node.JspBody n) throws JasperException {
1982            if (n.getBody() != null) {
1983                if (isSimpleTagHandler) {
1984                    out.printin(simpleTagHandlerVar);
1985                    out.print(".setJspBody(");
1986                    generateJspFragment(n, simpleTagHandlerVar);
1987                    out.println(");");
1988                } else {
1989                    visitBody(n);
1990                }
1991            }
1992        }
1993
1994        public void visit(Node.InvokeAction n) throws JasperException {
1995
1996            n.setBeginJavaLine(out.getJavaLine());
1997
1998            // Copy virtual page scope of tag file to page scope of invoking
1999
// page
2000
out.printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();");
2001            String JavaDoc varReaderAttr = n.getTextAttribute("varReader");
2002            String JavaDoc varAttr = n.getTextAttribute("var");
2003            if (varReaderAttr != null || varAttr != null) {
2004                out.printil("_jspx_sout = new java.io.StringWriter();");
2005            } else {
2006                out.printil("_jspx_sout = null;");
2007            }
2008
2009            // Invoke fragment, unless fragment is null
2010
out.printin("if (");
2011            out.print(toGetterMethod(n.getTextAttribute("fragment")));
2012            out.println(" != null) {");
2013            out.pushIndent();
2014            out.printin(toGetterMethod(n.getTextAttribute("fragment")));
2015            out.println(".invoke(_jspx_sout);");
2016            out.popIndent();
2017            out.printil("}");
2018
2019            // Store varReader in appropriate scope
2020
if (varReaderAttr != null || varAttr != null) {
2021                String JavaDoc scopeName = n.getTextAttribute("scope");
2022                out.printin("_jspx_page_context.setAttribute(");
2023                if (varReaderAttr != null) {
2024                    out.print(quote(varReaderAttr));
2025                    out.print(", new java.io.StringReader(_jspx_sout.toString())");
2026                } else {
2027                    out.print(quote(varAttr));
2028                    out.print(", _jspx_sout.toString()");
2029                }
2030                if (scopeName != null) {
2031                    out.print(", ");
2032                    out.print(getScopeConstant(scopeName));
2033                }
2034                out.println(");");
2035            }
2036
2037            // Restore EL context
2038
out.printil("jspContext.getELContext().putContext(JspContext.class,getJspContext());");
2039
2040            n.setEndJavaLine(out.getJavaLine());
2041        }
2042
2043        public void visit(Node.DoBodyAction n) throws JasperException {
2044
2045            n.setBeginJavaLine(out.getJavaLine());
2046
2047            // Copy virtual page scope of tag file to page scope of invoking
2048
// page
2049
out.printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();");
2050
2051            // Invoke body
2052
String JavaDoc varReaderAttr = n.getTextAttribute("varReader");
2053            String JavaDoc varAttr = n.getTextAttribute("var");
2054            if (varReaderAttr != null || varAttr != null) {
2055                out.printil("_jspx_sout = new java.io.StringWriter();");
2056            } else {
2057                out.printil("_jspx_sout = null;");
2058            }
2059            out.printil("if (getJspBody() != null)");
2060            out.pushIndent();
2061            out.printil("getJspBody().invoke(_jspx_sout);");
2062            out.popIndent();
2063
2064            // Store varReader in appropriate scope
2065
if (varReaderAttr != null || varAttr != null) {
2066                String JavaDoc scopeName = n.getTextAttribute("scope");
2067                out.printin("_jspx_page_context.setAttribute(");
2068                if (varReaderAttr != null) {
2069                    out.print(quote(varReaderAttr));
2070                    out
2071                            .print(", new java.io.StringReader(_jspx_sout.toString())");
2072                } else {
2073                    out.print(quote(varAttr));
2074                    out.print(", _jspx_sout.toString()");
2075                }
2076                if (scopeName != null) {
2077                    out.print(", ");
2078                    out.print(getScopeConstant(scopeName));
2079                }
2080                out.println(");");
2081            }
2082
2083            // Restore EL context
2084
out.printil("jspContext.getELContext().putContext(JspContext.class,getJspContext());");
2085
2086            n.setEndJavaLine(out.getJavaLine());
2087        }
2088
2089        public void visit(Node.AttributeGenerator n) throws JasperException {
2090            Node.CustomTag tag = n.getTag();
2091            Node.JspAttribute[] attrs = tag.getJspAttributes();
2092            for (int i = 0; attrs != null && i < attrs.length; i++) {
2093                if (attrs[i].getName().equals(n.getName())) {
2094                    out.print(evaluateAttribute(getTagHandlerInfo(tag),
2095                            attrs[i], tag, null));
2096                    break;
2097                }
2098            }
2099        }
2100
2101        private TagHandlerInfo getTagHandlerInfo(Node.CustomTag n)
2102                throws JasperException {
2103            Hashtable JavaDoc handlerInfosByShortName = (Hashtable JavaDoc) handlerInfos.get(n
2104                    .getPrefix());
2105            if (handlerInfosByShortName == null) {
2106                handlerInfosByShortName = new Hashtable JavaDoc();
2107                handlerInfos.put(n.getPrefix(), handlerInfosByShortName);
2108            }
2109            TagHandlerInfo handlerInfo = (TagHandlerInfo) handlerInfosByShortName
2110                    .get(n.getLocalName());
2111            if (handlerInfo == null) {
2112                handlerInfo = new TagHandlerInfo(n, n.getTagHandlerClass(), err);
2113                handlerInfosByShortName.put(n.getLocalName(), handlerInfo);
2114            }
2115            return handlerInfo;
2116        }
2117
2118        private void generateTagPlugin(Node.CustomTag n) throws JasperException {
2119            if (n.getAtSTag() != null) {
2120                n.getAtSTag().visit(this);
2121            }
2122            visitBody(n);
2123            if (n.getAtETag() != null) {
2124                n.getAtETag().visit(this);
2125            }
2126        }
2127
2128        private void generateCustomStart(Node.CustomTag n,
2129                TagHandlerInfo handlerInfo, String JavaDoc tagHandlerVar,
2130                String JavaDoc tagEvalVar, String JavaDoc tagPushBodyCountVar)
2131                throws JasperException {
2132
2133            Class JavaDoc tagHandlerClass = handlerInfo.getTagHandlerClass();
2134
2135            out.printin("// ");
2136            out.println(n.getQName());
2137            n.setBeginJavaLine(out.getJavaLine());
2138
2139            // Declare AT_BEGIN scripting variables
2140
declareScriptingVars(n, VariableInfo.AT_BEGIN);
2141            saveScriptingVars(n, VariableInfo.AT_BEGIN);
2142
2143            String JavaDoc tagHandlerClassName = JspUtil
2144                    .getCanonicalName(tagHandlerClass);
2145            out.printin(tagHandlerClassName);
2146            out.print(" ");
2147            out.print(tagHandlerVar);
2148            out.print(" = ");
2149            if (isPoolingEnabled && !(n.implementsJspIdConsumer())) {
2150                out.print("(");
2151                out.print(tagHandlerClassName);
2152                out.print(") ");
2153                out.print(n.getTagHandlerPoolName());
2154                out.print(".get(");
2155                out.print(tagHandlerClassName);
2156                out.println(".class);");
2157            } else {
2158                out.print("new ");
2159                out.print(tagHandlerClassName);
2160                out.println("();");
2161                out.printin("org.apache.jasper.runtime.AnnotationHelper.postConstruct(");
2162                out.print(VAR_ANNOTATIONPROCESSOR);
2163                out.print(", ");
2164                out.print(tagHandlerVar);
2165                out.println(");");
2166            }
2167
2168            // includes setting the context
2169
generateSetters(n, tagHandlerVar, handlerInfo, false);
2170
2171            // JspIdConsumer (after context has been set)
2172
if (n.implementsJspIdConsumer()) {
2173                out.printin(tagHandlerVar);
2174                out.print(".setJspId(\"");
2175                out.print(createJspId());
2176                out.println("\");");
2177            }
2178
2179            if (n.implementsTryCatchFinally()) {
2180                out.printin("int[] ");
2181                out.print(tagPushBodyCountVar);
2182                out.println(" = new int[] { 0 };");
2183                out.printil("try {");
2184                out.pushIndent();
2185            }
2186            out.printin("int ");
2187            out.print(tagEvalVar);
2188            out.print(" = ");
2189            out.print(tagHandlerVar);
2190            out.println(".doStartTag();");
2191
2192            if (!n.implementsBodyTag()) {
2193                // Synchronize AT_BEGIN scripting variables
2194
syncScriptingVars(n, VariableInfo.AT_BEGIN);
2195            }
2196
2197            if (!n.hasEmptyBody()) {
2198                out.printin("if (");
2199                out.print(tagEvalVar);
2200                out.println(" != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {");
2201                out.pushIndent();
2202
2203                // Declare NESTED scripting variables
2204
declareScriptingVars(n, VariableInfo.NESTED);
2205                saveScriptingVars(n, VariableInfo.NESTED);
2206
2207                if (n.implementsBodyTag()) {
2208                    out.printin("if (");
2209                    out.print(tagEvalVar);
2210                    out
2211                            .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {");
2212                    // Assume EVAL_BODY_BUFFERED
2213
out.pushIndent();
2214                    out.printil("out = _jspx_page_context.pushBody();");
2215                    if (n.implementsTryCatchFinally()) {
2216                        out.printin(tagPushBodyCountVar);
2217                        out.println("[0]++;");
2218                    } else if (pushBodyCountVar != null) {
2219                        out.printin(pushBodyCountVar);
2220                        out.println("[0]++;");
2221                    }
2222                    out.printin(tagHandlerVar);
2223                    out
2224                            .println(".setBodyContent((javax.servlet.jsp.tagext.BodyContent) out);");
2225                    out.printin(tagHandlerVar);
2226                    out.println(".doInitBody();");
2227
2228                    out.popIndent();
2229                    out.printil("}");
2230
2231                    // Synchronize AT_BEGIN and NESTED scripting variables
2232
syncScriptingVars(n, VariableInfo.AT_BEGIN);
2233                    syncScriptingVars(n, VariableInfo.NESTED);
2234
2235                } else {
2236                    // Synchronize NESTED scripting variables
2237
syncScriptingVars(n, VariableInfo.NESTED);
2238                }
2239
2240                if (n.implementsIterationTag()) {
2241                    out.printil("do {");
2242                    out.pushIndent();
2243                }
2244            }
2245            // Map the Java lines that handles start of custom tags to the
2246
// JSP line for this tag
2247
n.setEndJavaLine(out.getJavaLine());
2248        }
2249
2250        private void generateCustomEnd(Node.CustomTag n, String JavaDoc tagHandlerVar,
2251                String JavaDoc tagEvalVar, String JavaDoc tagPushBodyCountVar) {
2252
2253            if (!n.hasEmptyBody()) {
2254                if (n.implementsIterationTag()) {
2255                    out.printin("int evalDoAfterBody = ");
2256                    out.print(tagHandlerVar);
2257                    out.println(".doAfterBody();");
2258
2259                    // Synchronize AT_BEGIN and NESTED scripting variables
2260
syncScriptingVars(n, VariableInfo.AT_BEGIN);
2261                    syncScriptingVars(n, VariableInfo.NESTED);
2262
2263                    out
2264                            .printil("if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)");
2265                    out.pushIndent();
2266                    out.printil("break;");
2267                    out.popIndent();
2268
2269                    out.popIndent();
2270                    out.printil("} while (true);");
2271                }
2272
2273                restoreScriptingVars(n, VariableInfo.NESTED);
2274
2275                if (n.implementsBodyTag()) {
2276                    out.printin("if (");
2277                    out.print(tagEvalVar);
2278                    out
2279                            .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {");
2280                    out.pushIndent();
2281                    out.printil("out = _jspx_page_context.popBody();");
2282                    if (n.implementsTryCatchFinally()) {
2283                        out.printin(tagPushBodyCountVar);
2284                        out.println("[0]--;");
2285                    } else if (pushBodyCountVar != null) {
2286                        out.printin(pushBodyCountVar);
2287                        out.println("[0]--;");
2288                    }
2289                    out.popIndent();
2290                    out.printil("}");
2291                }
2292
2293                out.popIndent(); // EVAL_BODY
2294
out.printil("}");
2295            }
2296
2297            out.printin("if (");
2298            out.print(tagHandlerVar);
2299            out
2300                    .println(".doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {");
2301            out.pushIndent();
2302            if (!n.implementsTryCatchFinally()) {
2303                if (isPoolingEnabled && !(n.implementsJspIdConsumer())) {
2304                    out.printin(n.getTagHandlerPoolName());
2305                    out.print(".reuse(");
2306                    out.print(tagHandlerVar);
2307                    out.println(");");
2308                } else {
2309                    out.printin(tagHandlerVar);
2310                    out.println(".release();");
2311                    out.printil("try {");
2312                    out.pushIndent();
2313                    out.printin("org.apache.jasper.runtime.AnnotationHelper.preDestroy(");
2314                    out.print(VAR_ANNOTATIONPROCESSOR);
2315                    out.print(", ");
2316                    out.print(tagHandlerVar);
2317                    out.println(");");
2318                    out.popIndent();
2319                    out.printil("} catch (Exception e) {");
2320                    out.pushIndent();
2321                    out.printin("log(\"Error processing preDestroy on tag instance of \" +");
2322                    out.print(tagHandlerVar);
2323                    out.println(".getClass().getName());");
2324                    out.popIndent();
2325                    out.printil("}");
2326                }
2327            }
2328            if (isTagFile || isFragment) {
2329                out.printil("throw new SkipPageException();");
2330            } else {
2331                out.printil((methodNesting > 0) ? "return true;" : "return;");
2332            }
2333            out.popIndent();
2334            out.printil("}");
2335            // Synchronize AT_BEGIN scripting variables
2336
syncScriptingVars(n, VariableInfo.AT_BEGIN);
2337
2338            // TryCatchFinally
2339
if (n.implementsTryCatchFinally()) {
2340                out.popIndent(); // try
2341
out.printil("} catch (Throwable _jspx_exception) {");
2342                out.pushIndent();
2343
2344                out.printin("while (");
2345                out.print(tagPushBodyCountVar);
2346                out.println("[0]-- > 0)");
2347                out.pushIndent();
2348                out.printil("out = _jspx_page_context.popBody();");
2349                out.popIndent();
2350
2351                out.printin(tagHandlerVar);
2352                out.println(".doCatch(_jspx_exception);");
2353                out.popIndent();
2354                out.printil("} finally {");
2355                out.pushIndent();
2356                out.printin(tagHandlerVar);
2357                out.println(".doFinally();");
2358            }
2359
2360            if (isPoolingEnabled) {
2361                out.printin(n.getTagHandlerPoolName());
2362                out.print(".reuse(");
2363                out.print(tagHandlerVar);
2364                out.println(");");
2365            } else {
2366                out.printin(tagHandlerVar);
2367                out.println(".release();");
2368                out.printil("try {");
2369                out.pushIndent();
2370                out.printin("org.apache.jasper.runtime.AnnotationHelper.preDestroy(");
2371                out.print(VAR_ANNOTATIONPROCESSOR);
2372                out.print(", ");
2373                out.print(tagHandlerVar);
2374                out.println(");");
2375                out.popIndent();
2376                out.printil("} catch (Exception e) {");
2377                out.pushIndent();
2378                out.printin("log(\"Error processing preDestroy on tag instance of \" +");
2379                out.print(tagHandlerVar);
2380                out.println(".getClass().getName());");
2381                out.popIndent();
2382                out.printil("}");
2383            }
2384
2385            if (n.implementsTryCatchFinally()) {
2386                out.popIndent();
2387                out.printil("}");
2388            }
2389
2390            // Declare and synchronize AT_END scripting variables (must do this
2391
// outside the try/catch/finally block)
2392
declareScriptingVars(n, VariableInfo.AT_END);
2393            syncScriptingVars(n, VariableInfo.AT_END);
2394
2395            restoreScriptingVars(n, VariableInfo.AT_BEGIN);
2396        }
2397
2398        private void generateCustomDoTag(Node.CustomTag n,
2399                TagHandlerInfo handlerInfo, String JavaDoc tagHandlerVar)
2400                throws JasperException {
2401
2402            Class JavaDoc tagHandlerClass = handlerInfo.getTagHandlerClass();
2403
2404            n.setBeginJavaLine(out.getJavaLine());
2405            out.printin("// ");
2406            out.println(n.getQName());
2407
2408            // Declare AT_BEGIN scripting variables
2409
declareScriptingVars(n, VariableInfo.AT_BEGIN);
2410            saveScriptingVars(n, VariableInfo.AT_BEGIN);
2411
2412            String JavaDoc tagHandlerClassName = JspUtil
2413                    .getCanonicalName(tagHandlerClass);
2414            out.printin(tagHandlerClassName);
2415            out.print(" ");
2416            out.print(tagHandlerVar);
2417            out.print(" = ");
2418            out.print("new ");
2419            out.print(tagHandlerClassName);
2420            out.println("();");
2421
2422            // Resource injection
2423
out.printin("org.apache.jasper.runtime.AnnotationHelper.postConstruct(");
2424            out.print(VAR_ANNOTATIONPROCESSOR);
2425            out.print(", ");
2426            out.print(tagHandlerVar);
2427            out.println(");");
2428            
2429            generateSetters(n, tagHandlerVar, handlerInfo, true);
2430
2431            // JspIdConsumer (after context has been set)
2432
if (n.implementsJspIdConsumer()) {
2433                out.printin(tagHandlerVar);
2434                out.print(".setJspId(\"");
2435                out.print(createJspId());
2436                out.println("\");");
2437            }
2438
2439            // Set the body
2440
if (findJspBody(n) == null) {
2441                /*
2442                 * Encapsulate body of custom tag invocation in JspFragment and
2443                 * pass it to tag handler's setJspBody(), unless tag body is
2444                 * empty
2445                 */

2446                if (!n.hasEmptyBody()) {
2447                    out.printin(tagHandlerVar);
2448                    out.print(".setJspBody(");
2449                    generateJspFragment(n, tagHandlerVar);
2450                    out.println(");");
2451                }
2452            } else {
2453                /*
2454                 * Body of tag is the body of the <jsp:body> element. The visit
2455                 * method for that element is going to encapsulate that
2456                 * element's body in a JspFragment and pass it to the tag
2457                 * handler's setJspBody()
2458                 */

2459                String JavaDoc tmpTagHandlerVar = simpleTagHandlerVar;
2460                simpleTagHandlerVar = tagHandlerVar;
2461                boolean tmpIsSimpleTagHandler = isSimpleTagHandler;
2462                isSimpleTagHandler = true;
2463                visitBody(n);
2464                simpleTagHandlerVar = tmpTagHandlerVar;
2465                isSimpleTagHandler = tmpIsSimpleTagHandler;
2466            }
2467
2468            out.printin(tagHandlerVar);
2469            out.println(".doTag();");
2470
2471            restoreScriptingVars(n, VariableInfo.AT_BEGIN);
2472
2473            // Synchronize AT_BEGIN scripting variables
2474
syncScriptingVars(n, VariableInfo.AT_BEGIN);
2475
2476            // Declare and synchronize AT_END scripting variables
2477
declareScriptingVars(n, VariableInfo.AT_END);
2478            syncScriptingVars(n, VariableInfo.AT_END);
2479
2480            // Resource injection
2481
out.printin("org.apache.jasper.runtime.AnnotationHelper.preDestroy(");
2482            out.print(VAR_ANNOTATIONPROCESSOR);
2483            out.print(", ");
2484            out.print(tagHandlerVar);
2485            out.println(");");
2486
2487            n.setEndJavaLine(out.getJavaLine());
2488        }
2489
2490        private void declareScriptingVars(Node.CustomTag n, int scope) {
2491
2492            Vector JavaDoc vec = n.getScriptingVars(scope);
2493            if (vec != null) {
2494                for (int i = 0; i < vec.size(); i++) {
2495                    Object JavaDoc elem = vec.elementAt(i);
2496                    if (elem instanceof VariableInfo JavaDoc) {
2497                        VariableInfo JavaDoc varInfo = (VariableInfo JavaDoc) elem;
2498                        if (varInfo.getDeclare()) {
2499                            out.printin(varInfo.getClassName());
2500                            out.print(" ");
2501                            out.print(varInfo.getVarName());
2502                            out.println(" = null;");
2503                        }
2504                    } else {
2505                        TagVariableInfo JavaDoc tagVarInfo = (TagVariableInfo JavaDoc) elem;
2506                        if (tagVarInfo.getDeclare()) {
2507                            String JavaDoc varName = tagVarInfo.getNameGiven();
2508                            if (varName == null) {
2509                                varName = n.getTagData().getAttributeString(
2510                                        tagVarInfo.getNameFromAttribute());
2511                            } else if (tagVarInfo.getNameFromAttribute() != null) {
2512                                // alias
2513
continue;
2514                            }
2515                            out.printin(tagVarInfo.getClassName());
2516                            out.print(" ");
2517                            out.print(varName);
2518                            out.println(" = null;");
2519                        }
2520                    }
2521                }
2522            }
2523        }
2524
2525        /*
2526         * This method is called as part of the custom tag's start element.
2527         *
2528         * If the given custom tag has a custom nesting level greater than 0,
2529         * save the current values of its scripting variables to temporary
2530         * variables, so those values may be restored in the tag's end element.
2531         * This way, the scripting variables may be synchronized by the given
2532         * tag without affecting their original values.
2533         */

2534        private void saveScriptingVars(Node.CustomTag n, int scope) {
2535            if (n.getCustomNestingLevel() == 0) {
2536                return;
2537            }
2538
2539            TagVariableInfo JavaDoc[] tagVarInfos = n.getTagVariableInfos();
2540            VariableInfo JavaDoc[] varInfos = n.getVariableInfos();
2541            if ((varInfos.length == 0) && (tagVarInfos.length == 0)) {
2542                return;
2543            }
2544
2545            if (varInfos.length > 0) {
2546                for (int i = 0; i < varInfos.length; i++) {
2547                    if (varInfos[i].getScope() != scope)
2548                        continue;
2549                    // If the scripting variable has been declared, skip codes
2550
// for saving and restoring it.
2551
if (n.getScriptingVars(scope).contains(varInfos[i]))
2552                        continue;
2553                    String JavaDoc varName = varInfos[i].getVarName();
2554                    String JavaDoc tmpVarName = "_jspx_" + varName + "_"
2555                            + n.getCustomNestingLevel();
2556                    out.printin(tmpVarName);
2557                    out.print(" = ");
2558                    out.print(varName);
2559                    out.println(";");
2560                }
2561            } else {
2562                for (int i = 0; i < tagVarInfos.length; i++) {
2563                    if (tagVarInfos[i].getScope() != scope)
2564                        continue;
2565                    // If the scripting variable has been declared, skip codes
2566
// for saving and restoring it.
2567
if (n.getScriptingVars(scope).contains(tagVarInfos[i]))
2568                        continue;
2569                    String JavaDoc varName = tagVarInfos[i].getNameGiven();
2570                    if (varName == null) {
2571                        varName = n.getTagData().getAttributeString(
2572                                tagVarInfos[i].getNameFromAttribute());
2573                    } else if (tagVarInfos[i].getNameFromAttribute() != null) {
2574                        // alias
2575
continue;
2576                    }
2577                    String JavaDoc tmpVarName = "_jspx_" + varName + "_"
2578                            + n.getCustomNestingLevel();
2579                    out.printin(tmpVarName);
2580                    out.print(" = ");
2581                    out.print(varName);
2582                    out.println(";");
2583                }
2584            }
2585        }
2586
2587        /*
2588         * This method is called as part of the custom tag's end element.
2589         *
2590         * If the given custom tag has a custom nesting level greater than 0,
2591         * restore its scripting variables to their original values that were
2592         * saved in the tag's start element.
2593         */

2594        private void restoreScriptingVars(Node.CustomTag n, int scope) {
2595            if (n.getCustomNestingLevel() == 0) {
2596                return;
2597            }
2598
2599            TagVariableInfo JavaDoc[] tagVarInfos = n.getTagVariableInfos();
2600            VariableInfo JavaDoc[] varInfos = n.getVariableInfos();
2601            if ((varInfos.length == 0) && (tagVarInfos.length == 0)) {
2602                return;
2603            }
2604
2605            if (varInfos.length > 0) {
2606                for (int i = 0; i < varInfos.length; i++) {
2607                    if (varInfos[i].getScope() != scope)
2608                        continue;
2609                    // If the scripting variable has been declared, skip codes
2610
// for saving and restoring it.
2611
if (n.getScriptingVars(scope).contains(varInfos[i]))
2612                        continue;
2613                    String JavaDoc varName = varInfos[i].getVarName();
2614                    String JavaDoc tmpVarName = "_jspx_" + varName + "_"
2615                            + n.getCustomNestingLevel();
2616                    out.printin(varName);
2617                    out.print(" = ");
2618                    out.print(tmpVarName);
2619                    out.println(";");
2620                }
2621            } else {
2622                for (int i = 0; i < tagVarInfos.length; i++) {
2623                    if (tagVarInfos[i].getScope() != scope)
2624                        continue;
2625                    // If the scripting variable has been declared, skip codes
2626
// for saving and restoring it.
2627
if (n.getScriptingVars(scope).contains(tagVarInfos[i]))
2628                        continue;
2629                    String JavaDoc varName = tagVarInfos[i].getNameGiven();
2630                    if (varName == null) {
2631                        varName = n.getTagData().getAttributeString(
2632                                tagVarInfos[i].getNameFromAttribute());
2633                    } else if (tagVarInfos[i].getNameFromAttribute() != null) {
2634                        // alias
2635
continue;
2636                    }
2637                    String JavaDoc tmpVarName = "_jspx_" + varName + "_"
2638                            + n.getCustomNestingLevel();
2639                    out.printin(varName);
2640                    out.print(" = ");
2641                    out.print(tmpVarName);
2642                    out.println(";");
2643                }
2644            }
2645        }
2646
2647        /*
2648         * Synchronizes the scripting variables of the given custom tag for the
2649         * given scope.
2650         */

2651        private void syncScriptingVars(Node.CustomTag n, int scope) {
2652            TagVariableInfo JavaDoc[] tagVarInfos = n.getTagVariableInfos();
2653            VariableInfo JavaDoc[] varInfos = n.getVariableInfos();
2654
2655            if ((varInfos.length == 0) && (tagVarInfos.length == 0)) {
2656                return;
2657            }
2658
2659            if (varInfos.length > 0) {
2660                for (int i = 0; i < varInfos.length; i++) {
2661                    if (varInfos[i].getScope() == scope) {
2662                        out.printin(varInfos[i].getVarName());
2663                        out.print(" = (");
2664                        out.print(varInfos[i].getClassName());
2665                        out.print(") _jspx_page_context.findAttribute(");
2666                        out.print(quote(varInfos[i].getVarName()));
2667                        out.println(");");
2668                    }
2669                }
2670            } else {
2671                for (int i = 0; i < tagVarInfos.length; i++) {
2672                    if (tagVarInfos[i].getScope() == scope) {
2673                        String JavaDoc name = tagVarInfos[i].getNameGiven();
2674                        if (name == null) {
2675                            name = n.getTagData().getAttributeString(
2676                                    tagVarInfos[i].getNameFromAttribute());
2677                        } else if (tagVarInfos[i].getNameFromAttribute() != null) {
2678                            // alias
2679
continue;
2680                        }
2681                        out.printin(name);
2682                        out.print(" = (");
2683                        out.print(tagVarInfos[i].getClassName());
2684                        out.print(") _jspx_page_context.findAttribute(");
2685                        out.print(quote(name));
2686                        out.println(");");
2687                    }
2688                }
2689            }
2690        }
2691
2692        private String JavaDoc getJspContextVar() {
2693            if (this.isTagFile) {
2694                return "this.getJspContext()";
2695            } else {
2696                return "_jspx_page_context";
2697            }
2698        }
2699
2700        private String JavaDoc getExpressionFactoryVar() {
2701            return VAR_EXPRESSIONFACTORY;
2702        }
2703
2704        /*
2705         * Creates a tag variable name by concatenating the given prefix and
2706         * shortName and endcoded to make the resultant string a valid Java
2707         * Identifier.
2708         */

2709        private String JavaDoc createTagVarName(String JavaDoc fullName, String JavaDoc prefix,
2710                String JavaDoc shortName) {
2711
2712            String JavaDoc varName;
2713            synchronized (tagVarNumbers) {
2714                varName = prefix + "_" + shortName + "_";
2715                if (tagVarNumbers.get(fullName) != null) {
2716                    Integer JavaDoc i = (Integer JavaDoc) tagVarNumbers.get(fullName);
2717                    varName = varName + i.intValue();
2718                    tagVarNumbers.put(fullName, new Integer JavaDoc(i.intValue() + 1));
2719                } else {
2720                    tagVarNumbers.put(fullName, new Integer JavaDoc(1));
2721                    varName = varName + "0";
2722                }
2723            }
2724            return JspUtil.makeJavaIdentifier(varName);
2725        }
2726
2727        private String JavaDoc evaluateAttribute(TagHandlerInfo handlerInfo,
2728                Node.JspAttribute attr, Node.CustomTag n, String JavaDoc tagHandlerVar)
2729                throws JasperException {
2730
2731            String JavaDoc attrValue = attr.getValue();
2732            if (attrValue == null) {
2733                if (attr.isNamedAttribute()) {
2734                    if (n.checkIfAttributeIsJspFragment(attr.getName())) {
2735                        // XXX - no need to generate temporary variable here
2736
attrValue = generateNamedAttributeJspFragment(attr
2737                                .getNamedAttributeNode(), tagHandlerVar);
2738                    } else {
2739                        attrValue = generateNamedAttributeValue(attr
2740                                .getNamedAttributeNode());
2741                    }
2742                } else {
2743                    return null;
2744                }
2745            }
2746
2747            String JavaDoc localName = attr.getLocalName();
2748
2749            Method JavaDoc m = null;
2750            Class JavaDoc[] c = null;
2751            if (attr.isDynamic()) {
2752                c = OBJECT_CLASS;
2753            } else {
2754                m = handlerInfo.getSetterMethod(localName);
2755                if (m == null) {
2756                    err.jspError(n, "jsp.error.unable.to_find_method", attr
2757                            .getName());
2758                }
2759                c = m.getParameterTypes();
2760                // XXX assert(c.length > 0)
2761
}
2762
2763            if (attr.isExpression()) {
2764                // Do nothing
2765
} else if (attr.isNamedAttribute()) {
2766                if (!n.checkIfAttributeIsJspFragment(attr.getName())
2767                        && !attr.isDynamic()) {
2768                    attrValue = convertString(c[0], attrValue, localName,
2769                            handlerInfo.getPropertyEditorClass(localName), true);
2770                }
2771            } else if (attr.isELInterpreterInput()) {
2772
2773                // results buffer
2774
StringBuffer JavaDoc sb = new StringBuffer JavaDoc(64);
2775
2776                TagAttributeInfo JavaDoc tai = attr.getTagAttributeInfo();
2777                String JavaDoc type = tai.getTypeName();
2778                String JavaDoc returnType = JspUtil.toJavaSourceTypeFromTld(attr
2779                        .getExpectedTypeName());
2780
2781                // generate elContext reference
2782
sb.append(getJspContextVar());
2783                sb.append(".getELContext()");
2784                String JavaDoc elContext = sb.toString();
2785                if (attr.getEL() != null && attr.getEL().getMapName() != null) {
2786                    sb.setLength(0);
2787                    sb.append("new org.apache.jasper.el.ELContextWrapper(");
2788                    sb.append(elContext);
2789                    sb.append(',');
2790                    sb.append(attr.getEL().getMapName());
2791                    sb.append(')');
2792                    elContext = sb.toString();
2793                }
2794
2795                // reset buffer
2796
sb.setLength(0);
2797                
2798                // create our mark
2799
sb.append(n.getStart().toString());
2800                sb.append(" '");
2801                sb.append(attrValue);
2802                sb.append('\'');
2803                String JavaDoc mark = sb.toString();
2804                
2805                // reset buffer
2806
sb.setLength(0);
2807
2808                // depending on type
2809
if (attr.isDeferredInput()
2810                        || ValueExpression.class.getName().equals(type)) {
2811                    sb.append("new org.apache.jasper.el.JspValueExpression(");
2812                    sb.append(quote(mark));
2813                    sb.append(',');
2814                    sb.append(getExpressionFactoryVar());
2815                    sb.append(".createValueExpression(");
2816                    if (attr.getEL() != null) { // optimize
2817
sb.append(elContext);
2818                        sb.append(',');
2819                    }
2820                    sb.append(quote(attrValue));
2821                    sb.append(',');
2822                    sb.append(returnType);
2823                    sb.append("))");
2824                    // should the expression be evaluated before passing to
2825
// the setter?
2826
boolean evaluate = false;
2827                    if (tai.canBeRequestTime()) {
2828                        evaluate = true; // JSP.2.3.2
2829
}
2830                    if (attr.isDeferredInput()) {
2831                        evaluate = false; // JSP.2.3.3
2832
}
2833                    if (attr.isDeferredInput() && tai.canBeRequestTime()) {
2834                        evaluate = !attrValue.contains("#{"); // JSP.2.3.5
2835
}
2836                    if (evaluate) {
2837                        sb.append(".getValue(");
2838                        sb.append(getJspContextVar());
2839                        sb.append(".getELContext()");
2840                        sb.append(")");
2841                    }
2842                    attrValue = sb.toString();
2843                } else if (attr.isDeferredMethodInput()
2844                        || MethodExpression.class.getName().equals(type)) {
2845                    sb.append("new org.apache.jasper.el.JspMethodExpression(");
2846                    sb.append(quote(mark));
2847                    sb.append(',');
2848                    sb.append(getExpressionFactoryVar());
2849                    sb.append(".createMethodExpression(");
2850                    sb.append(elContext);
2851                    sb.append(',');
2852                    sb.append(quote(attrValue));
2853                    sb.append(',');
2854                    sb.append(returnType);
2855                    sb.append(',');
2856                    sb.append("new Class[] {");
2857
2858                    String JavaDoc[] p = attr.getParameterTypeNames();
2859                    for (int i = 0; i < p.length; i++) {
2860                        sb.append(JspUtil.toJavaSourceTypeFromTld(p[i]));
2861                        sb.append(',');
2862                    }
2863                    if (p.length > 0) {
2864                        sb.setLength(sb.length() - 1);
2865                    }
2866
2867                    sb.append("}))");
2868                    attrValue = sb.toString();
2869                } else {
2870                    // run attrValue through the expression interpreter
2871
boolean replaceESC = attrValue.indexOf(Constants.ESC) > 0;
2872                    String JavaDoc mapName = (attr.getEL() != null) ? attr.getEL()
2873                            .getMapName() : null;
2874                    attrValue = JspUtil.interpreterCall(this.isTagFile,
2875                            attrValue, c[0], mapName, false);
2876                    // XXX hack: Replace ESC with '$'
2877
if (replaceESC) {
2878                        attrValue = "(" + attrValue + ").replace("
2879                                + Constants.ESCStr + ", '$')";
2880                    }
2881                }
2882            } else {
2883                attrValue = convertString(c[0], attrValue, localName,
2884                        handlerInfo.getPropertyEditorClass(localName), false);
2885            }
2886            return attrValue;
2887        }
2888
2889        /**
2890         * Generate code to create a map for the alias variables
2891         *
2892         * @return the name of the map
2893         */

2894        private String JavaDoc generateAliasMap(Node.CustomTag n, String JavaDoc tagHandlerVar)
2895                throws JasperException {
2896
2897            TagVariableInfo JavaDoc[] tagVars = n.getTagVariableInfos();
2898            String JavaDoc aliasMapVar = null;
2899
2900            boolean aliasSeen = false;
2901            for (int i = 0; i < tagVars.length; i++) {
2902
2903                String JavaDoc nameFrom = tagVars[i].getNameFromAttribute();
2904                if (nameFrom != null) {
2905                    String JavaDoc aliasedName = n.getAttributeValue(nameFrom);
2906                    if (aliasedName == null)
2907                        continue;
2908
2909                    if (!aliasSeen) {
2910                        out.printin("java.util.HashMap ");
2911                        aliasMapVar = tagHandlerVar + "_aliasMap";
2912                        out.print(aliasMapVar);
2913                        out.println(" = new java.util.HashMap();");
2914                        aliasSeen = true;
2915                    }
2916                    out.printin(aliasMapVar);
2917                    out.print(".put(");
2918                    out.print(quote(tagVars[i].getNameGiven()));
2919                    out.print(", ");
2920                    out.print(quote(aliasedName));
2921                    out.println(");");
2922                }
2923            }
2924            return aliasMapVar;
2925        }
2926
2927        private void generateSetters(Node.CustomTag n, String JavaDoc tagHandlerVar,
2928                TagHandlerInfo handlerInfo, boolean simpleTag)
2929                throws JasperException {
2930
2931            // Set context
2932
if (simpleTag) {
2933                // Generate alias map
2934
String JavaDoc aliasMapVar = null;
2935                if (n.isTagFile()) {
2936                    aliasMapVar = generateAliasMap(n, tagHandlerVar);
2937                }
2938                out.printin(tagHandlerVar);
2939                if (aliasMapVar == null) {
2940                    out.println(".setJspContext(_jspx_page_context);");
2941                } else {
2942                    out.print(".setJspContext(_jspx_page_context, ");
2943                    out.print(aliasMapVar);
2944                    out.println(");");
2945                }
2946            } else {
2947                out.printin(tagHandlerVar);
2948                out.println(".setPageContext(_jspx_page_context);");
2949            }
2950
2951            // Set parent
2952
if (isTagFile && parent == null) {
2953                out.printin(tagHandlerVar);
2954                out.print(".setParent(");
2955                out.print("new javax.servlet.jsp.tagext.TagAdapter(");
2956                out.print("(javax.servlet.jsp.tagext.SimpleTag) this ));");
2957            } else if (!simpleTag) {
2958                out.printin(tagHandlerVar);
2959                out.print(".setParent(");
2960                if (parent != null) {
2961                    if (isSimpleTagParent) {
2962                        out.print("new javax.servlet.jsp.tagext.TagAdapter(");
2963                        out.print("(javax.servlet.jsp.tagext.SimpleTag) ");
2964                        out.print(parent);
2965                        out.println("));");
2966                    } else {
2967                        out.print("(javax.servlet.jsp.tagext.Tag) ");
2968                        out.print(parent);
2969                        out.println(");");
2970                    }
2971                } else {
2972                    out.println("null);");
2973                }
2974            } else {
2975                // The setParent() method need not be called if the value being
2976
// passed is null, since SimpleTag instances are not reused
2977
if (parent != null) {
2978                    out.printin(tagHandlerVar);
2979                    out.print(".setParent(");
2980                    out.print(parent);
2981                    out.println(");");
2982                }
2983            }
2984
2985            // need to handle deferred values and methods
2986
Node.JspAttribute[] attrs = n.getJspAttributes();
2987            for (int i = 0; attrs != null && i < attrs.length; i++) {
2988                String JavaDoc attrValue = evaluateAttribute(handlerInfo, attrs[i], n,
2989                        tagHandlerVar);
2990                
2991                Mark m = n.getStart();
2992                out.printil("// "+m.getFile()+"("+m.getLineNumber()+","+m.getColumnNumber()+") "+ attrs[i].getTagAttributeInfo());
2993                if (attrs[i].isDynamic()) {
2994                    out.printin(tagHandlerVar);
2995                    out.print(".");
2996                    out.print("setDynamicAttribute(");
2997                    String JavaDoc uri = attrs[i].getURI();
2998                    if ("".equals(uri) || (uri == null)) {
2999                        out.print("null");
3000                    } else {
3001                        out.print("\"" + attrs[i].getURI() + "\"");
3002                    }
3003                    out.print(", \"");
3004                    out.print(attrs[i].getLocalName());
3005                    out.print("\", ");
3006                    out.print(attrValue);
3007                    out.println(");");
3008                } else {
3009                    out.printin(tagHandlerVar);
3010                    out.print(".");
3011                    out.print(handlerInfo.getSetterMethod(
3012                            attrs[i].getLocalName()).getName());
3013                    out.print("(");
3014                    out.print(attrValue);
3015                    out.println(");");
3016                }
3017            }
3018        }
3019
3020        /*
3021         * @param c The target class to which to coerce the given string @param
3022         * s The string value @param attrName The name of the attribute whose
3023         * value is being supplied @param propEditorClass The property editor
3024         * for the given attribute @param isNamedAttribute true if the given
3025         * attribute is a named attribute (that is, specified using the
3026         * jsp:attribute standard action), and false otherwise
3027         */

3028        private String JavaDoc convertString(Class JavaDoc c, String JavaDoc s, String JavaDoc attrName,
3029                Class JavaDoc propEditorClass, boolean isNamedAttribute)
3030                throws JasperException {
3031
3032            String JavaDoc quoted = s;
3033            if (!isNamedAttribute) {
3034                quoted = quote(s);
3035            }
3036
3037            if (propEditorClass != null) {
3038                String JavaDoc className = JspUtil.getCanonicalName(c);
3039                return "("
3040                        + className
3041                        + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromBeanInfoPropertyEditor("
3042                        + className + ".class, \"" + attrName + "\", " + quoted
3043                        + ", " + JspUtil.getCanonicalName(propEditorClass)
3044                        + ".class)";
3045            } else if (c == String JavaDoc.class) {
3046                return quoted;
3047            } else if (c == boolean.class) {
3048                return JspUtil.coerceToPrimitiveBoolean(s, isNamedAttribute);
3049            } else if (c == Boolean JavaDoc.class) {
3050                return JspUtil.coerceToBoolean(s, isNamedAttribute);
3051            } else if (c == byte.class) {
3052                return JspUtil.coerceToPrimitiveByte(s, isNamedAttribute);
3053            } else if (c == Byte JavaDoc.class) {
3054                return JspUtil.coerceToByte(s, isNamedAttribute);
3055            } else if (c == char.class) {
3056                return JspUtil.coerceToChar(s, isNamedAttribute);
3057            } else if (c == Character JavaDoc.class) {
3058                return JspUtil.coerceToCharacter(s, isNamedAttribute);
3059            } else if (c == double.class) {
3060                return JspUtil.coerceToPrimitiveDouble(s, isNamedAttribute);
3061            } else if (c == Double JavaDoc.class) {
3062                return JspUtil.coerceToDouble(s, isNamedAttribute);
3063            } else if (c == float.class) {
3064                return JspUtil.coerceToPrimitiveFloat(s, isNamedAttribute);
3065            } else if (c == Float JavaDoc.class) {
3066                return JspUtil.coerceToFloat(s, isNamedAttribute);
3067            } else if (c == int.class) {
3068                return JspUtil.coerceToInt(s, isNamedAttribute);
3069            } else if (c == Integer JavaDoc.class) {
3070                return JspUtil.coerceToInteger(s, isNamedAttribute);
3071            } else if (c == short.class) {
3072                return JspUtil.coerceToPrimitiveShort(s, isNamedAttribute);
3073            } else if (c == Short JavaDoc.class) {
3074                return JspUtil.coerceToShort(s, isNamedAttribute);
3075            } else if (c == long.class) {
3076                return JspUtil.coerceToPrimitiveLong(s, isNamedAttribute);
3077            } else if (c == Long JavaDoc.class) {
3078                return JspUtil.coerceToLong(s, isNamedAttribute);
3079            } else if (c == Object JavaDoc.class) {
3080                return "new String(" + quoted + ")";
3081            } else {
3082                String JavaDoc className = JspUtil.getCanonicalName(c);
3083                return "("
3084                        + className
3085                        + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromPropertyEditorManager("
3086                        + className + ".class, \"" + attrName + "\", " + quoted
3087                        + ")";
3088            }
3089        }
3090
3091        /*
3092         * Converts the scope string representation, whose possible values are
3093         * "page", "request", "session", and "application", to the corresponding
3094         * scope constant.
3095         */

3096        private String JavaDoc getScopeConstant(String JavaDoc scope) {
3097            String JavaDoc scopeName = "PageContext.PAGE_SCOPE"; // Default to page
3098

3099            if ("request".equals(scope)) {
3100                scopeName = "PageContext.REQUEST_SCOPE";
3101            } else if ("session".equals(scope)) {
3102                scopeName = "PageContext.SESSION_SCOPE";
3103            } else if ("application".equals(scope)) {
3104                scopeName = "PageContext.APPLICATION_SCOPE";
3105            }
3106
3107            return scopeName;
3108        }
3109
3110        /**
3111         * Generates anonymous JspFragment inner class which is passed as an
3112         * argument to SimpleTag.setJspBody().
3113         */

3114        private void generateJspFragment(Node n, String JavaDoc tagHandlerVar)
3115                throws JasperException {
3116            // XXX - A possible optimization here would be to check to see
3117
// if the only child of the parent node is TemplateText. If so,
3118
// we know there won't be any parameters, etc, so we can
3119
// generate a low-overhead JspFragment that just echoes its
3120
// body. The implementation of this fragment can come from
3121
// the org.apache.jasper.runtime package as a support class.
3122
FragmentHelperClass.Fragment fragment = fragmentHelperClass
3123                    .openFragment(n, tagHandlerVar, methodNesting);
3124            ServletWriter outSave = out;
3125            out = fragment.getGenBuffer().getOut();
3126            String JavaDoc tmpParent = parent;
3127            parent = "_jspx_parent";
3128            boolean isSimpleTagParentSave = isSimpleTagParent;
3129            isSimpleTagParent = true;
3130            boolean tmpIsFragment = isFragment;
3131            isFragment = true;
3132            String JavaDoc pushBodyCountVarSave = pushBodyCountVar;
3133            if (pushBodyCountVar != null) {
3134                // Use a fixed name for push body count, to simplify code gen
3135
pushBodyCountVar = "_jspx_push_body_count";
3136            }
3137            visitBody(n);
3138            out = outSave;
3139            parent = tmpParent;
3140            isSimpleTagParent = isSimpleTagParentSave;
3141            isFragment = tmpIsFragment;
3142            pushBodyCountVar = pushBodyCountVarSave;
3143            fragmentHelperClass.closeFragment(fragment, methodNesting);
3144            // XXX - Need to change pageContext to jspContext if
3145
// we're not in a place where pageContext is defined (e.g.
3146
// in a fragment or in a tag file.
3147
out.print("new " + fragmentHelperClass.getClassName() + "( "
3148                    + fragment.getId() + ", _jspx_page_context, "
3149                    + tagHandlerVar + ", " + pushBodyCountVar + ")");
3150        }
3151
3152        /**
3153         * Generate the code required to obtain the runtime value of the given
3154         * named attribute.
3155         *
3156         * @return The name of the temporary variable the result is stored in.
3157         */

3158        public String JavaDoc generateNamedAttributeValue(Node.NamedAttribute n)
3159                throws JasperException {
3160
3161            String JavaDoc varName = n.getTemporaryVariableName();
3162
3163            // If the only body element for this named attribute node is
3164
// template text, we need not generate an extra call to
3165
// pushBody and popBody. Maybe we can further optimize
3166
// here by getting rid of the temporary variable, but in
3167
// reality it looks like javac does this for us.
3168
Node.Nodes body = n.getBody();
3169            if (body != null) {
3170                boolean templateTextOptimization = false;
3171                if (body.size() == 1) {
3172                    Node bodyElement = body.getNode(0);
3173                    if (bodyElement instanceof Node.TemplateText) {
3174                        templateTextOptimization = true;
3175                        out.printil("String "
3176                                + varName
3177                                + " = "
3178                                + quote(new String JavaDoc(
3179                                        ((Node.TemplateText) bodyElement)
3180                                                .getText())) + ";");
3181                    }
3182                }
3183
3184                // XXX - Another possible optimization would be for
3185
// lone EL expressions (no need to pushBody here either).
3186

3187                if (!templateTextOptimization) {
3188                    out.printil("out = _jspx_page_context.pushBody();");
3189                    visitBody(n);
3190                    out.printil("String " + varName + " = "
3191                            + "((javax.servlet.jsp.tagext.BodyContent)"
3192                            + "out).getString();");
3193                    out.printil("out = _jspx_page_context.popBody();");
3194                }
3195            } else {
3196                // Empty body must be treated as ""
3197
out.printil("String " + varName + " = \"\";");
3198            }
3199
3200            return varName;
3201        }
3202
3203        /**
3204         * Similar to generateNamedAttributeValue, but create a JspFragment
3205         * instead.
3206         *
3207         * @param n
3208         * The parent node of the named attribute
3209         * @param tagHandlerVar
3210         * The variable the tag handler is stored in, so the fragment
3211         * knows its parent tag.
3212         * @return The name of the temporary variable the fragment is stored in.
3213         */

3214        public String JavaDoc generateNamedAttributeJspFragment(Node.NamedAttribute n,
3215                String JavaDoc tagHandlerVar) throws JasperException {
3216            String JavaDoc varName = n.getTemporaryVariableName();
3217
3218            out.printin("javax.servlet.jsp.tagext.JspFragment " + varName
3219                    + " = ");
3220            generateJspFragment(n, tagHandlerVar);
3221            out.println(";");
3222
3223            return varName;
3224        }
3225    }
3226
3227    private static void generateLocalVariables(ServletWriter out, Node n)
3228            throws JasperException {
3229        Node.ChildInfo ci;
3230        if (n instanceof Node.CustomTag) {
3231            ci = ((Node.CustomTag) n).getChildInfo();
3232        } else if (n instanceof Node.JspBody) {
3233            ci = ((Node.JspBody) n).getChildInfo();
3234        } else if (n instanceof Node.NamedAttribute) {
3235            ci = ((Node.NamedAttribute) n).getChildInfo();
3236        } else {
3237            // Cannot access err since this method is static, but at
3238
// least flag an error.
3239
throw new JasperException("Unexpected Node Type");
3240            // err.getString(
3241
// "jsp.error.internal.unexpected_node_type" ) );
3242
}
3243
3244        if (ci.hasUseBean()) {
3245            out
3246                    .printil("HttpSession session = _jspx_page_context.getSession();");
3247            out
3248                    .printil("ServletContext application = _jspx_page_context.getServletContext();");
3249        }
3250        if (ci.hasUseBean() || ci.hasIncludeAction() || ci.hasSetProperty()
3251                || ci.hasParamAction()) {
3252            out
3253                    .printil("HttpServletRequest request = (HttpServletRequest)_jspx_page_context.getRequest();");
3254        }
3255        if (ci.hasIncludeAction()) {
3256            out
3257                    .printil("HttpServletResponse response = (HttpServletResponse)_jspx_page_context.getResponse();");
3258        }
3259    }
3260
3261    /**
3262     * Common part of postamble, shared by both servlets and tag files.
3263     */

3264    private void genCommonPostamble() {
3265        // Append any methods that were generated in the buffer.
3266
for (int i = 0; i < methodsBuffered.size(); i++) {
3267            GenBuffer methodBuffer = (GenBuffer) methodsBuffered.get(i);
3268            methodBuffer.adjustJavaLines(out.getJavaLine() - 1);
3269            out.printMultiLn(methodBuffer.toString());
3270        }
3271
3272        // Append the helper class
3273
if (fragmentHelperClass.isUsed()) {
3274            fragmentHelperClass.generatePostamble();
3275            fragmentHelperClass.adjustJavaLines(out.getJavaLine() - 1);
3276            out.printMultiLn(fragmentHelperClass.toString());
3277        }
3278
3279        // Append char array declarations
3280
if (charArrayBuffer != null) {
3281            out.printMultiLn(charArrayBuffer.toString());
3282        }
3283
3284        // Close the class definition
3285
out.popIndent();
3286        out.printil("}");
3287    }
3288
3289    /**
3290     * Generates the ending part of the static portion of the servlet.
3291     */

3292    private void generatePostamble(Node.Nodes page) {
3293        out.popIndent();
3294        out.printil("} catch (Throwable t) {");
3295        out.pushIndent();
3296        out.printil("if (!(t instanceof SkipPageException)){");
3297        out.pushIndent();
3298        out.printil("out = _jspx_out;");
3299        out.printil("if (out != null && out.getBufferSize() != 0)");
3300        out.pushIndent();
3301        out.printil("try { out.clearBuffer(); } catch (java.io.IOException e) {}");
3302        out.popIndent();
3303
3304        out
3305                .printil("if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);");
3306        out.popIndent();
3307        out.printil("}");
3308        out.popIndent();
3309        out.printil("} finally {");
3310        out.pushIndent();
3311
3312        out
3313                .printil("if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);");
3314
3315        out.popIndent();
3316        out.printil("}");
3317
3318        // Close the service method
3319
out.popIndent();
3320        out.printil("}");
3321
3322        // Generated methods, helper classes, etc.
3323
genCommonPostamble();
3324    }
3325
3326    /**
3327     * Constructor.
3328     */

3329    Generator(ServletWriter out, Compiler JavaDoc compiler) {
3330        this.out = out;
3331        methodsBuffered = new ArrayList JavaDoc();
3332        charArrayBuffer = null;
3333        err = compiler.getErrorDispatcher();
3334        ctxt = compiler.getCompilationContext();
3335        fragmentHelperClass = new FragmentHelperClass(ctxt
3336                .getServletClassName()
3337                + "Helper");
3338        pageInfo = compiler.getPageInfo();
3339
3340        /*
3341         * Temporary hack. If a JSP page uses the "extends" attribute of the
3342         * page directive, the _jspInit() method of the generated servlet class
3343         * will not be called (it is only called for those generated servlets
3344         * that extend HttpJspBase, the default), causing the tag handler pools
3345         * not to be initialized and resulting in a NPE. The JSP spec needs to
3346         * clarify whether containers can override init() and destroy(). For
3347         * now, we just disable tag pooling for pages that use "extends".
3348         */

3349        if (pageInfo.getExtends(false) == null) {
3350            isPoolingEnabled = ctxt.getOptions().isPoolingEnabled();
3351        } else {
3352            isPoolingEnabled = false;
3353        }
3354        beanInfo = pageInfo.getBeanRepository();
3355        breakAtLF = ctxt.getOptions().getMappedFile();
3356        if (isPoolingEnabled) {
3357            tagHandlerPoolNames = new Vector JavaDoc();
3358        }
3359    }
3360
3361    /**
3362     * The main entry for Generator.
3363     *
3364     * @param out
3365     * The servlet output writer
3366     * @param compiler
3367     * The compiler
3368     * @param page
3369     * The input page
3370     */

3371    public static void generate(ServletWriter out, Compiler JavaDoc compiler,
3372            Node.Nodes page) throws JasperException {
3373
3374        Generator gen = new Generator(out, compiler);
3375
3376        if (gen.isPoolingEnabled) {
3377            gen.compileTagHandlerPoolList(page);
3378        }
3379        if (gen.ctxt.isTagFile()) {
3380            JasperTagInfo tagInfo = (JasperTagInfo) gen.ctxt.getTagInfo();
3381            gen.generateTagHandlerPreamble(tagInfo, page);
3382
3383            if (gen.ctxt.isPrototypeMode()) {
3384                return;
3385            }
3386
3387            gen.generateXmlProlog(page);
3388            gen.fragmentHelperClass.generatePreamble();
3389            page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(), out,
3390                    gen.methodsBuffered, gen.fragmentHelperClass, gen.ctxt
3391                            .getClassLoader(), tagInfo));
3392            gen.generateTagHandlerPostamble(tagInfo);
3393        } else {
3394            gen.generatePreamble(page);
3395            gen.generateXmlProlog(page);
3396            gen.fragmentHelperClass.generatePreamble();
3397            page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(), out,
3398                    gen.methodsBuffered, gen.fragmentHelperClass, gen.ctxt
3399                            .getClassLoader(), null));
3400            gen.generatePostamble(page);
3401        }
3402    }
3403
3404    /*
3405     * Generates tag handler preamble.
3406     */

3407    private void generateTagHandlerPreamble(JasperTagInfo tagInfo,
3408            Node.Nodes tag) throws JasperException {
3409
3410        // Generate package declaration
3411
String JavaDoc className = tagInfo.getTagClassName();
3412        int lastIndex = className.lastIndexOf('.');
3413        if (lastIndex != -1) {
3414            String JavaDoc pkgName = className.substring(0, lastIndex);
3415            genPreamblePackage(pkgName);
3416            className = className.substring(lastIndex + 1);
3417        }
3418
3419        // Generate imports
3420
genPreambleImports();
3421
3422        // Generate class declaration
3423
out.printin("public final class ");
3424        out.println(className);
3425        out.printil(" extends javax.servlet.jsp.tagext.SimpleTagSupport");
3426        out.printin(" implements org.apache.jasper.runtime.JspSourceDependent");
3427        if (tagInfo.hasDynamicAttributes()) {
3428            out.println(",");
3429            out.printin(" javax.servlet.jsp.tagext.DynamicAttributes");
3430        }
3431        out.println(" {");
3432        out.println();
3433        out.pushIndent();
3434
3435        /*
3436         * Class body begins here
3437         */

3438        generateDeclarations(tag);
3439
3440        // Static initializations here
3441
genPreambleStaticInitializers();
3442
3443        out.printil("private JspContext jspContext;");
3444
3445        // Declare writer used for storing result of fragment/body invocation
3446
// if 'varReader' or 'var' attribute is specified
3447
out.printil("private java.io.Writer _jspx_sout;");
3448
3449        // Class variable declarations
3450
genPreambleClassVariableDeclarations(tagInfo.getTagName());
3451
3452        generateSetJspContext(tagInfo);
3453
3454        // Tag-handler specific declarations
3455
generateTagHandlerAttributes(tagInfo);
3456        if (tagInfo.hasDynamicAttributes())
3457            generateSetDynamicAttribute();
3458
3459        // Methods here
3460
genPreambleMethods();
3461
3462        // Now the doTag() method
3463
out.printil("public void doTag() throws JspException, java.io.IOException {");
3464
3465        if (ctxt.isPrototypeMode()) {
3466            out.printil("}");
3467            out.popIndent();
3468            out.printil("}");
3469            return;
3470        }
3471
3472        out.pushIndent();
3473
3474        /*
3475         * According to the spec, 'pageContext' must not be made available as an
3476         * implicit object in tag files. Declare _jspx_page_context, so we can
3477         * share the code generator with JSPs.
3478         */

3479        out.printil("PageContext _jspx_page_context = (PageContext)jspContext;");
3480        
3481        // Declare implicit objects.
3482
out.printil("HttpServletRequest request = "
3483                + "(HttpServletRequest) _jspx_page_context.getRequest();");
3484        out.printil("HttpServletResponse response = "
3485                + "(HttpServletResponse) _jspx_page_context.getResponse();");
3486        out.printil("HttpSession session = _jspx_page_context.getSession();");
3487        out.printil("ServletContext application = _jspx_page_context.getServletContext();");
3488        out.printil("ServletConfig config = _jspx_page_context.getServletConfig();");
3489        out.printil("JspWriter out = jspContext.getOut();");
3490        out.printil("_jspInit(config);");
3491        
3492        // set current JspContext on ELContext
3493
out.printil("jspContext.getELContext().putContext(JspContext.class,jspContext);");
3494        
3495        generatePageScopedVariables(tagInfo);
3496
3497        declareTemporaryScriptingVars(tag);
3498        out.println();
3499
3500        out.printil("try {");
3501        out.pushIndent();
3502    }
3503
3504    private void generateTagHandlerPostamble(TagInfo JavaDoc tagInfo) {
3505        out.popIndent();
3506
3507        // Have to catch Throwable because a classic tag handler
3508
// helper method is declared to throw Throwable.
3509
out.printil("} catch( Throwable t ) {");
3510        out.pushIndent();
3511        out.printil("if( t instanceof SkipPageException )");
3512        out.printil(" throw (SkipPageException) t;");
3513        out.printil("if( t instanceof java.io.IOException )");
3514        out.printil(" throw (java.io.IOException) t;");
3515        out.printil("if( t instanceof IllegalStateException )");
3516        out.printil(" throw (IllegalStateException) t;");
3517        out.printil("if( t instanceof JspException )");
3518        out.printil(" throw (JspException) t;");
3519        out.printil("throw new JspException(t);");
3520        out.popIndent();
3521        out.printil("} finally {");
3522        out.pushIndent();
3523        
3524        // handle restoring VariableMapper
3525
TagAttributeInfo JavaDoc[] attrInfos = tagInfo.getAttributes();
3526        for (int i = 0; i < attrInfos.length; i++) {
3527            if (attrInfos[i].isDeferredMethod() || attrInfos[i].isDeferredValue()) {
3528                out.printin("_el_variablemapper.setVariable(");
3529                out.print(quote(attrInfos[i].getName()));
3530                out.print(",_el_ve");
3531                out.print(i);
3532                out.println(");");
3533            }
3534        }
3535        
3536        // restore nested JspContext on ELContext
3537
out.printil("jspContext.getELContext().putContext(JspContext.class,super.getJspContext());");
3538        
3539        out.printil("((org.apache.jasper.runtime.JspContextWrapper) jspContext).syncEndTagFile();");
3540        if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) {
3541            out.printil("_jspDestroy();");
3542        }
3543        out.popIndent();
3544        out.printil("}");
3545
3546        // Close the doTag method
3547
out.popIndent();
3548        out.printil("}");
3549
3550        // Generated methods, helper classes, etc.
3551
genCommonPostamble();
3552    }
3553
3554    /**
3555     * Generates declarations for tag handler attributes, and defines the getter
3556     * and setter methods for each.
3557     */

3558    private void generateTagHandlerAttributes(TagInfo JavaDoc tagInfo)
3559            throws JasperException {
3560
3561        if (tagInfo.hasDynamicAttributes()) {
3562            out.printil("private java.util.HashMap _jspx_dynamic_attrs = new java.util.HashMap();");
3563        }
3564
3565        // Declare attributes
3566
TagAttributeInfo JavaDoc[] attrInfos = tagInfo.getAttributes();
3567        for (int i = 0; i < attrInfos.length; i++) {
3568            out.printin("private ");
3569            if (attrInfos[i].isFragment()) {
3570                out.print("javax.servlet.jsp.tagext.JspFragment ");
3571            } else {
3572                out.print(JspUtil.toJavaSourceType(attrInfos[i].getTypeName()));
3573                out.print(" ");
3574            }
3575            out.print(attrInfos[i].getName());
3576            out.println(";");
3577        }
3578        out.println();
3579
3580        // Define attribute getter and setter methods
3581
if (attrInfos != null) {
3582            for (int i = 0; i < attrInfos.length; i++) {
3583                // getter method
3584
out.printin("public ");
3585                if (attrInfos[i].isFragment()) {
3586                    out.print("javax.servlet.jsp.tagext.JspFragment ");
3587                } else {
3588                    out.print(JspUtil.toJavaSourceType(attrInfos[i]
3589                            .getTypeName()));
3590                    out.print(" ");
3591                }
3592                out.print(toGetterMethod(attrInfos[i].getName()));
3593                out.println(" {");
3594                out.pushIndent();
3595                out.printin("return this.");
3596                out.print(attrInfos[i].getName());
3597                out.println(";");
3598                out.popIndent();
3599                out.printil("}");
3600                out.println();
3601
3602                // setter method
3603
out.printin("public void ");
3604                out.print(toSetterMethodName(attrInfos[i].getName()));
3605                if (attrInfos[i].isFragment()) {
3606                    out.print("(javax.servlet.jsp.tagext.JspFragment ");
3607                } else {
3608                    out.print("(");
3609                    out.print(JspUtil.toJavaSourceType(attrInfos[i]
3610                            .getTypeName()));
3611                    out.print(" ");
3612                }
3613                out.print(attrInfos[i].getName());
3614                out.println(") {");
3615                out.pushIndent();
3616                out.printin("this.");
3617                out.print(attrInfos[i].getName());
3618                out.print(" = ");
3619                out.print(attrInfos[i].getName());
3620                out.println(";");
3621                if (ctxt.isTagFile()) {
3622                    // Tag files should also set jspContext attributes
3623
out.printin("jspContext.setAttribute(\"");
3624                    out.print(attrInfos[i].getName());
3625                    out.print("\", ");
3626                    out.print(attrInfos[i].getName());
3627                    out.println(");");
3628                }
3629                out.popIndent();
3630                out.printil("}");
3631                out.println();
3632            }
3633        }
3634    }
3635
3636    /*
3637     * Generate setter for JspContext so we can create a wrapper and store both
3638     * the original and the wrapper. We need the wrapper to mask the page
3639     * context from the tag file and simulate a fresh page context. We need the
3640     * original to do things like sync AT_BEGIN and AT_END scripting variables.
3641     */

3642    private void generateSetJspContext(TagInfo JavaDoc tagInfo) {
3643
3644        boolean nestedSeen = false;
3645        boolean atBeginSeen = false;
3646        boolean atEndSeen = false;
3647
3648        // Determine if there are any aliases
3649
boolean aliasSeen = false;
3650        TagVariableInfo JavaDoc[] tagVars = tagInfo.getTagVariableInfos();
3651        for (int i = 0; i < tagVars.length; i++) {
3652            if (tagVars[i].getNameFromAttribute() != null
3653                    && tagVars[i].getNameGiven() != null) {
3654                aliasSeen = true;
3655                break;
3656            }
3657        }
3658
3659        if (aliasSeen) {
3660            out
3661                    .printil("public void setJspContext(JspContext ctx, java.util.Map aliasMap) {");
3662        } else {
3663            out.printil("public void setJspContext(JspContext ctx) {");
3664        }
3665        out.pushIndent();
3666        out.printil("super.setJspContext(ctx);");
3667        out.printil("java.util.ArrayList _jspx_nested = null;");
3668        out.printil("java.util.ArrayList _jspx_at_begin = null;");
3669        out.printil("java.util.ArrayList _jspx_at_end = null;");
3670
3671        for (int i = 0; i < tagVars.length; i++) {
3672
3673            switch (tagVars[i].getScope()) {
3674            case VariableInfo.NESTED:
3675                if (!nestedSeen) {
3676                    out.printil("_jspx_nested = new java.util.ArrayList();");
3677                    nestedSeen = true;
3678                }
3679                out.printin("_jspx_nested.add(");
3680                break;
3681
3682            case VariableInfo.AT_BEGIN:
3683                if (!atBeginSeen) {
3684                    out.printil("_jspx_at_begin = new java.util.ArrayList();");
3685                    atBeginSeen = true;
3686                }
3687                out.printin("_jspx_at_begin.add(");
3688                break;
3689
3690            case VariableInfo.AT_END:
3691                if (!atEndSeen) {
3692                    out.printil("_jspx_at_end = new java.util.ArrayList();");
3693                    atEndSeen = true;
3694                }
3695                out.printin("_jspx_at_end.add(");
3696                break;
3697            } // switch
3698

3699            out.print(quote(tagVars[i].getNameGiven()));
3700            out.println(");");
3701        }
3702        if (aliasSeen) {
3703            out
3704                    .printil("this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, aliasMap);");
3705        } else {
3706            out
3707                    .printil("this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, null);");
3708        }
3709        out.popIndent();
3710        out.printil("}");
3711        out.println();
3712        out.printil("public JspContext getJspContext() {");
3713        out.pushIndent();
3714        out.printil("return this.jspContext;");
3715        out.popIndent();
3716        out.printil("}");
3717    }
3718
3719    /*
3720     * Generates implementation of
3721     * javax.servlet.jsp.tagext.DynamicAttributes.setDynamicAttribute() method,
3722     * which saves each dynamic attribute that is passed in so that a scoped
3723     * variable can later be created for it.
3724     */

3725    public void generateSetDynamicAttribute() {
3726        out
3727                .printil("public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {");
3728        out.pushIndent();
3729        /*
3730         * According to the spec, only dynamic attributes with no uri are to be
3731         * present in the Map; all other dynamic attributes are ignored.
3732         */

3733        out.printil("if (uri == null)");
3734        out.pushIndent();
3735        out.printil("_jspx_dynamic_attrs.put(localName, value);");
3736        out.popIndent();
3737        out.popIndent();
3738        out.printil("}");
3739    }
3740
3741    /*
3742     * Creates a page-scoped variable for each declared tag attribute. Also, if
3743     * the tag accepts dynamic attributes, a page-scoped variable is made
3744     * available for each dynamic attribute that was passed in.
3745     */

3746    private void generatePageScopedVariables(JasperTagInfo tagInfo) {
3747
3748        // "normal" attributes
3749
TagAttributeInfo JavaDoc[] attrInfos = tagInfo.getAttributes();
3750        boolean variableMapperVar = false;
3751        for (int i = 0; i < attrInfos.length; i++) {
3752            String JavaDoc attrName = attrInfos[i].getName();
3753            
3754            // handle assigning deferred vars to VariableMapper, storing
3755
// previous values under '_el_ve[i]' for later re-assignment
3756
if (attrInfos[i].isDeferredValue() || attrInfos[i].isDeferredMethod()) {
3757                
3758                // we need to scope the modified VariableMapper for consistency and performance
3759
if (!variableMapperVar) {
3760                    out.printil("javax.el.VariableMapper _el_variablemapper = jspContext.getELContext().getVariableMapper();");
3761                    variableMapperVar = true;
3762                }
3763                
3764                out.printin("javax.el.ValueExpression _el_ve");
3765                out.print(i);
3766                out.print(" = _el_variablemapper.setVariable(");
3767                out.print(quote(attrName));
3768                out.print(',');
3769                if (attrInfos[i].isDeferredMethod()) {
3770                    out.print(VAR_EXPRESSIONFACTORY);
3771                    out.print(".createValueExpression(");
3772                    out.print(toGetterMethod(attrName));
3773                    out.print(",javax.el.MethodExpression.class)");
3774                } else {
3775                    out.print(toGetterMethod(attrName));
3776                }
3777                out.println(");");
3778            } else {
3779                out.printil("if( " + toGetterMethod(attrName) + " != null ) ");
3780                out.pushIndent();
3781                out.printin("_jspx_page_context.setAttribute(");
3782                out.print(quote(attrName));
3783                out.print(", ");
3784                out.print(toGetterMethod(attrName));
3785                out.println(");");
3786                out.popIndent();
3787            }
3788        }
3789
3790        // Expose the Map containing dynamic attributes as a page-scoped var
3791
if (tagInfo.hasDynamicAttributes()) {
3792            out.printin("_jspx_page_context.setAttribute(\"");
3793            out.print(tagInfo.getDynamicAttributesMapName());
3794            out.print("\", _jspx_dynamic_attrs);");
3795        }
3796    }
3797
3798    /*
3799     * Generates the getter method for the given attribute name.
3800     */

3801    private String JavaDoc toGetterMethod(String JavaDoc attrName) {
3802        char[] attrChars = attrName.toCharArray();
3803        attrChars[0] = Character.toUpperCase(attrChars[0]);
3804        return "get" + new String JavaDoc(attrChars) + "()";
3805    }
3806
3807    /*
3808     * Generates the setter method name for the given attribute name.
3809     */

3810    private String JavaDoc toSetterMethodName(String JavaDoc attrName) {
3811        char[] attrChars = attrName.toCharArray();
3812        attrChars[0] = Character.toUpperCase(attrChars[0]);
3813        return "set" + new String JavaDoc(attrChars);
3814    }
3815
3816    /**
3817     * Class storing the result of introspecting a custom tag handler.
3818     */

3819    private static class TagHandlerInfo {
3820
3821        private Hashtable JavaDoc methodMaps;
3822
3823        private Hashtable JavaDoc propertyEditorMaps;
3824
3825        private Class JavaDoc tagHandlerClass;
3826
3827        /**
3828         * Constructor.
3829         *
3830         * @param n
3831         * The custom tag whose tag handler class is to be
3832         * introspected
3833         * @param tagHandlerClass
3834         * Tag handler class
3835         * @param err
3836         * Error dispatcher
3837         */

3838        TagHandlerInfo(Node n, Class JavaDoc tagHandlerClass, ErrorDispatcher err)
3839                throws JasperException {
3840            this.tagHandlerClass = tagHandlerClass;
3841            this.methodMaps = new Hashtable JavaDoc();
3842            this.propertyEditorMaps = new Hashtable JavaDoc();
3843
3844            try {
3845                BeanInfo JavaDoc tagClassInfo = Introspector
3846                        .getBeanInfo(tagHandlerClass);
3847                PropertyDescriptor JavaDoc[] pd = tagClassInfo.getPropertyDescriptors();
3848                for (int i = 0; i < pd.length; i++) {
3849                    /*
3850                     * FIXME: should probably be checking for things like
3851                     * pageContext, bodyContent, and parent here -akv
3852                     */

3853                    if (pd[i].getWriteMethod() != null) {
3854                        methodMaps.put(pd[i].getName(), pd[i].getWriteMethod());
3855                    }
3856                    if (pd[i].getPropertyEditorClass() != null)
3857                        propertyEditorMaps.put(pd[i].getName(), pd[i]
3858                                .getPropertyEditorClass());
3859                }
3860            } catch (IntrospectionException JavaDoc ie) {
3861                err.jspError(n, "jsp.error.introspect.taghandler",
3862                        tagHandlerClass.getName(), ie);
3863            }
3864        }
3865
3866        /**
3867         * XXX
3868         */

3869        public Method JavaDoc getSetterMethod(String JavaDoc attrName) {
3870            return (Method JavaDoc) methodMaps.get(attrName);
3871        }
3872
3873        /**
3874         * XXX
3875         */

3876        public Class JavaDoc getPropertyEditorClass(String JavaDoc attrName) {
3877            return (Class JavaDoc) propertyEditorMaps.get(attrName);
3878        }
3879
3880        /**
3881         * XXX
3882         */

3883        public Class JavaDoc getTagHandlerClass() {
3884            return tagHandlerClass;
3885        }
3886    }
3887
3888    /**
3889     * A class for generating codes to a buffer. Included here are some support
3890     * for tracking source to Java lines mapping.
3891     */

3892    private static class GenBuffer {
3893
3894        /*
3895         * For a CustomTag, the codes that are generated at the beginning of the
3896         * tag may not be in the same buffer as those for the body of the tag.
3897         * Two fields are used here to keep this straight. For codes that do not
3898         * corresponds to any JSP lines, they should be null.
3899         */

3900        private Node node;
3901
3902        private Node.Nodes body;
3903
3904        private java.io.CharArrayWriter JavaDoc charWriter;
3905
3906        protected ServletWriter out;
3907
3908        GenBuffer() {
3909            this(null, null);
3910        }
3911
3912        GenBuffer(Node n, Node.Nodes b) {
3913            node = n;
3914            body = b;
3915            if (body != null) {
3916                body.setGeneratedInBuffer(true);
3917            }
3918            charWriter = new java.io.CharArrayWriter JavaDoc();
3919            out = new ServletWriter(new java.io.PrintWriter JavaDoc(charWriter));
3920        }
3921
3922        public ServletWriter getOut() {
3923            return out;
3924        }
3925
3926        public String JavaDoc toString() {
3927            return charWriter.toString();
3928        }
3929
3930        /**
3931         * Adjust the Java Lines. This is necessary because the Java lines
3932         * stored with the nodes are relative the beginning of this buffer and
3933         * need to be adjusted when this buffer is inserted into the source.
3934         */

3935        public void adjustJavaLines(final int offset) {
3936
3937            if (node != null) {
3938                adjustJavaLine(node, offset);
3939            }
3940
3941            if (body != null) {
3942                try {
3943                    body.visit(new Node.Visitor() {
3944
3945                        public void doVisit(Node n) {
3946                            adjustJavaLine(n, offset);
3947                        }
3948
3949                        public void visit(Node.CustomTag n)
3950                                throws JasperException {
3951                            Node.Nodes b = n.getBody();
3952                            if (b != null && !b.isGeneratedInBuffer()) {
3953                                // Don't adjust lines for the nested tags that
3954
// are also generated in buffers, because the
3955
// adjustments will be done elsewhere.
3956
b.visit(this);
3957                            }
3958                        }
3959                    });
3960                } catch (JasperException ex) {
3961                }
3962            }
3963        }
3964
3965        private static void adjustJavaLine(Node n, int offset) {
3966            if (n.getBeginJavaLine() > 0) {
3967                n.setBeginJavaLine(n.getBeginJavaLine() + offset);
3968                n.setEndJavaLine(n.getEndJavaLine() + offset);
3969            }
3970        }
3971    }
3972
3973    /**
3974     * Keeps track of the generated Fragment Helper Class
3975     */

3976    private static class FragmentHelperClass {
3977
3978        private static class Fragment {
3979            private GenBuffer genBuffer;
3980
3981            private int id;
3982
3983            public Fragment(int id, Node node) {
3984                this.id = id;
3985                genBuffer = new GenBuffer(null, node.getBody());
3986            }
3987
3988            public GenBuffer getGenBuffer() {
3989                return this.genBuffer;
3990            }
3991
3992            public int getId() {
3993                return this.id;
3994            }
3995        }
3996
3997        // True if the helper class should be generated.
3998
private boolean used = false;
3999
4000        private ArrayList JavaDoc fragments = new ArrayList JavaDoc();
4001
4002        private String JavaDoc className;
4003
4004        // Buffer for entire helper class
4005
private GenBuffer classBuffer = new GenBuffer();
4006
4007        public FragmentHelperClass(String JavaDoc className) {
4008            this.className = className;
4009        }
4010
4011        public String JavaDoc getClassName() {
4012            return this.className;
4013        }
4014
4015        public boolean isUsed() {
4016            return this.used;
4017        }
4018
4019        public void generatePreamble() {
4020            ServletWriter out = this.classBuffer.getOut();
4021            out.println();
4022            out.pushIndent();
4023            // Note: cannot be static, as we need to reference things like
4024
// _jspx_meth_*
4025
out.printil("private class " + className);
4026            out.printil(" extends "
4027                    + "org.apache.jasper.runtime.JspFragmentHelper");
4028            out.printil("{");
4029            out.pushIndent();
4030            out
4031                    .printil("private javax.servlet.jsp.tagext.JspTag _jspx_parent;");
4032            out.printil("private int[] _jspx_push_body_count;");
4033            out.println();
4034            out.printil("public " + className
4035                    + "( int discriminator, JspContext jspContext, "
4036                    + "javax.servlet.jsp.tagext.JspTag _jspx_parent, "
4037                    + "int[] _jspx_push_body_count ) {");
4038            out.pushIndent();
4039            out.printil("super( discriminator, jspContext, _jspx_parent );");
4040            out.printil("this._jspx_parent = _jspx_parent;");
4041            out.printil("this._jspx_push_body_count = _jspx_push_body_count;");
4042            out.popIndent();
4043            out.printil("}");
4044        }
4045
4046        public Fragment openFragment(Node parent, String JavaDoc tagHandlerVar,
4047                int methodNesting) throws JasperException {
4048            Fragment result = new Fragment(fragments.size(), parent);
4049            fragments.add(result);
4050            this.used = true;
4051            parent.setInnerClassName(className);
4052
4053            ServletWriter out = result.getGenBuffer().getOut();
4054            out.pushIndent();
4055            out.pushIndent();
4056            // XXX - Returns boolean because if a tag is invoked from
4057
// within this fragment, the Generator sometimes might
4058
// generate code like "return true". This is ignored for now,
4059
// meaning only the fragment is skipped. The JSR-152
4060
// expert group is currently discussing what to do in this case.
4061
// See comment in closeFragment()
4062
if (methodNesting > 0) {
4063                out.printin("public boolean invoke");
4064            } else {
4065                out.printin("public void invoke");
4066            }
4067            out.println(result.getId() + "( " + "JspWriter out ) ");
4068            out.pushIndent();
4069            // Note: Throwable required because methods like _jspx_meth_*
4070
// throw Throwable.
4071
out.printil("throws Throwable");
4072            out.popIndent();
4073            out.printil("{");
4074            out.pushIndent();
4075            generateLocalVariables(out, parent);
4076
4077            return result;
4078        }
4079
4080        public void closeFragment(Fragment fragment, int methodNesting) {
4081            ServletWriter out = fragment.getGenBuffer().getOut();
4082            // XXX - See comment in openFragment()
4083
if (methodNesting > 0) {
4084                out.printil("return false;");
4085            } else {
4086                out.printil("return;");
4087            }
4088            out.popIndent();
4089            out.printil("}");
4090        }
4091
4092        public void generatePostamble() {
4093            ServletWriter out = this.classBuffer.getOut();
4094            // Generate all fragment methods:
4095
for (int i = 0; i < fragments.size(); i++) {
4096                Fragment fragment = (Fragment) fragments.get(i);
4097                fragment.getGenBuffer().adjustJavaLines(out.getJavaLine() - 1);
4098                out.printMultiLn(fragment.getGenBuffer().toString());
4099            }
4100
4101            // Generate postamble:
4102
out.printil("public void invoke( java.io.Writer writer )");
4103            out.pushIndent();
4104            out.printil("throws JspException");
4105            out.popIndent();
4106            out.printil("{");
4107            out.pushIndent();
4108            out.printil("JspWriter out = null;");
4109            out.printil("if( writer != null ) {");
4110            out.pushIndent();
4111            out.printil("out = this.jspContext.pushBody(writer);");
4112            out.popIndent();
4113            out.printil("} else {");
4114            out.pushIndent();
4115            out.printil("out = this.jspContext.getOut();");
4116            out.popIndent();
4117            out.printil("}");
4118            out.printil("try {");
4119            out.pushIndent();
4120            out.printil("this.jspContext.getELContext().putContext(JspContext.class,this.jspContext);");
4121            out.printil("switch( this.discriminator ) {");
4122            out.pushIndent();
4123            for (int i = 0; i < fragments.size(); i++) {
4124                out.printil("case " + i + ":");
4125                out.pushIndent();
4126                out.printil("invoke" + i + "( out );");
4127                out.printil("break;");
4128                out.popIndent();
4129            }
4130            out.popIndent();
4131            out.printil("}"); // switch
4132
out.popIndent();
4133            out.printil("}"); // try
4134
out.printil("catch( Throwable e ) {");
4135            out.pushIndent();
4136            out.printil("if (e instanceof SkipPageException)");
4137            out.printil(" throw (SkipPageException) e;");
4138            out.printil("throw new JspException( e );");
4139            out.popIndent();
4140            out.printil("}"); // catch
4141
out.printil("finally {");
4142            out.pushIndent();
4143
4144            out.printil("if( writer != null ) {");
4145            out.pushIndent();
4146            out.printil("this.jspContext.popBody();");
4147            out.popIndent();
4148            out.printil("}");
4149
4150            out.popIndent();
4151            out.printil("}"); // finally
4152
out.popIndent();
4153            out.printil("}"); // invoke method
4154
out.popIndent();
4155            out.printil("}"); // helper class
4156
out.popIndent();
4157        }
4158
4159        public String JavaDoc toString() {
4160            return classBuffer.toString();
4161        }
4162
4163        public void adjustJavaLines(int offset) {
4164            for (int i = 0; i < fragments.size(); i++) {
4165                Fragment fragment = (Fragment) fragments.get(i);
4166                fragment.getGenBuffer().adjustJavaLines(offset);
4167            }
4168        }
4169    }
4170}
4171
Popular Tags