/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source 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. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.jsp.java; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; import javax.el.ELContext; import javax.servlet.jsp.el.ELException; import javax.servlet.jsp.tagext.PageData; import javax.servlet.jsp.tagext.TagInfo; import javax.servlet.jsp.tagext.TagLibraryValidator; import javax.servlet.jsp.tagext.ValidationMessage; import com.caucho.VersionFactory; import com.caucho.config.types.Signature; import com.caucho.el.Expr; import com.caucho.java.CompileClassNotFound; import com.caucho.java.LineMap; import com.caucho.java.LineMapWriter; import com.caucho.jsp.JspGenerator; import com.caucho.jsp.JspPageConfig; import com.caucho.jsp.JspParseException; import com.caucho.jsp.ParseState; import com.caucho.jsp.ParseTagManager; import com.caucho.jsp.QPageData; import com.caucho.jsp.StaticPage; import com.caucho.jsp.TagInstance; import com.caucho.jsp.Taglib; import com.caucho.jsp.cfg.TldFunction; import com.caucho.jsp.el.JspELParser; import com.caucho.make.ClassDependency; import com.caucho.server.util.CauchoSystem; import com.caucho.util.IntMap; import com.caucho.util.L10N; import com.caucho.vfs.Depend; import com.caucho.vfs.Encoding; import com.caucho.vfs.MergePath; import com.caucho.vfs.Path; import com.caucho.vfs.PersistentDependency; import com.caucho.vfs.ReadStream; import com.caucho.vfs.TempStream; import com.caucho.vfs.WriteStream; import com.caucho.xml.QName; import com.caucho.xpath.NamespaceContext; import com.caucho.xpath.XPath; import com.caucho.xpath.XPathParseException; /** * Generates JSP code. JavaGenerator, JavaScriptGenerator, and * StaticGenerator specialize the JspGenerator for language-specific * requirements. * * <p>JspParser parses the JSP file into an XML-DOM tree. JspGenerator * generates code from that tree. */ public class JavaJspGenerator extends JspGenerator { private static final L10N L = new L10N(JavaJspGenerator.class); private static final Logger log = Logger.getLogger(JavaJspGenerator.class.getName()); static final String IE_CLSID = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; static final String IE_URL = "http://java.sun.com/products/plugin/1.2.2/jinstall-1_2_2-win.cab#Version=1,2,2,0"; static final String NS_URL = "http://java.sun.com/products/plugin/"; static HashMap<String,Class<?>> _primitiveClasses; static HashMap<String,String> _primitives; protected JspNode _rootNode; protected ParseState _parseState; /* * Variables storing the JSP directives. */ protected boolean _ideHack = false; /* * Variables controlling caching * isUncacheable overrides isCacheable. */ protected boolean _isCacheable; protected boolean _isUncacheable; protected ArrayList<Depend> _cacheDepends = new ArrayList<Depend>(); // dependencies for the source file itself protected ArrayList<PersistentDependency> _depends = new ArrayList<PersistentDependency>(); long _lastModified; // XXX: obsolete? protected TagInstance _topTag; protected int _tagId; // XXX: needed in combination with XTP boolean _alwaysModified; protected ParseTagManager _tagManager; protected JspPageConfig _config = new JspPageConfig(); protected String _fullClassName; protected String _className; private HashMap<String,Class<?>> _classes; private HashSet<String> _declaredVariables = new HashSet<String>(); private String _filename; private final JspGenELContext _elContext; private HashMap<String,Method> _elFunctionMap = new HashMap<String,Method>(); private ArrayList<Taglib> _tagLibraryList = new ArrayList<Taglib>(); private ArrayList<String> _tagFileClassList = new ArrayList<String>(); private PageData _pageData; protected IntMap _strings = new IntMap(); private ArrayList<String> _exprList = new ArrayList<String>(); private ArrayList<ValueExpr> _valueExprList = new ArrayList<ValueExpr>(); private ArrayList<MethodExpr> _methodExprList = new ArrayList<MethodExpr>(); private ArrayList<com.caucho.xpath.Expr> _xpathExprList = new ArrayList<com.caucho.xpath.Expr>(); private ArrayList<JspFragmentNode> _fragmentList = new ArrayList<JspFragmentNode>(); private String _workPath; protected String _pkg; private int _uniqueId = 0; private int _jspId = 1; private boolean _requireSource = false; private boolean _isOmitXmlDeclaration = false; private String _doctypeSystem; private String _doctypePublic; private String _doctypeRootElement; private boolean _isJsfPrologueInit; private boolean _isStatic = false; protected ArrayList<JspDeclaration> _declarations = new ArrayList<JspDeclaration>(); public JavaJspGenerator(ParseTagManager tagManager) { _elContext = new JspGenELContext(this); _tagManager = tagManager; _topTag = new TagInstance(tagManager); } public TagInstance getRootTag() { return _topTag; } protected void setParseState(ParseState parseState) { _parseState = parseState; } public ParseState getParseState() { return _parseState; } public void setPageConfig(JspPageConfig pageConfig) { _config = pageConfig; } void setStaticEncoding(boolean staticEncoding) { _config.setStaticEncoding(staticEncoding); } void setRequireSource(boolean requireSource) { _requireSource = requireSource; } void setIdeHack(boolean ideHack) { _ideHack = ideHack; } String getPackagePrefix() { return ""; } Path getAppDir() { return _jspCompiler.getAppDir(); } /** * Returns true for XML. */ boolean isXml() { // jsp/0362 return _parseState.isXml(); } /** * Returns true if the XML declaration should be set. */ boolean isOmitXmlDeclaration() { return _isOmitXmlDeclaration; } /** * Returns true if the XML declaration should be set. */ void setOmitXmlDeclaration(boolean omitXml) { _isOmitXmlDeclaration = omitXml; } /** * Sets the dtd system name */ void setDoctypeSystem(String doctypeSystem) { _doctypeSystem = doctypeSystem; } /** * Gets the dtd system name */ String getDoctypeSystem() { return _doctypeSystem; } /** * Sets the dtd public name */ void setDoctypePublic(String doctypePublic) { _doctypePublic = doctypePublic; } /** * Gets the dtd public name */ String getDoctypePublic() { return _doctypePublic; } /** * Gets the dtd root element name */ void setDoctypeRootElement(String doctypeRootElement) { _doctypeRootElement = doctypeRootElement; } /** * Gets the dtd root element name */ String getDoctypeRootElement() { return _doctypeRootElement; } /** * Returns the character encoding. */ String getCharacterEncoding() { return _parseState.getCharEncoding(); } Path getClassDir() { return _jspCompiler.getClassDir(); } /** * Sets the root JSP node. */ public void setRootNode(JspNode node) { _rootNode = node; } public JspPageConfig getConfig() { return _config; } public boolean isTag() { return false; } public void init() { _isOmitXmlDeclaration = ! isXml(); } public boolean hasScripting() { return _rootNode.hasScripting(); } public boolean isJsfPrologueInit() { return _isJsfPrologueInit; } public void setJsfPrologueInit(boolean isInit) { _isJsfPrologueInit = isInit; } /** * Adds a taglib. */ public void addTaglib(String prefix, String uri) throws JspParseException { addTaglib(prefix, uri, false); } /** * True for a pre jsp21 tag */ public boolean isPre21() { return _parseState.getJspVersion().compareTo("2.1") < 0; } public boolean isPrototype() { return _parseState.isPrototype(); } /** * Adds a taglib. */ public void addOptionalTaglib(String prefix, String uri) throws JspParseException { addTaglib(prefix, uri, true); } /** * Adds a taglib. */ public Taglib addTaglib(String prefix, String uri, boolean isOptional) throws JspParseException { if (log.isLoggable(Level.FINEST)) log.finest("taglib prefix=" + prefix + " uri:" + uri); Taglib taglib; try { taglib = _tagManager.addTaglib(prefix, uri); } catch (JspParseException e) { if (isOptional) { log.log(Level.FINE, e.toString(), e); return null; } throw e; } if (taglib == null && isOptional && ! uri.startsWith("urn:jsptld:") && ! uri.startsWith("urn:jsptagdir:")) return null; if (taglib == null) { throw error(L.l("'{0}' has no matching taglib-uri. Taglibs specified with an absolute URI must either be:\n" + "1) specified in the web.xml\n" + "2) defined in a jar's .tld in META-INF\n" + "3) defined in a .tld in WEB-INF\n" + "4) predefined by Resin", uri)); } taglib = addLibrary(taglib); ArrayList<TldFunction> functions = taglib.getFunctionList(); for (int i = 0; i < functions.size(); i++) { TldFunction function = functions.get(i); String name = taglib.getPrefixString() + ":" + function.getName(); _elFunctionMap.put(name, function.getMethod()); } return taglib; } void addTagFileClass(String cl) { if ("com.caucho.jsp.java.JspTagFileSupport".equals(cl)) throw new IllegalStateException(); if (! _tagFileClassList.contains(cl)) _tagFileClassList.add(cl); } private Taglib addLibrary(Taglib taglib) throws JspParseException { for (int i = 0; i < _tagLibraryList.size(); i++) { Taglib oldTaglib = _tagLibraryList.get(i); if (oldTaglib.getURI().equals(taglib.getURI())) return oldTaglib; } /* // taglib = taglib.copy(); for (int i = 0; i < _tagLibraryList.size(); i++) { Taglib oldTaglib = _tagLibraryList.get(i); oldTaglib.addTaglib(taglib); taglib.addTaglib(oldTaglib); } */ _tagLibraryList.add(taglib); return taglib; } Method resolveFunction(String prefix, String localName) { if (prefix.equals("")) return _elFunctionMap.get(localName); else return _elFunctionMap.get(prefix + ':' + localName); } /** * Adds a taglib. */ public void addTaglibDir(String prefix, String tagdir) throws JspParseException { Taglib taglib = _tagManager.addTaglibDir(prefix, tagdir); ArrayList<TldFunction> functions = taglib.getFunctionList(); for (int i = 0; i < functions.size(); i++) { TldFunction function = functions.get(i); String name = taglib.getPrefixString() + ":" + function.getName(); _elFunctionMap.put(name, function.getMethod()); } } /** * Returns true if the JSP compilation has produced a static file. */ public boolean isStatic() { return _isStatic; } /** * Returns the page's XML view. */ public PageData getPageData() throws IOException { if (_pageData != null) return _pageData; TempStream ts = new TempStream(); ts.openWrite(); WriteStream ws = new WriteStream(ts); ws.setEncoding("UTF-8"); _rootNode.printXml(ws); ws.close(); if (log.isLoggable(Level.FINER)) { StringBuilder sb = new StringBuilder(); ReadStream is = ts.openReadAndSaveBuffer(); int ch; while ((ch = is.readChar()) >= 0) { sb.append((char) ch); } is.close(); log.finer("JSP[" + _fullClassName + "] " + sb); } _pageData = new QPageData(ts); return _pageData; } public ELContext getELContext() { return _elContext; } /** * Validates the JSP page. */ public void validate() throws Exception { for (int i = 0; i < _tagLibraryList.size(); i++) { Taglib taglib = _tagLibraryList.get(i); TagLibraryValidator validator = taglib.getValidator(); if (validator != null) { ValidationMessage []messages; messages = validator.validate(taglib.getPrefixString(), taglib.getURI(), getPageData()); if (messages != null && messages.length > 0) { StringBuilder message = new StringBuilder(); for (int j = 0; j < messages.length; j++) { if (j != 0) message.append("\n"); message.append(messages[j].getMessage()); } // TCK: needs to be commented out for TCK if (log.isLoggable(Level.FINE)) { InputStream is = getPageData().getInputStream(); StringBuilder sb = new StringBuilder(); int ch; while ((ch = is.read()) >= 0) sb.append((char) ch); throw _rootNode.error(message.toString() + "\n\n" + sb); } else throw _rootNode.error(message.toString()); } } } } /** * Generates the JSP page. */ @Override protected void generate(Path path, String className) throws Exception { init(className); if (_jspCompilerInstance == null || ! _jspCompilerInstance.isGeneratedSource()) addDepend(path); _cacheDepends = new ArrayList<Depend>(); _tagId = 1; if (_ideHack) _config.setStaticEncoding(false); // disable static pages. No longer needed and complicates // precompilation if (isGenerateStatic() && ! _parseState.getJspPropertyGroup().getStaticPageGeneratesClass()) { generateStatic(); } else { WriteStream os = openWriteStream(); JspJavaWriter out = new JspJavaWriter(os, this); try { generate(out); } finally { if (os != null) os.close(); } } if (_lineMap != null) { Path javaPath = getGeneratedPath(); String tail = javaPath.getTail(); tail = tail + ".smap"; WriteStream os = javaPath.getParent().lookup(tail).openWrite(); LineMapWriter writer = new LineMapWriter(os); writer.write(_lineMap); os.close(); } } public void addDepend(Path path) { addDepend(path.createDepend()); } /** * Adds a dependency based on a class. */ public void addDepend(Class<?> cl) { addDepend(new ClassDependency(cl)); } public void addDepend(PersistentDependency depend) { if (! _depends.contains(depend)) _depends.add(depend); } public ArrayList<PersistentDependency> getDependList() { return _depends; } public boolean isStaticEncoding() { return _config.isStaticEncoding(); } public boolean getRecycleTags() { return _parseState.isRecycleTags(); } /** * Adds a new Java declaration to the list. */ public void addDeclaration(JspDeclaration decl) { _declarations.add(decl); } /** * Sets the taglib manager. */ public void setTagManager(ParseTagManager tagManager) { _tagManager = tagManager; } /** * Returns the taglib manager. */ public ParseTagManager getTagManager() { return _tagManager; } protected void init(String className) { _fullClassName = className; _className = className; String prefix = getPackagePrefix(); if (prefix.endsWith(".")) prefix = prefix.substring(0, prefix.length() - 1); int p = className.lastIndexOf('.'); if (p > 0) { _pkg = className.substring(0, p); _className = className.substring(p + 1); } else _pkg = ""; if (prefix.length() > 0 && _pkg.length() > 0) _pkg = prefix + "." + _pkg; else if (prefix.length() > 0) _pkg = prefix; _workPath = _pkg.replace('.', '/'); _lineMap = new LineMap(className.replace('.', '/') + ".java"); } /** * True if it's a declared variable. */ public boolean isDeclared(String var) { return _declaredVariables.contains(var); } /** * Adds a declared variable. */ public void addDeclared(String var) { _declaredVariables.add(var); } /** * Generates the Java code. */ protected void generate(JspJavaWriter out) throws Exception { out.setLineMap(_lineMap); generateClassHeader(out); generatePageHeader(out); _rootNode.generate(out); generatePageFooter(out); // _rootNode.generateDeclaration(out); generateClassFooter(out); } /** * Generates a static file. */ protected void generateStatic() throws Exception { _isStatic = true; Path javaPath = getGeneratedPath(); String tail = javaPath.getTail(); int p = tail.indexOf('.'); tail = tail.substring(0, p); Path staticPath = javaPath.getParent().lookup(tail + ".static"); WriteStream os = staticPath.openWrite(); //os.setEncoding(_parseState.getCharEncoding()); os.setEncoding("UTF-8"); try { JspJavaWriter out = new JspJavaWriter(os, this); _rootNode.generateStatic(out); } finally { os.close(); } Path dependPath = javaPath.getParent().lookup(tail + ".depend"); StaticPage.writeDepend(dependPath, getDependList()); } /** * Generates the class header. * * @param doc the XML document representing the JSP page. */ protected void generateClassHeader(JspJavaWriter out) throws IOException, JspParseException { out.println("/*"); out.println(" * JSP generated by " + VersionFactory.getFullVersion()); out.println(" */" ); out.println(); if (_pkg != null && ! _pkg.equals("")) out.println("package " + _pkg + ";"); out.println("import javax.servlet.*;"); out.println("import javax.servlet.jsp.*;"); out.println("import javax.servlet.http.*;"); fillSingleTaglibImports(); ArrayList<String> imports = _parseState.getImportList(); for (int i = 0; i < imports.size(); i++) { String name = imports.get(i); out.print("import "); out.print(name); out.println(";"); } _parseState.addImport("javax.servlet.*"); _parseState.addImport("javax.servlet.jsp.*"); _parseState.addImport("javax.servlet.http.*"); _parseState.addImport("java.lang.*"); out.println(); if (_parseState.getExtends() != null) { //if (extendsLocation != null) //setLocation(extendsLocation.srcFilename, extendsLocation.srcLine, 0); out.print("public class "); out.print(_className); out.print(" extends "); out.print(_parseState.getExtends().getName()); out.print(" implements com.caucho.jsp.CauchoPage"); if (! _parseState.isThreadSafe()) out.print(", javax.servlet.SingleThreadModel"); } else { out.print("public class "); out.print(_className); out.print(" extends com.caucho.jsp.JavaPage"); if (! _parseState.isThreadSafe()) out.print(" implements javax.servlet.SingleThreadModel"); } out.println(); out.println("{"); out.pushDepth(); out.println("private static final java.util.HashMap<String,java.lang.reflect.Method> _jsp_functionMap = new java.util.HashMap<String,java.lang.reflect.Method>();"); out.println("private boolean _caucho_isDead;"); out.println("private boolean _caucho_isNotModified;"); out.println("private com.caucho.jsp.PageManager _jsp_pageManager;"); //out.println("private com.caucho.util.FreeList<TagState> _jsp_freeState = new com.caucho.util.FreeList<TagState>(8);"); String info = _parseState.getInfo(); if (info != null) { out.println(); out.print("public String getServletInfo() { return \""); for (int i = 0; i < info.length(); i++) { char ch = info.charAt(i); if (ch == '\\') out.print("\\\\"); else if (ch == '\n') out.print("\\n"); else if (ch == '\r') out.print("\\r"); else if (ch == '"') out.print("\\\""); else out.print(ch); } out.println("\"; }"); } for (int i = 0; i < _declarations.size(); i++) { JspDeclaration decl = _declarations.get(i); out.println(); decl.generateDeclaration(out); } } /** * As a convenience, when the Tag isn't in a package, import * it automatically. */ protected void fillSingleTaglibImports() throws JspParseException { /* Iterator<Taglib> iter = _taglibMap.values().iterator(); while (iter.hasNext()) { Taglib taglib = iter.next(); if (taglib == null) continue; ArrayList<String> singleTags = taglib.getSingleTagClassNames(); for (int i = 0; i < singleTags.size(); i++) { String className = singleTags.get(i); _parseState.addImport(className); } } */ } /** * Prints the _jspService header */ protected void generatePageHeader(JspJavaWriter out) throws Exception { out.println(""); out.println("public void"); out.println("_jspService(javax.servlet.http.HttpServletRequest request,"); out.println(" javax.servlet.http.HttpServletResponse response)"); out.println(" throws java.io.IOException, javax.servlet.ServletException"); out.println("{"); out.pushDepth(); // static shouldn't start up a session boolean isSession = _parseState.isSession() && ! _rootNode.isStatic(); if (isSession) { out.println("javax.servlet.http.HttpSession session = request.getSession(true);"); } out.println("com.caucho.server.webapp.WebApp _jsp_application = _caucho_getApplication();"); out.print("com.caucho.jsp.PageContextImpl pageContext = _jsp_pageManager.allocatePageContext("); out.print("this, _jsp_application, request, response, "); if (_parseState.getErrorPage() == null) out.print("null"); else out.print("\"" + _parseState.getErrorPage() + "\""); out.print(", "); if (isSession) { out.print("session"); } else out.print("null"); out.print(", "); out.print(_parseState.getBuffer()); out.print(", "); out.print(_parseState.isAutoFlush()); out.print(", "); out.print(_parseState.isPrintNullAsBlank()); out.println(");"); out.println(); if (_rootNode.hasCustomTag()) { out.println("TagState _jsp_state = new TagState();"); // out.println("TagState _jsp_state = _jsp_freeState.allocate();"); //out.println("if (_jsp_state == null)"); //out.println(" _jsp_state = new TagState();"); } else out.println("TagState _jsp_state = null;"); out.println(); out.println("try {"); out.pushDepth(); if (isSession) out.println("_jspService(request, response, pageContext, _jsp_application, session, _jsp_state);"); else out.println("_jspService(request, response, pageContext, _jsp_application, _jsp_state);"); out.popDepth(); out.println("} catch (java.lang.Throwable _jsp_e) {"); out.println(" pageContext.handlePageException(_jsp_e);"); out.println("} finally {"); out.pushDepth(); if (_rootNode.hasCustomTag()) { //out.println("if (! _jsp_freeState.free(_jsp_state))"); out.println("_jsp_state.release();"); } out.println("_jsp_pageManager.freePageContext(pageContext);"); // close finally out.popDepth(); out.println("}"); out.popDepth(); out.println("}"); // impl out.println(""); out.println("private void"); out.println("_jspService(javax.servlet.http.HttpServletRequest request,"); out.println(" javax.servlet.http.HttpServletResponse response,"); out.println(" com.caucho.jsp.PageContextImpl pageContext,"); out.println(" javax.servlet.ServletContext application,"); if (isSession) { out.println(" javax.servlet.http.HttpSession session,"); } out.println(" TagState _jsp_state)"); out.println(" throws Throwable"); out.println("{"); out.pushDepth(); out.println("javax.servlet.jsp.JspWriter out = pageContext.getOut();"); out.println("final javax.el.ELContext _jsp_env = pageContext.getELContext();"); out.println("javax.servlet.ServletConfig config = getServletConfig();"); out.println("javax.servlet.Servlet page = this;"); if (_parseState.isErrorPage()) { out.println("java.lang.Throwable exception = ((com.caucho.jsp.PageContextImpl) pageContext).getThrowable();"); } out.println("javax.servlet.jsp.tagext.JspTag _jsp_parent_tag = null;"); out.println("com.caucho.jsp.PageContextImpl _jsp_parentContext = pageContext;"); generateContentType(out); _rootNode.generatePrologue(out); out.println(); } /** * Generates the content type of the page. */ private void generateContentType(JspJavaWriter out) throws IOException { String encoding = Encoding.getMimeName(_parseState.getCharEncoding()); if (encoding == null && isXml()) encoding = "UTF-8"; if (encoding == null && _parseState.getJspPropertyGroup() != null) encoding = _parseState.getJspPropertyGroup().getCharacterEncoding(); if (encoding == null) encoding = Encoding.getMimeName(_parseState.getPageEncoding()); // jsp/1co7 /* if (encoding == null) encoding = Encoding.getMimeName(CharacterEncoding.getLocalEncoding()); */ /* if ("ISO-8859-1".equals(encoding)) encoding = null; */ String contentType = _parseState.getContentType(); out.print("response.setContentType(\""); if (contentType != null) out.printJavaString(contentType); else if (isXml()) out.print("text/xml"); else out.print("text/html"); out.println("\");"); if (contentType != null && contentType.equals("text/html")) contentType = null; if (encoding == null) { // server/1204 } else if (contentType == null || contentType.indexOf("charset") < 0) { out.print("response.setCharacterEncoding(\""); if (encoding != null) out.printJavaString(encoding); else out.printJavaString("iso-8859-1"); out.println("\");"); } // jsp/1e0k, #4007 /* if (encoding != null) { out.println("String _caucho_request_character_encoding = request.getCharacterEncoding();"); out.println("if (_caucho_request_character_encoding == null || \"\".equals(_caucho_request_character_encoding))"); out.pushDepth(); out.println("request.setCharacterEncoding(\"" + encoding + "\");"); out.popDepth(); } */ } public int addString(String string) { int index = _strings.get(string); if (index < 0) { index = _strings.size(); _strings.put(string, index); } return index; } /** * Saves a bean's class for later introspection. * * @param id the bean id * @param typeName the bean's type */ public void addBeanClass(String id, String typeName) throws Exception { if (_classes == null) _classes = new HashMap<String,Class<?>>(); try { if (_primitives.get(typeName) != null) return; Class<?> cl = getBeanClass(typeName); if (cl == null) throw error(L.l("Can't find class '{0}'", typeName)); _classes.put(id, cl); } catch (CompileClassNotFound e) { log.log(Level.WARNING, e.toString(), e); throw error(L.l("Can't find class '{0}'\n{1}", typeName, e.getMessage())); } catch (ClassNotFoundException e) { log.log(Level.FINE, e.toString(), e); throw error(L.l("Can't find class '{0}'", typeName)); } } /** * Loads a bean based on the class name. */ public Class<?> getBeanClass(String typeName) throws ClassNotFoundException { // Generics parameters should be removed and only the base class loaded int p = typeName.indexOf('<'); if (p > 0) return getBeanClass(typeName.substring(0, p)); // Arrays need to use Array.newInstance(cl, new int[]); p = typeName.indexOf('['); if (p > 0) { Class<?> cl = getBeanClass(typeName.substring(0, p)); int count = 0; for (int i = 0; i < typeName.length(); i++) if (typeName.charAt(i) == '[') count++; int []dims = new int[count]; for (int i = 0; i < count; i++) dims[i] = 1; Object obj = Array.newInstance(cl, dims); return obj.getClass(); } Class<?> cl = loadBeanClass(typeName); if (cl != null) return cl; // Inner classes need rewriting Foo.Bar -> Foo$Bar int i = typeName.lastIndexOf('.'); for (; i >= 0; i = typeName.lastIndexOf('.', i - 1)) { String mainClassName = typeName.substring(0, i); Class<?> mainClass = loadBeanClass(mainClassName); typeName = mainClassName + '$' + typeName.substring(i + 1); if (mainClass != null) return getBeanClass(typeName); } return null; } Class<?> loadBeanClass(String typeName) { Class<?> cl = _primitiveClasses.get(typeName); if (cl != null) return cl; try { return CauchoSystem.loadClass(typeName); } catch (CompileClassNotFound e) { log.log(Level.FINE, e.toString(), e); } catch (ClassNotFoundException e) { } // qualified names don't use the imports if (typeName.indexOf('.') >= 0) return null; ArrayList<String> imports = _parseState.getImportList(); for (int i = 0; i < imports.size(); i++) { String pkg = imports.get(i); String fullName = null; if (pkg.endsWith("." + typeName)) fullName = pkg; else if (pkg.endsWith(".*")) fullName = pkg.substring(0, pkg.length() - 1) + typeName; else continue; try { return CauchoSystem.loadClass(fullName); } catch (CompileClassNotFound e) { log.log(Level.WARNING, e.toString(), e); } catch (ClassNotFoundException e) { } } return null; } public Class<?> getClass(String id) { if (_classes == null) return null; return _classes.get(id); } protected void generatePageFooter(JspJavaWriter out) throws IOException { out.popDepth(); out.println("}"); } /** * Completes the generated class: closing the main method, generating * the dependencies and generating the constant strings. * * @param doc the XML document representing the JSP page. */ protected void generateClassFooter(JspJavaWriter out) throws Exception { // fragments must be first because they may create others. generateFragments(out); generateDepends(out); generateTags(out); _rootNode.generateClassEpilogue(out); //generateTags may still add to _value(Expr|Method)List generateInit(out); generateExprs(out); generateXPath(out); generateConstantStrings(out); out.popDepth(); out.println("}"); } public int addFragment(JspFragmentNode node) { int index = _fragmentList.indexOf(node); if (index >= 0) return index; _fragmentList.add(node); return _fragmentList.size() - 1; } public JspFragmentNode getFragment(int index) { return _fragmentList.get(index); } public com.caucho.el.Expr genExpr(String value) throws JspParseException, ELException { JspELParser parser = new JspELParser(_elContext, value); return parser.parse(); } /** * Adds an expression to the expression list. */ public int addExpr(String expr) throws JspParseException, ELException { genExpr(expr); int index = _exprList.indexOf(expr); if (index >= 0) return index; index = _exprList.size(); _exprList.add(expr); return index; } /** * Adds an expression to the expression list. */ public int addValueExpr(String value, String type) throws JspParseException, ELException { JspELParser parser = new JspELParser(_elContext, value); com.caucho.el.Expr expr = parser.parse(); int index = _valueExprList.indexOf(expr); if (index >= 0) return index; index = _valueExprList.size(); try { if (type == null || type.equals("")) _valueExprList.add(new ValueExpr(value, expr, Object.class)); else { Class<?> cl = getBeanClass(type); if (cl == null) throw new NullPointerException(type); _valueExprList.add(new ValueExpr(value, expr, cl)); } } catch (ClassNotFoundException e) { throw new ELException(e); } return index; } /** * Adds an expression to the expression list. */ public int addMethodExpr(String value, String sigString) throws JspParseException, ELException { JspELParser parser = new JspELParser(_elContext, value); com.caucho.el.Expr expr = parser.parse(); Class<?> retType = void.class; Class<?> []args = new Class[0]; try { if (sigString != null && ! sigString.equals("")) { Signature sig = new Signature(sigString); String []types = sig.getParameterTypes(); args = new Class[types.length]; for (int i = 0; i < types.length; i++) { args[i] = getBeanClass(types[i]); } if (sig.getReturnType() == null) throw error(L.l("deferredMethod signature '{0}' needs a return type.", sigString)); retType = getBeanClass(sig.getReturnType()); } } catch (ClassNotFoundException e) { throw new ELException(e); } MethodExpr methodExpr = new MethodExpr(value, expr, args, retType); if (expr.isLiteralText()) { if (void.class.equals(retType)) { // jsp/18v3 throw error(L.l("deferredMethod with string literal '{0}' cannot return void '{1}'", value, sigString)); } Object testValue = expr.getValue(null); try { Expr.coerceToType(testValue, retType); } catch (Exception e) { // jsp/18v4 (tck) throw error(L.l("string literal '{0}' can't return type '{1}'", value, sigString)); } } int index = _methodExprList.indexOf(methodExpr); if (index >= 0) return index; index = _methodExprList.size(); _methodExprList.add(methodExpr); return index; } /** * out.Prints the expressions */ private void generateExprs(JspJavaWriter out) throws IOException { for (int i = 0; i < _exprList.size(); i++) { // String expr = _exprList.get(i); out.println("private static com.caucho.el.Expr _caucho_expr_" + i + ";"); /* out.print(" "); expr.printCreate(out.getWriteStream()); out.println(";"); */ } for (int i = 0; i < _valueExprList.size(); i++) { /* ValueExpr expr = _valueExprList.get(i); String exprType = "ObjectValueExpression"; Class<?> retType = expr.getReturnType(); if (String.class.equals(retType)) exprType = "StringValueExpression"; else if (Byte.class.equals(retType) || byte.class.equals(retType)) exprType = "ByteValueExpression"; else if (Short.class.equals(retType) || short.class.equals(retType)) exprType = "ShortValueExpression"; else if (Integer.class.equals(retType) || int.class.equals(retType)) exprType = "IntegerValueExpression"; else if (Long.class.equals(retType) || long.class.equals(retType)) exprType = "LongValueExpression"; else if (Float.class.equals(retType) || long.class.equals(retType)) exprType = "FloatValueExpression"; else if (Double.class.equals(retType) || double.class.equals(retType)) exprType = "DoubleValueExpression"; else if (Boolean.class.equals(retType) || boolean.class.equals(retType)) exprType = "BooleanValueExpression"; else if (Character.class.equals(retType) || char.class.equals(retType)) exprType = "CharacterValueExpression"; else if (BigInteger.class.equals(retType)) exprType = "BigIntegerValueExpression"; else if (BigDecimal.class.equals(retType)) exprType = "BigDecimalValueExpression"; */ out.println("private static javax.el.ValueExpression _caucho_value_expr_" + i + ";"); } for (int i = 0; i < _methodExprList.size(); i++) { out.println("private static javax.el.MethodExpression _caucho_method_expr_" + i + ";"); } } /** * Adds an expression to the expression list. */ public String addXPathExpr(String value, NamespaceContext ns) throws JspParseException, XPathParseException { return addXPathExpr(XPath.parseExpr(value, ns)); } /** * Adds an expression to the expression list. */ public String addXPathExpr(com.caucho.xpath.Expr expr) throws JspParseException { int index = _xpathExprList.indexOf(expr); if (index >= 0) return "_caucho_xpath_" + index; index = _xpathExprList.size(); _xpathExprList.add(expr); return "_caucho_xpath_" + index; } /** * out.Prints the expressions */ private void generateXPath(JspJavaWriter out) throws IOException { if (_xpathExprList.size() == 0) return; for (int i = 0; i < _xpathExprList.size(); i++) { out.println("private static com.caucho.xpath.Expr _caucho_xpath_" + i + ";"); } out.println("static {"); out.pushDepth(); out.println("try {"); out.pushDepth(); for (int i = 0; i < _xpathExprList.size(); i++) { com.caucho.xpath.Expr expr = _xpathExprList.get(i); out.print("_caucho_xpath_" + i + " ="); out.println(" com.caucho.xpath.XPath.parseExpr(\"" + expr + "\");"); } out.popDepth(); out.println("} catch (Exception e) {"); out.println(" e.printStackTrace();"); out.println("}"); out.popDepth(); out.println("}"); } /** * out.Prints the fragments */ private void generateTags(JspJavaWriter out) throws Exception { out.println(); out.println("final static class TagState {"); out.pushDepth(); _rootNode.generateTagState(out); for (JspFragmentNode frag : _fragmentList) { frag.generateTagState(out); } out.println(); out.println("void release()"); out.println("{"); out.pushDepth(); _rootNode.generateTagRelease(out); for (JspFragmentNode frag : _fragmentList) { frag.generateTagRelease(out); } /* for (int i = 0; i < _topTag.size(); i++) { TagInstance tag = _topTag.get(i); if (tag.getTagClass() == null) { } else if (Tag.class.isAssignableFrom(tag.getTagClass())) { out.println("if (" + tag.getId() + " != null)"); out.println(" " + tag.getId() + ".release();"); } } */ out.popDepth(); out.println("}"); // release out.popDepth(); out.println("}"); // TagState } /** * out.Prints the fragments */ private void generateFragments(JspJavaWriter out) throws Exception { boolean hasFragment = false; /* for (int i = 0; i < _fragmentList.size(); i++) { JspFragmentNode node = _fragmentList.get(i); if (node.isStatic()) { } else hasFragment = true; } if (! hasFragment) return; */ Collections.sort(_fragmentList, new FragmentComparator()); for (int i = 0; i < _fragmentList.size(); i++) { JspFragmentNode frag = _fragmentList.get(i); if (frag.isValueFragment()) { // jsp/1cje frag.generateValueMethod(out); } else { generateNonValueFragment(out, frag, frag.getFragmentCode()); } } } private void generateNonValueFragment(JspJavaWriter out, JspFragmentNode frag, int id) throws Exception { out.println(); out.println("_CauchoFragment_" + id + " createFragment_" + id + "(_CauchoFragment_" + id + " frag,"); out.println(" javax.servlet.jsp.JspContext _jsp_parentContext,"); out.println(" com.caucho.jsp.PageContextImpl pageContext,"); out.println(" javax.servlet.jsp.tagext.JspTag parent,"); out.println(" javax.servlet.jsp.tagext.JspFragment jspBody,"); out.println(" TagState _jsp_state,"); out.println(" com.caucho.jsp.PageManager _jsp_pageManager)"); out.println("{"); out.pushDepth(); out.println("if (frag == null) {"); out.println(" frag = new _CauchoFragment_" + id + "(_jsp_parentContext,"); out.println(" pageContext, parent, jspBody, _jsp_state,"); out.println(" _jsp_pageManager);"); out.println("}"); out.println(); out.println(); out.println("return frag;"); out.popDepth(); out.println("}"); out.println("public class _CauchoFragment_" + id + " extends com.caucho.jsp.JspFragmentSupport {"); out.pushDepth(); // out.println("private int _frag_code;"); out.println("private TagState _jsp_state;"); out.println("_CauchoFragment_" + id + "("); out.println(" javax.servlet.jsp.JspContext _jsp_parentContext,"); out.println(" com.caucho.jsp.PageContextImpl pageContext,"); out.println(" javax.servlet.jsp.tagext.JspTag parent,"); out.println(" javax.servlet.jsp.tagext.JspFragment jspBody,"); out.println(" TagState _jsp_state,"); out.println(" com.caucho.jsp.PageManager _jsp_pageManager)"); out.println("{"); out.pushDepth(); // out.println("this._frag_code = code;"); out.println("this._jsp_parentContext = _jsp_parentContext;"); out.println("this.pageContext = pageContext;"); out.println("this._jsp_env = pageContext.getELContext();"); out.println("this._jsp_parent_tag = parent;"); out.println("this._jspBody = jspBody;"); out.println("this._jsp_state = _jsp_state;"); out.println("this._jsp_pageManager = _jsp_pageManager;"); out.popDepth(); out.println("}"); generateNonValueFragment(out, frag); // frag.generateValueMethod(out); /* out.println(); out.println("protected void _jsp_invoke(JspWriter out)"); out.println(" throws Throwable"); out.println("{"); out.pushDepth(); out.popDepth(); out.println("}"); */ out.popDepth(); out.println("}"); } private void generateNonValueFragment(JspJavaWriter out, JspFragmentNode frag) throws Exception { out.println(); // out.println("private void " + frag.getFragmentName() + "(JspWriter out)"); out.println("protected void _jsp_invoke(JspWriter out)"); out.println(" throws Throwable"); out.println("{"); out.pushDepth(); HashSet<String> oldDeclaredVariables = _declaredVariables; _declaredVariables = new HashSet<String>(); try { if (frag.hasScripting()) { generateScriptingVariables(out); } frag.generatePrologueChildren(out); frag.generate(out); } finally { _declaredVariables = oldDeclaredVariables; } out.popDepth(); out.println("}"); } private void generateScriptingVariables(JspJavaWriter out) throws IOException { // jsp/103j out.println("HttpServletRequest request = this.pageContext.getRequest();"); out.println("HttpServletResponse response = this.pageContext.getResponse();"); out.println("ServletContext application = this.pageContext.getApplication();"); out.println("PageContext jspContext = this.pageContext;"); } /** * Generates the dependency methods. Since we can't assume the * underlying class is Page when the JSP page uses "extends" * each JSP page needs to generate this code. */ private void generateDepends(JspJavaWriter out) throws IOException { out.println(); // out.println("private com.caucho.java.LineMap _caucho_line_map;"); out.println("private com.caucho.make.DependencyContainer _caucho_depends"); out.println(" = new com.caucho.make.DependencyContainer();"); if (_isCacheable && ! _isUncacheable) out.println("private java.util.ArrayList _caucho_cacheDepends = new java.util.ArrayList();"); out.println(); out.println("public java.util.ArrayList<com.caucho.vfs.Dependency> _caucho_getDependList()"); out.println("{"); out.println(" return _caucho_depends.getDependencies();"); out.println("}"); out.println(); out.println("public void _caucho_addDepend(com.caucho.vfs.PersistentDependency depend)"); out.println("{"); out.pushDepth(); if (_parseState.getExtends() == null) out.println("super._caucho_addDepend(depend);"); // out.println(" com.caucho.jsp.JavaPage.addDepend(_caucho_depends, depend);"); out.println("_caucho_depends.add(depend);"); out.popDepth(); out.println("}"); out.println(); // out.println("@Override"); out.println("protected void _caucho_setNeverModified(boolean isNotModified)"); out.println("{"); // out.println(" super._caucho_setNeverModified(isNotModified);"); out.println(" _caucho_isNotModified = true;"); out.println("}"); out.println(); out.println("public boolean _caucho_isModified()"); out.println("{"); out.pushDepth(); out.println("if (_caucho_isDead)"); out.println(" return true;"); out.println(); out.println("if (_caucho_isNotModified)"); out.println(" return false;"); out.println(); out.println("if (com.caucho.server.util.CauchoSystem.getVersionId() != " + CauchoSystem.getVersionId() + "L)"); out.println(" return true;"); out.println(); ArrayList<PersistentDependency> depends; depends = new ArrayList<PersistentDependency>(); depends.addAll(_parseState.getDependList()); for (int i = 0; i < _depends.size(); i++) { PersistentDependency depend = _depends.get(i); if (! depends.contains(depend)) depends.add(depend); } if (_alwaysModified) out.println("return true;"); else if (depends.size() == 0) out.println("return false;"); else { out.println("return _caucho_depends.isModified();"); /* out.println("for (int i = _caucho_depends.size() - 1; i >= 0; i--) {"); out.pushDepth(); out.println("com.caucho.vfs.Dependency depend;"); out.println("depend = (com.caucho.vfs.Dependency) _caucho_depends.get(i);"); out.println("if (depend.isModified()) {"); out.println(" return true;"); out.println("}"); out.popDepth(); out.println("}"); out.println("return false;"); */ } out.popDepth(); out.println("}"); if (_rootNode.isStatic() && CauchoSystem.isTest()) out.println("private static long _caucho_lastModified = com.caucho.util.Alarm.getCurrentTime();"); out.println(); out.println("public long _caucho_lastModified()"); out.println("{"); out.pushDepth(); /* if (! _isCacheable || _isUncacheable) out.println("return 0;"); else { out.println("return com.caucho.jsp.Page.calculateLastModified(_caucho_depends, _caucho_cacheDepends);"); } */ if (! isGenerateStatic()) { out.println("return 0;"); } else if (CauchoSystem.isTest()) { out.println("return _caucho_lastModified;"); } else { out.println("long lastModified = 0;"); /* out.println("for (int i = _caucho_depends.size() - 1; i >= 0; i--) {"); out.pushDepth(); out.println("Object oDepend = _caucho_depends.get(i);"); out.println("if (oDepend instanceof com.caucho.vfs.Depend) {"); out.println(" com.caucho.vfs.Depend depend = (com.caucho.vfs.Depend) oDepend;"); out.println(" if (lastModified < depend.getLastModified())"); out.println(" lastModified = depend.getLastModified();"); out.println("}"); out.popDepth(); out.println("}"); */ out.println(); out.println("return lastModified;"); } out.popDepth(); out.println("}"); /* out.println(); out.println("public com.caucho.java.LineMap _caucho_getLineMap()"); out.println("{"); out.pushDepth(); out.println("return _caucho_line_map;"); out.popDepth(); out.println("}"); */ if (_parseState.getExtends() == null && ! _parseState.isTag()) { out.println(); out.println("public void destroy()"); out.println("{"); out.pushDepth(); out.println(" _caucho_isDead = true;"); out.println(" super.destroy();"); out.println("TagState tagState;"); //out.println("while ((tagState = _jsp_freeState.allocate()) != null)"); //out.println(" tagState.release();"); out.popDepth(); out.println("}"); } if (_parseState.getExtends() != null && ! _parseState.isTag()) { out.println(); out.println("public com.caucho.server.webapp.WebApp _caucho_getApplication()"); out.println("{"); out.pushDepth(); out.println(" return (com.caucho.server.webapp.WebApp) getServletConfig().getServletContext();"); out.popDepth(); out.println("}"); } printDependInit(out, depends); generateInject(out); } private boolean isGenerateStatic() { // #2548 return false; /* return (_rootNode.isStatic() && ! _parseState.isTag() && _parseState.getExtends() == null); */ } /** * Generates the normal init. */ private void generateInit(JspJavaWriter out) throws IOException { out.println(); out.println("public java.util.HashMap<String,java.lang.reflect.Method> _caucho_getFunctionMap()"); out.println("{"); out.pushDepth(); out.println("return _jsp_functionMap;"); out.popDepth(); out.println("}"); if (isTag()) out.println("static boolean _jsp_isTagInit;"); out.println(); out.println("public void caucho_init(ServletConfig config)"); out.println("{"); out.pushDepth(); if (isTag()) { out.println("if (_jsp_isTagInit)"); out.println(" return;"); out.println("_jsp_isTagInit = true;"); } out.println("try {"); out.pushDepth(); out.println("com.caucho.server.webapp.WebApp webApp"); out.println(" = (com.caucho.server.webapp.WebApp) config.getServletContext();"); if (! isTag()) { out.println("init(config);"); } out.println("if (com.caucho.jsp.JspManager.getCheckInterval() >= 0)"); out.println(" _caucho_depends.setCheckInterval(com.caucho.jsp.JspManager.getCheckInterval());"); out.println("_jsp_pageManager = webApp.getJspApplicationContext().getPageManager();"); out.println("com.caucho.jsp.TaglibManager manager = webApp.getJspApplicationContext().getTaglibManager();"); for (Taglib taglib : _tagLibraryList) { out.print("manager.addTaglibFunctions(_jsp_functionMap, \""); out.printJavaString(taglib.getPrefixString()); out.print("\", \""); out.printJavaString(taglib.getURI()); out.println("\");"); } if (! isTag()) out.println("com.caucho.jsp.PageContextImpl pageContext = new com.caucho.jsp.InitPageContextImpl(webApp, this);"); else out.println("com.caucho.jsp.PageContextImpl pageContext = new com.caucho.jsp.InitPageContextImpl(webApp, _caucho_getFunctionMap());"); for (int i = 0; i < _exprList.size(); i++) { String expr = _exprList.get(i); out.print("_caucho_expr_" + i + " = com.caucho.jsp.JspUtil.createExpr(pageContext.getELContext(), \""); out.printJavaString(expr); out.println("\");"); } for (int i = 0; i < _valueExprList.size(); i++) { ValueExpr expr = _valueExprList.get(i); out.print("_caucho_value_expr_" + i + " = com.caucho.jsp.JspUtil.createValueExpression(pageContext.getELContext(), "); out.printClass(expr.getReturnType()); out.print(".class, \""); out.printJavaString(expr.getExpressionString()); out.println("\");"); } for (int i = 0; i < _methodExprList.size(); i++) { MethodExpr expr = _methodExprList.get(i); out.print("_caucho_method_expr_" + i + " = com.caucho.jsp.JspUtil.createMethodExpression(pageContext.getELContext(), \""); out.printJavaString(expr.getExprString()); out.print("\", "); if (expr.getReturnType() != null) { out.printClass(expr.getReturnType()); out.print(".class"); } else out.print("String.class"); out.print(", new Class[] {"); Class<?> []args = expr.getArgs(); if (args != null) { for (int j = 0; j < args.length; j++) { if (j != 0) out.print(", "); out.printClass(args[j]); out.print(".class"); } } out.println("});"); } for (String tagClass : _tagFileClassList) { out.println("new " + tagClass + "().caucho_init(config);"); } out.popDepth(); out.println("} catch (Exception e) {"); out.println(" throw com.caucho.config.ConfigException.create(e);"); out.println("}"); out.popDepth(); out.println("}"); } /** * Prints the initialization methods to track dependencies. */ private void printDependInit(JspJavaWriter out, ArrayList<PersistentDependency> depends) throws IOException { out.println(); out.println("public void init(com.caucho.vfs.Path appDir)"); out.println(" throws javax.servlet.ServletException"); out.println("{"); out.pushDepth(); if (_ideHack) { out.println("_jsp_init_strings();"); } out.println("com.caucho.vfs.Path resinHome = com.caucho.server.util.CauchoSystem.getResinHome();"); out.println("com.caucho.vfs.MergePath mergePath = new com.caucho.vfs.MergePath();"); out.println("mergePath.addMergePath(appDir);"); out.println("mergePath.addMergePath(resinHome);"); out.println("com.caucho.loader.DynamicClassLoader loader;"); out.println("loader = (com.caucho.loader.DynamicClassLoader) getClass().getClassLoader();"); out.println("String resourcePath = loader.getResourcePathSpecificFirst();"); out.println("mergePath.addClassPath(resourcePath);"); MergePath classPath = new MergePath(); classPath.addClassPath(); /* XXX: the order shouldn't matter in this situation ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader instanceof DynamicClassLoader) { DynamicClassLoader loader = (DynamicClassLoader) classLoader; String resourcePath = loader.getResourcePathSpecificFirst(); classPath.addClassPath(resourcePath); } */ String srcName = _filename; if (srcName == null) srcName = "foo"; out.println("com.caucho.vfs.Depend depend;"); Path appDir = getAppDir(); for (int i = 0; i < depends.size(); i++) { PersistentDependency dependency = depends.get(i); if (dependency instanceof Depend) { Depend depend = (Depend) dependency; if (depend.getPath().isDirectory()) continue; out.print("depend = new com.caucho.vfs.Depend("); printPathDir(out, depend, depend.getPath().getFullPath(), appDir, classPath); out.println(", " + depend.getDigest() + "L, " + _requireSource + ");"); // out.println("com.caucho.jsp.JavaPage.addDepend(_caucho_depends, depend);"); out.println("_caucho_depends.add(depend);"); } else { /* out.print("com.caucho.jsp.JavaPage.addDepend(_caucho_depends, "); out.print(dependency.getJavaCreateString()); out.println(");"); */ out.print("_caucho_depends.add("); out.print(dependency.getJavaCreateString()); out.println(");"); } } if (_isCacheable && ! _isUncacheable) { for (int i = 0; i < _cacheDepends.size(); i++) { Depend depend = _cacheDepends.get(i); if (depend.getPath().isDirectory()) continue; out.print("depend = new com.caucho.vfs.Depend("); printPathDir(out, depend, depend.getPath().getFullPath(), appDir, classPath); out.println(", \"" + depend.getDigest() + "\", " + _requireSource + ");"); out.println("_caucho_cacheDepends.add((Object) depend);"); } } out.popDepth(); out.println("}"); } /** * Prints an expression to lookup the path directory */ private void printPathDir(JspJavaWriter out, Depend depend, String path, Path appDir, MergePath classPath) throws IOException { String resinHome = CauchoSystem.getResinHome().getFullPath(); String prefix = getAppDir().getFullPath(); if (prefix.length() > 1 && ! prefix.endsWith("/")) prefix = prefix + "/"; if (path.startsWith(prefix)) { String subPath = path.substring(prefix.length()); Path appPathTest = appDir.lookup(subPath); if (appPathTest.getCrc64() == depend.getPath().getCrc64()) { out.print("appDir.lookup(\""); out.printJavaString(subPath); out.print("\")"); return; } } ArrayList<Path> classPathList = classPath.getMergePaths(); for (int i = 0; i < classPathList.size(); i++) { Path dir = classPathList.get(i); prefix = dir.getFullPath(); if (! prefix.endsWith("/")) prefix = prefix + "/"; if (prefix.equals("/")) continue; else if (path.startsWith(prefix)) { String tail = path.substring(prefix.length()); if (tail.startsWith("/")) tail = tail.substring(1); Path cpPath = appDir.lookup("classpath:" + tail); if (depend.getPath().getCrc64() == cpPath.getCrc64()) { out.print("appDir.lookup(\"classpath:"); out.printJavaString(tail); out.print("\")"); return; } else { out.print("appDir.lookup(\""); out.printJavaString(depend.getPath().getURL()); out.print("\")"); return; } } } if (path.startsWith(resinHome + "/")) { path = path.substring(resinHome.length() + 1); out.print("mergePath.lookup(\""); out.printJavaString(path); out.print("\")"); } else { out.print("mergePath.lookup(\""); out.printJavaString(depend.getPath().getURL()); out.print("\")"); } } /** * Prints the tag injection. */ private void generateInject(JspJavaWriter out) throws IOException { if (_topTag == null || ! _topTag.hasChildren()) return; Iterator<TagInstance> iter = _topTag.iterator(); while (iter.hasNext()) { TagInstance tag = iter.next(); if (tag != null) generateTagInjectDecl(out, tag); } out.println(); out.println("static {"); out.pushDepth(); out.println("try {"); out.pushDepth(); iter = _topTag.iterator(); while (iter.hasNext()) { TagInstance tag = iter.next(); if (tag != null) generateTagInject(out, tag); } out.popDepth(); out.println("} catch (Exception e) {"); out.println(" e.printStackTrace();"); out.println(" throw new RuntimeException(e);"); out.println("}"); out.popDepth(); out.println("}"); } /** * Prints the tag injection. */ private void generateTagInjectDecl(JspJavaWriter out, TagInstance tag) throws IOException { /* if (tag.getAnalyzedTag() != null && tag.getAnalyzedTag().getHasInjection()) { out.println("private static com.caucho.config.j2ee.InjectProgram _jsp_inject_" + tag.getId() + ";"); }*/ Iterator<TagInstance> iter = tag.iterator(); while (iter.hasNext()) { TagInstance child = iter.next(); generateTagInjectDecl(out, child); } } /** * Prints the tag injection. */ private void generateTagInject(JspJavaWriter out, TagInstance tag) throws IOException {/* if (tag.getAnalyzedTag() != null && tag.getAnalyzedTag().getHasInjection()) { out.print("_jsp_inject_" + tag.getId() + " = "); out.println("com.caucho.config.inject.InjectManager.create().getReference(" + tag.getTagClass().getName() + ".class);"); }*/ Iterator<TagInstance> iter = tag.iterator(); while (iter.hasNext()) { TagInstance child = iter.next(); generateTagInject(out, child); } } private void generateConstantStrings(JspJavaWriter out) throws IOException { if (_strings.size() == 0) return; out.println(); Iterator<?> iter = _strings.iterator(); while (iter.hasNext()) { Object key = iter.next(); int j = _strings.get(key); if (_ideHack) out.println("private final char []_jsp_string" + j + ";"); else out.println("private final static char []_jsp_string" + j + ";"); } if (_ideHack) { out.println("private void _jsp_init_strings() {"); out.pushDepth(); } else { out.println("static {"); out.pushDepth(); } String enc = out.getWriteStream().getJavaEncoding(); if (enc == null || enc.equals("ISO8859_1")) enc = null; if (_config.isStaticEncoding() && enc != null) { out.println("try {"); out.pushDepth(); } iter = _strings.iterator(); while (iter.hasNext()) { String text = (String) iter.next(); int j = _strings.get(text); out.print("_jsp_string" + j + " = \""); for (int i = 0; i < text.length(); i++) { char ch = text.charAt(i); switch (ch) { case '\n': out.print("\\n"); break; case '\r': out.print("\\r"); break; case '"': out.print("\\\""); break; case '\\': out.print("\\\\"); break; default: out.print(ch); } } out.println("\".toCharArray();"); } if (_config.isStaticEncoding() && enc != null) { out.popDepth(); out.println("} catch (java.io.UnsupportedEncodingException e) {"); out.println(" e.printStackTrace();"); out.println("}"); } out.popDepth(); out.println("}"); } /** * Opens a write stream to the *.java file we're generating. * * @param path work directory path * * @return the write stream */ WriteStream openWriteStream() throws IOException { Path javaPath = getGeneratedPath(); WriteStream os = javaPath.openWrite(); os.setEncoding("JAVA"); return os; } Path getGeneratedPath() throws IOException { // String name = _pkg + "." + _className; Path dir = getJspCompiler().getClassDir().lookup(_workPath); Path javaPath = dir.lookup(_className + ".java"); try { javaPath.getParent().mkdirs(); } catch (Exception e) { log.log(Level.WARNING, e.toString(), e); } return javaPath; } @Override public int uniqueId() { return _uniqueId++; } public int generateJspId() { return _jspId++; } protected void addImport(String name) { } boolean hasTags() { // size() == 1 is the jsp: tags. return _tagManager.hasTags(); } /** * Returns the tag with the given qname. */ public TagInfo getTag(QName qname) throws JspParseException { return _tagManager.getTag(qname); } /** * Returns the tag with the given qname. */ public Class<?> getTagClass(QName qname) throws Exception { return _tagManager.getTagClass(qname); } public Taglib addTaglib(QName qname) throws JspParseException { return _tagManager.addTaglib(qname); } public String getSourceLines(Path source, int errorLine) { if (source == null || errorLine < 1) return ""; boolean hasLine = false; StringBuilder sb = new StringBuilder("\n\n"); ReadStream is = null; try { is = source.openRead(); is.setEncoding(_parseState.getPageEncoding()); int line = 0; String text; while ((text = is.readLine()) != null) { line++; if (errorLine - 2 <= line && line <= errorLine + 2) { sb.append(line); sb.append(": "); sb.append(text); sb.append("\n"); hasLine = true; } } } catch (IOException e) { log.log(Level.FINER, e.toString(), e); } finally { is.close(); } if (hasLine) return sb.toString(); else return ""; } public JspParseException error(String message) { JspParseException e = new JspParseException(message); e.setErrorPage(_parseState.getErrorPage()); return e; } public JspParseException error(Exception e) { JspParseException exn = new JspParseException(e); exn.setErrorPage(_parseState.getErrorPage()); return exn; } static class MethodExpr { private String _exprString; com.caucho.el.Expr _expr; Class<?> []_args; Class<?> _retType; MethodExpr(String exprString, com.caucho.el.Expr expr, Class<?> []args, Class<?> retType) { _exprString = exprString; _expr = expr; _args = args; _retType = retType; } String getExprString() { return _exprString; } com.caucho.el.Expr getExpr() { return _expr; } Class<?> []getArgs() { return _args; } Class<?> getReturnType() { return _retType; } } static class ValueExpr { private String _exprString; com.caucho.el.Expr _expr; Class<?> _retType; ValueExpr(String exprString, com.caucho.el.Expr expr, Class<?> retType) { _exprString = exprString; _expr = expr; _retType = retType; } String getExpressionString() { return _exprString; } com.caucho.el.Expr getExpr() { return _expr; } Class<?> getReturnType() { return _retType; } } static class FragmentComparator implements Comparator<JspFragmentNode> { @Override public int compare(JspFragmentNode a, JspFragmentNode b) { return getDepth(a) - getDepth(b); } private int getDepth(JspNode node) { int depth = 0; for (; node != null; node = node.getParent()) { depth++; } return depth; } } static { _primitives = new HashMap<String,String>(); _primitives.put("boolean", "boolean"); _primitives.put("byte", "byte"); _primitives.put("short", "short"); _primitives.put("char", "char"); _primitives.put("int", "int"); _primitives.put("long", "long"); _primitives.put("float", "float"); _primitives.put("double", "double"); _primitiveClasses = new HashMap<String,Class<?>>(); _primitiveClasses.put("boolean", boolean.class); _primitiveClasses.put("byte", byte.class); _primitiveClasses.put("short", short.class); _primitiveClasses.put("char", char.class); _primitiveClasses.put("int", int.class); _primitiveClasses.put("long", long.class); _primitiveClasses.put("float", float.class); _primitiveClasses.put("double", double.class); _primitiveClasses.put("void", void.class); } }