costin 01/06/05 23:12:47 Modified: jasper34/generator/org/apache/jasper34/generator ServletWriter.java Log: Expanded ServletWriter ( with methods from JspParseEventListener ). Still need to be simplified, by adding few more callbacks ( and allowing generators to play with more methods ) Revision Changes Path 1.2 +390 -103 jakarta-tomcat-jasper/jasper34/generator/org/apache/jasper34/generator/ServletWriter.java Index: ServletWriter.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper34/generator/org/apache/jasper34/generator/ServletWriter.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ServletWriter.java 2001/05/27 23:19:31 1.1 +++ ServletWriter.java 2001/06/06 06:12:45 1.2 @@ -1,8 +1,4 @@ /* - * $Header: /home/cvs/jakarta-tomcat-jasper/jasper34/generator/org/apache/jasper34/generator/ServletWriter.java,v 1.1 2001/05/27 23:19:31 costin Exp $ - * $Revision: 1.1 $ - * $Date: 2001/05/27 23:19:31 $ - * * ==================================================================== * * The Apache Software License, Version 1.1 @@ -59,132 +55,423 @@ * */ package org.apache.jasper34.generator; + +import java.io.*; +import java.util.*; -import java.io.PrintWriter; -import java.io.BufferedReader; -import java.io.StringReader; -import java.io.IOException; +import org.apache.jasper34.javagen.*; +import org.apache.jasper34.core.*; +import org.apache.jasper34.runtime.*; +import org.apache.jasper34.parser.*; +import org.apache.jasper34.jsptree.*; /** - * This is what is used to generate servlets. + * This is what is used to generate servlets. + * Derived from the generic java code generator. * * @author Anil K. Vijendran + * @author Costin Manolache */ -public class ServletWriter { - public static int TAB_WIDTH = 4; - public static String SPACES = " "; +public class ServletWriter extends JavaSourceGenerator { + + public ServletWriter(PrintWriter writer) { + super( writer ); + } + + public void generateServlet(JspCompilationContext ctxt, + JspPageInfo pageInfo ) + throws JasperException + { + // Do we need that ?? + ctxt.setContentType(pageInfo.servletContentType); + + generateHeader(pageInfo); + + generateClassDeclarations(pageInfo ); + + generateStaticInit(pageInfo ); - // Current indent level: - int indent = 0; + generateConstructor(pageInfo ); + + generateJspxInit( pageInfo ); + + generateGetPageContext( pageInfo ); + + generateServiceMethod( pageInfo ); + + generateJspService(pageInfo); + + this.generateClassFooter(); + + // Generate additional file for large chunks + generateChunksDat( pageInfo ); + } + - // The sink writer: - PrintWriter writer; + // -------------------- Code generators -------------------- + + private void generateHeader(JspPageInfo pageInfo) + throws JasperException + { + String servletPackageName = pageInfo.getServletPackageName(); + String servletClassName = pageInfo.getServletClassName(); + // First the package name: + this.setPackage( servletPackageName ); + + Enumeration e = pageInfo.imports.elements(); + while (e.hasMoreElements()) + this.addImport((String) e.nextElement()); + + this.generateHeader(); + + for(int i = 0; i < pageInfo.generators.size(); i++) { + GeneratorBase gen=(GeneratorBase)pageInfo.generators.elementAt(i); + //gen.startComment(this); + gen.generateFileDeclaration(this); + //gen.endComment(this); + } + + this.setClassName( servletClassName ); + this.setExtendClass( pageInfo.extendsClass.equals("") ? + pageInfo.jspServletBase : pageInfo.extendsClass); + + if (pageInfo.singleThreaded) + pageInfo.interfaces.addElement("SingleThreadModel"); + + if (pageInfo.interfaces.size() != 0) { + for(int i = 0; i < pageInfo.interfaces.size() ; i++) + this.addInterface((String)pageInfo.interfaces.elementAt(i)); + } + + this.generateClassHeader(); + } - public ServletWriter(PrintWriter writer) { - this.writer = writer; + private void generateClassDeclarations(JspPageInfo pageInfo) + throws JasperException + { + for(int i = 0; i < pageInfo.generators.size(); i++) { + GeneratorBase gen=(GeneratorBase)pageInfo.generators.elementAt(i); + //gen.startComment(this); + gen.generateClassDeclaration(this); + //gen.endComment(this); + } + + this.println(); } - public void close() throws IOException { - writer.close(); + private void generateJspService(JspPageInfo pageInfo) + throws JasperException + { + this.println("public void _jspService("+ + "PageContext pageContext, " + + "HttpServletRequest request, "+ + "HttpServletResponse response)"); + this.println(" throws Throwable "); + this.println("{"); + + this.pushIndent(); + if (pageInfo.contentTypeDir == true) + this.println("response.setContentType(" + + this.quoteString(pageInfo.servletContentType) + + ");"); + else + this.println("response.setContentType(\"" + + pageInfo.servletContentType + + ";charset=8859_1\");"); + + if (pageInfo.isErrorPage()) + this.println("Throwable exception = (Throwable) request.getAttribute(\"javax.servlet.jsp.jspException\");"); + this.println("Object page = this;"); + this.println("String _value = null;"); + this.println("ServletContext application = pageContext.getServletContext();"); + this.println("ServletConfig config = pageContext.getServletConfig();"); + this.println("JspWriter out = pageContext.getOut();"); + + if (pageInfo.genSessionVariable) + this.println("HttpSession session = pageContext.getSession();"); + + this.println(); + + // We can use tc hooks + for(int i = 0; i < pageInfo.generators.size(); i++) { + GeneratorBase gen=(GeneratorBase)pageInfo.generators.elementAt(i); + generateStartComment(gen); + gen.generateServiceMethod(this); + generateEndComment(gen); + } + this.println(); + this.popIndent(); + + // Close the class definition: + this.popIndent(); + this.println("}"); + } + + private void generateStaticInit(JspPageInfo pageInfo ) + throws JasperException + { + this.println("static {"); + this.pushIndent(); + + for(int i = 0; i < pageInfo.generators.size(); i++) { + GeneratorBase gen=(GeneratorBase)pageInfo.generators.elementAt(i); + //gen.startComment(this); + gen.generateStaticInitializer(this); + //gen.endComment(this); + } + + this.popIndent(); + this.println("}"); } + + private void generateConstructor(JspPageInfo pageInfo ) + throws JasperException + { + this.println("public "+ pageInfo.getServletClassName()+"( ) {"); + this.println("}"); + this.println(); + } + - public void pushIndent() { - if ((indent += TAB_WIDTH) > SPACES.length()) - indent = SPACES.length(); + private void generateJspxInit(JspPageInfo pageInfo ) + throws JasperException + { + this.println("private boolean _jspx_inited = false;"); + this.println(); + + this.println("public final synchronized void _jspx_init() throws " + + Constants.JSP_RUNTIME_PACKAGE + ".JasperException {"); + this.pushIndent(); + this.println("if (! _jspx_inited) {"); + this.pushIndent(); + + for(int i = 0; i < pageInfo.generators.size(); i++) { + GeneratorBase gen=(GeneratorBase)pageInfo.generators.elementAt(i); + //gen.startComment(this); + gen.generateInitMethod(this); + //gen.endComment(this); + } + + this.println("_jspx_inited = true;"); + this.popIndent(); + this.println("}"); + this.popIndent(); + this.println("}"); + this.println(); } + + - public void popIndent() { - if ((indent -= TAB_WIDTH) <= 0 ) - indent = 0; + private void generateGetPageContext(JspPageInfo pageInfo ) + throws JasperException + { + this.println("public final PageContext _getPageContext(HttpServletRequest request, " + + " HttpServletResponse response)"); + + this.println( "{" ); + this.pushIndent(); + + // protected field _jspxFactory already defined in HttpJspBase + if( ! pageInfo.extendsClass.equals("") ) + this.println("JspFactory _jspxFactory = JspFactory.getDefaultFactory();"); + + + this.println("return _jspxFactory.getPageContext(this, request, response,\n" + + "\t\t\t" + + this.quoteString(pageInfo.error) + ", " + + pageInfo.genSessionVariable + ", " + + pageInfo.bufferSize + ", " + + pageInfo.autoFlush + + ");"); + this.popIndent(); + this.println("}"); + this.println(); } - /** - * Print a standard comment for echo outputed chunk. - * @param start The starting position of the JSP chunk being processed. - * @param stop The ending position of the JSP chunk being processed. - */ - public void printComment(Mark start, Mark stop, char[] chars) { - if (start != null && stop != null) { - println("// from="+start); - println("// to="+stop); - } + + /** Generate serviceMethod - as required by the spec + Used only if the page extends something else than HttpJspBase + If HttpJspBase is used, the code is not needed, as it + replicates the code in it. + */ + private void generateServiceMethod(JspPageInfo pageInfo ) + throws JasperException + { + // if extends HttpJspBase, this method is already defined in supper + if( pageInfo.extendsClass.equals("") ) + return; + + this.println(); + + this.println("public void "+pageInfo.serviceMethodName+"("+ + "HttpServletRequest request, "+ + "HttpServletResponse response)"); + this.println(" throws java.io.IOException, ServletException {"); + this.pushIndent(); + + this.println(); + this.println("JspFactory _jspxFactory = JspFactory.getDefaultFactory();"); + this.println("PageContext pageContext = null;"); + + this.println("try {"); + this.pushIndent(); + this.println("try {"); + this.pushIndent(); + + this.println(); + this.println("_jspx_init();"); + + this.println("pageContext = _getPageContext(request, response);"); + this.println(); + this.println("_jspService( pageContext, request, response );"); + //writer.println("} catch (Throwable t) {"); + this.popIndent(); + this.println("} catch (Exception ex) {"); + this.pushIndent(); + // Used to have a clearBuffer here, but it's moved in handlePageEx + this.println("if (pageContext != null) pageContext.handlePageException(ex);"); + this.popIndent(); + this.println("} catch (Error error) {"); + this.pushIndent(); + this.println("throw error;"); + this.popIndent(); + this.println("} catch (Throwable throwable) {"); + this.pushIndent(); + this.println("throw new ServletException(throwable);"); + this.popIndent(); + this.println("}"); + this.popIndent(); + this.println("} finally {"); + this.pushIndent(); + // Do stuff here for finally actions... + //writer.println("out.close();"); + + // Use flush buffer ( which just empty JspWriterImpl buffer ) + // instead of commiting the response. + this.println("JspWriter out=pageContext.getOut();"); + this.println("((" + Constants.JSP_RUNTIME_PACKAGE + + ".JspWriterImpl)out).flushBuffer();"); + this.println("if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);"); + this.popIndent(); + this.println("}"); + // Close the service method: + this.popIndent(); + this.println("}"); + + this.println(); + } + + + +// /** +// * Print a standard comment for echo outputed chunk. +// * @param start The starting position of the JSP chunk being processed. +// * @param stop The ending position of the JSP chunk being processed. +// */ +// public void printComment(Mark start, Mark stop, char[] chars) { +// if (start != null && stop != null) { +// println("// from="+start); +// println("// to="+stop); +// } - if (chars != null) - for(int i = 0; i < chars.length;) { - indent(); - print("// "); - while (chars[i] != '\n' && i < chars.length) - writer.print(chars[i++]); +// if (chars != null) +// for(int i = 0; i < chars.length;) { +// indent(); +// print("// "); +// while (chars[i] != '\n' && i < chars.length) +// writer.print(chars[i++]); +// println(); +// } +// } + + private void generateChunksDat(JspPageInfo pageInfo ) + throws JasperException + { + + if (pageInfo.ctxt.getOptions().getLargeFile()) { + try { + FileOutputStream fos=new FileOutputStream(pageInfo.dataFile); + ObjectOutputStream o + = new ObjectOutputStream(fos); + + /* + * Serialize an array of char[]'s instead of an + * array of String's because there is a limitation + * on the size of Strings that can be serialized. + */ + char[][] tempCharArray = new char[pageInfo.vector.size()][]; + pageInfo.vector.copyInto(tempCharArray); + o.writeObject(tempCharArray); + o.close(); + this.close(); + } catch (IOException ex) { + throw new JasperException(Constants.getString("jsp.error.data.file.write"), ex); } + } } + // -------------------- Generate comments -------------------- + // The code generator also maintains line number info. Right now we generate + // some comments, later we'll add real mappings + /** - * Quote the given string to make it appear in a chunk of java code. - * @param s The string to quote. - * @return The quoted string. + * Generates "start-of the JSP-embedded code block" comment + * + * @param start Start position of the block + * @param stop End position of the block + * @exception JasperException */ + public void generateStartComment(GeneratorBase generator ) + throws JasperException + { + // XXX Use emacs style or something common + Mark start=generator.start; + Mark stop=generator.stop; + String html = ""; + if (generator instanceof CharDataGenerator) { + html = "// HTML "; + } + if (start != null && stop != null) { + if (start.getFile().equals( stop.getFile())) { + String fileName = this.quoteString(start.getFile ()); + this.println(html + "// begin [file=" + fileName+";from=" + + toShortString(start) + ";to=" + + toShortString(stop) + "]"); + } else { + this.println(html + "// begin [from="+toString(start)+ + ";to="+toString(stop)+"]"); + } + } else { + this.println(html + "// begin"); + } - public String quoteString(String s) { - // Turn null string into quoted empty strings: - if ( s == null ) - return "null"; - // Hard work: - if ( s.indexOf('"') < 0 && s.indexOf('\\') < 0 && s.indexOf ('\n') < 0 - && s.indexOf ('\r') < 0) - return "\""+s+"\""; - StringBuffer sb = new StringBuffer(); - int len = s.length(); - sb.append('"'); - for (int i = 0 ; i < len ; i++) { - char ch = s.charAt(i); - if ( ch == '\\' && i+1 < len) { - sb.append('\\'); - sb.append('\\'); - sb.append(s.charAt(++i)); - } else if ( ch == '"' ) { - sb.append('\\'); - sb.append('"'); - } else if (ch == '\n') { - sb.append ("\\n"); - }else if (ch == '\r') { - sb.append ("\\r"); - }else { - sb.append(ch); - } - } - sb.append('"'); - return sb.toString(); - } - - public void println(String line) { - writer.println(SPACES.substring(0, indent)+line); - } - - public void println() { - writer.println(""); - } - - public void indent() { - writer.print(SPACES.substring(0, indent)); + // this.pushIndent(); } - - public void print(String s) { - writer.print(s); - } - - public void printMultiLn(String multiline) { - // Try to be smart (i.e. indent properly) at generating the code: - BufferedReader reader = - new BufferedReader(new StringReader(multiline)); - try { - for (String line = null ; (line = reader.readLine()) != null ; ) - // println(SPACES.substring(0, indent)+line); - println(line); - } catch (IOException ex) { - // Unlikely to happen, since we're acting on strings - } + /** + * Generates "end-of the JSP-embedded code block" comment + * + * @param out The ServletWriter + * @param start Start position of the block + * @param stop End position of the block + * @exception JasperException + */ + public void generateEndComment(GeneratorBase generator) + throws JasperException + { + // this.popIndent(); + this.println("// end"); } + // The format may change + private String toShortString( Mark mark ) { + return "("+mark.getLineNumber() + ","+mark.getColumnNumber() +")"; + } + // + private String toString( Mark mark ) { + return mark.getSystemId()+"("+mark.getLineNumber()+","+mark.getColumnNumber() +")"; + } + + }