📄 jspcompiler.java
字号:
/* GNUJSP - a free JSP implementation Copyright (C) 1998-1999, Vincent Partington <vinny@klomp.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/package org.gjt.jsp;import java.io.BufferedReader;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.FileWriter;import java.io.InputStreamReader;import java.io.IOException;import java.io.LineNumberReader;import java.io.PrintStream;import java.io.PrintWriter;import java.io.StringReader;import java.io.OutputStream;import java.util.Enumeration;import java.util.Hashtable;import java.util.Properties;import java.util.StringTokenizer;import java.util.Vector;import java.net.URLClassLoader;import java.net.URL;import java.net.URLDecoder;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import Acme.Utils;/** * This JSP compiler class takes the quick&dirty approach to JSP parsing. * The whole JSP file is read into memory and an index is run through it * until a StringIndexOutOfBoundsException occurs. I was happily hacking * away at this until I discovered it had gotten more than 30K long. It * seems to work, but someday it might be a good idea to break this * all up into separate classes, like a JSPParser, JavaGenerator en * JavaCompiler class. * * A new JSPCompiler should be created every time a file is compiled. * The classfiles directory, the file and the classname are parameters * to the constructor. Call compile() to do the actual compiling. */public class JSPCompiler { public static final int COMPILER_VERSION_NR = 4; private static final int PARSE_NONE = 0, PARSE_HTML = 1, PARSE_DECLARATION = 2, PARSE_SCRIPTLET = 3, PARSE_EXPRESSION = 4; private static final String lineSeparator = System.getProperty("line.separator"), encodedLineSeparator = javaStringEncode(System.getProperty("line.separator")); private JSPServlet jspServlet; private File jspFile, javaFile, classFile; private String className; private HttpServletRequest servletRequest; private String src; private int srcPos, lineNr; private int parseState = PARSE_NONE; private boolean justWroteNewline = false; private Vector dependencies = new Vector(); private boolean createSession = false; private String content_typeDirective = null; private StringBuffer extendsDirective = new StringBuffer(), implementsDirective = new StringBuffer(), importDirective = new StringBuffer(), methodDirective = new StringBuffer(), declarationsCode = new StringBuffer(), beanCode = new StringBuffer(), scriptletsCode = new StringBuffer(); /** * Create a JSPCompiler object. */ public JSPCompiler(JSPServlet jspServlet, File jspFile, String className, HttpServletRequest servletRequest) { this.jspServlet = jspServlet; this.jspFile = jspFile; this.javaFile = getFileForClass(jspServlet.repository, className, ".java"); this.classFile = getFileForClass(jspServlet.repository, className, ".class"); this.className = className; this.servletRequest = servletRequest; } /** * Do the actual compilation. This is done in three phases: * <OL> * <LI>parse the JSP file * <LI>generate a <CODE>.java</CODE> file * <LI>compile the <CODE>.java</CODE> file into a <CODE>.class</CODE> file * </OL> * * @exception JSPException is thrown when a compilation error occurs */ public void compile() throws JSPException { parseJspFile(); generateJavaFile(); compileJavaFile(); } private void parseJspFile() throws JSPException { parseOneJspFile(); changeParseState(PARSE_NONE); if(content_typeDirective == null) { content_typeDirective = jspServlet.defaultContentType; } if(extendsDirective.length() == 0) { extendsDirective.append("javax.servlet.http.HttpServlet"); } if(methodDirective.length() == 0) { methodDirective.append("service"); } } private void parseOneJspFile() throws JSPException { BufferedReader in; StringBuffer srcBuf; String s; int i; char c, d; // read jsp source dependencies.addElement(jspFile); dependencies.addElement(new Long(jspFile.lastModified())); try { in = new BufferedReader(new FileReader(jspFile)); try { srcBuf = new StringBuffer((int) jspFile.length()); while((s = in.readLine()) != null) { srcBuf.append(s).append((char) '\n'); } src = srcBuf.toString(); srcBuf = null; } finally { in.close(); } } catch(FileNotFoundException fnfexc) { throw new JSPException(HttpServletResponse.SC_NOT_FOUND, "File " + jspFile + " could not be found"); } catch(IOException ioexc) { throw new JSPException(ioexc.toString()); } // parse jsp source lineNr = 1; srcPos = 0; try { PARSING: for(;;) { c = src.charAt(srcPos); // check for possible state change if(c == '<') { if(parseState == PARSE_NONE || parseState == PARSE_HTML) { if(parseInNoneOrHtmlState()) { continue PARSING; } } else if(parseState == PARSE_DECLARATION) { if(parseInDeclarationState()) { continue PARSING; } } } else if(c == '%' && (parseState == PARSE_EXPRESSION || parseState == PARSE_SCRIPTLET) && (srcPos < src.length()-1 && src.charAt(srcPos+1) == '>')) { // end of expression or scriptlet changeParseState(PARSE_NONE); srcPos += 2; continue PARSING; } // output character switch(parseState) { case PARSE_NONE: changeParseState(PARSE_HTML); case PARSE_HTML: if(justWroteNewline && c != '\n') { justWroteNewline = false; scriptletsCode.append("\" +").append(lineSeparator).append("\t\t\t\""); } switch(c) { case '\b': scriptletsCode.append("\\b"); break; case '\t': scriptletsCode.append("\\t"); break; case '\n': scriptletsCode.append(encodedLineSeparator); justWroteNewline = true; lineNr++; break; case '\f': scriptletsCode.append("\\f"); break; case '\'': scriptletsCode.append("\\\'"); break; case '\"': scriptletsCode.append("\\\""); break; case '\\': scriptletsCode.append("\\\\"); break; default: if(c > 0xFF) { s = "00" + Integer.toHexString(c); scriptletsCode.append("\\u").append(s.substring(s.length() - 4)); } else if(c < ' ' || c >= 0x7F) { s = "00" + Integer.toOctalString(c); scriptletsCode.append((char) '\\').append(s.substring(s.length() - 3)); } else { scriptletsCode.append((char) c); } break; } break; case PARSE_DECLARATION: if(c == '\n') { declarationsCode.append(lineSeparator); lineNr++; } else { declarationsCode.append((char) c); } break; default: if(c == '\n') { scriptletsCode.append(lineSeparator); lineNr++; } else { scriptletsCode.append((char) c); } break; } srcPos++; } } catch(StringIndexOutOfBoundsException sioobexc) { // instead of checking for the end of the string ourselves // we let java.lang.String find it. This makes the code // simpeler and more efficient. } } private boolean parseInNoneOrHtmlState() throws StringIndexOutOfBoundsException, JSPException { String[] keyAndValue; char d; if(srcPos < src.length()-3 && src.charAt(srcPos+1) == '%') { // directive or start of expression or scriptlet d = src.charAt(srcPos+2); if(d == '=') { // start of expression changeParseState(PARSE_EXPRESSION); setSrcPos(srcPos+3); return true; } else if(d == '@') { // directive parseDirective(); return true; } else { // start of scriplet changeParseState(PARSE_SCRIPTLET); setSrcPos(srcPos+2); return true; } } else if(srcPos < src.length()-20 && src.substring(srcPos+1, srcPos+12).equalsIgnoreCase("!--#INCLUDE") && Character.isWhitespace(src.charAt(srcPos+12))) { parseSSI(); return true; } else if(srcPos < src.length()-20 && src.substring(srcPos+1, srcPos+7).equalsIgnoreCase("SCRIPT") && Character.isWhitespace(src.charAt(srcPos+7))) { // possible start of declaration boolean runatServer = false; int prevSrcPos = srcPos, prevLineNr = lineNr; srcPos += 7; skipWhitespace(); for(;;) { // check for end of tag if(src.charAt(srcPos) == '>') { if(runatServer) { // start of declaration changeParseState(PARSE_DECLARATION); srcPos++; return true; } else { srcPos = prevSrcPos; lineNr = prevLineNr; return false; } } keyAndValue = parseKeyAndValue(); if(keyAndValue[0].equalsIgnoreCase("RUNAT") && keyAndValue[1].equalsIgnoreCase("SERVER")) { runatServer = true; } } } else if(srcPos < src.length()-10 && src.substring(srcPos+1, srcPos+5).equalsIgnoreCase("BEAN") && Character.isWhitespace(src.charAt(srcPos+5))) { // bean parseBean(); return true; } return false; } private boolean parseInDeclarationState() throws StringIndexOutOfBoundsException, JSPException { if(srcPos < src.length()-8 && src.substring(srcPos+1, srcPos+8).equalsIgnoreCase("/SCRIPT") && (Character.isWhitespace(src.charAt(srcPos+8)) || src.charAt(srcPos+8) == '>')) { // end of declaration changeParseState(PARSE_NONE); setSrcPos(src.indexOf('>', srcPos)); srcPos++; return true; } return false; } private void parseDirective() throws StringIndexOutOfBoundsException, JSPException { String[] keyAndValue; StringTokenizer toker; int i; char c; srcPos += 3; skipWhitespace(); for(;;) { // check for end of directive c = src.charAt(srcPos); if(c == '%') { if(src.charAt(srcPos+1) == '>') { srcPos += 2; } else { srcPos++; } return; } else if(c == '>') { srcPos++; return; } keyAndValue = parseKeyAndValue(); if(keyAndValue[0].equalsIgnoreCase("content_type")) { // content_type if(content_typeDirective == null) { content_typeDirective = keyAndValue[1]; } } else if(keyAndValue[0].equalsIgnoreCase("extends")) { // extends if(extendsDirective.length() == 0) { extendsDirective.append(lineSeparator); recordFileAndLineNr(extendsDirective); extendsDirective.append(keyAndValue[1]); } } else if(keyAndValue[0].equalsIgnoreCase("implements")) { // implements toker = new StringTokenizer(keyAndValue[1], " ,"); while(toker.hasMoreTokens()) { if(implementsDirective.length() == 0) { implementsDirective.append(" implements").append(lineSeparator); } else { implementsDirective.append(",").append(lineSeparator); } recordFileAndLineNr(implementsDirective); implementsDirective.append(toker.nextToken()); } } else if(keyAndValue[0].equalsIgnoreCase("import")) { // import toker = new StringTokenizer(keyAndValue[1], " ,"); while(toker.hasMoreTokens()) { recordFileAndLineNr(importDirective); importDirective.append("import ").append(toker.nextToken()).append((char) ';').append(lineSeparator); } } else if(keyAndValue[0].equalsIgnoreCase("include")) { // include parseInclude(keyAndValue[1], false); } else if(keyAndValue[0].equalsIgnoreCase("language")) { // language if(!keyAndValue[1].equalsIgnoreCase("java")) { throw new JSPException("<B>" + jspFile.getPath() + ":" + lineNr + "</B>: Unknown jsp language " + keyAndValue[1]); } } else if(keyAndValue[0].equalsIgnoreCase("method")) { // method if(methodDirective.length() == 0) { methodDirective.append(lineSeparator); recordFileAndLineNr(methodDirective); methodDirective.append(keyAndValue[1]); } } else if(keyAndValue[0].equalsIgnoreCase("vinclude")) { // vinclude parseInclude(keyAndValue[1], true); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -