costin 01/06/16 14:06:14 Modified: jasper34/liaison/org/apache/jasper34/servlet JspEngineContext.java JspServlet.java Log: The first serious cleanup for JspServlet. I tested it and it seems to work fine ( assuming you get the right classpath :-). I'll send a mail with the details on using JspServlet, it needs jasper.jar and all required deps in the classpath ( not available in tomcat33, since the container is isolated - so you can either put it in common or in the webapp ). There are few issues regarding the use of JspServlet, the code is still far behind the interceptor - but could be used for simple things. The good news is that most of the spaghetti that ended up in JspServlet is gone, I hope most people will be able to understand the code now ( I had big problems with that ). Revision Changes Path 1.6 +56 -13 jakarta-tomcat-jasper/jasper34/liaison/org/apache/jasper34/servlet/JspEngineContext.java Index: JspEngineContext.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper34/liaison/org/apache/jasper34/servlet/JspEngineContext.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- JspEngineContext.java 2001/06/12 15:39:25 1.5 +++ JspEngineContext.java 2001/06/16 21:06:14 1.6 @@ -61,7 +61,8 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; +import java.io.*; +import java.net.*; import org.apache.jasper34.generator.*; import org.apache.jasper34.core.Compiler; @@ -99,12 +100,11 @@ HttpServletResponse res; - public JspEngineContext(ClassLoader loader, String classpath, + public JspEngineContext(String classpath, ServletContext context, String jspFile, boolean isErrPage, Options options, HttpServletRequest req, HttpServletResponse res) { - this.loader = loader; this.classpath = classpath; this.context = context; this.jspFile = jspFile; @@ -133,7 +133,8 @@ * The classpath that is passed off to the Java compiler. */ public String getClassPath() { - return ((JasperLoader)loader).getClassPath() + classpath; + // XXX Use common code, toolkit + return options.getClassPath(); } /** @@ -162,13 +163,54 @@ * this JSP? I don't think this is used right now -- akv. */ public ClassLoader getClassLoader() { + if( loader==null ) { + + try { + ClassLoader parentClassLoader=getParentLoader( context ); + File sDir=options.getScratchDir(); + + // PD will be set in the policy + // XXX get loader + URL urls[]=new URL[1]; + urls[0]=new URL( "file", null, + sDir.getAbsolutePath().replace('\\','/') + "/"); + + // XXX JDK1.1, compat + loader=new URLClassLoader( urls, parentClassLoader); + } catch( Exception ex ) { + ex.printStackTrace(); + } + + } return loader; } -// public void addJar( String jar ) throws IOException { -// loader.addJar( jar ); -// } + /** Extract parent class loader from ServletContext + */ + private ClassLoader getParentLoader(ServletContext ctx) { + ClassLoader parentClassLoader = + (ClassLoader) context.getAttribute(Constants.SERVLET_CLASS_LOADER); + if (parentClassLoader == null) + parentClassLoader = this.getClass().getClassLoader(); + + // getClass().getClassLoader() returns null in JDK 1.1.6/1.1.8 + if (parentClassLoader != null) { + ContainerLiaison.message("jsp.message.parent_class_loader_is", + new Object[] { + parentClassLoader.toString() + }, Log.DEBUG); + } + else { + ContainerLiaison.message("jsp.message.parent_class_loader_is", + new Object[] { + "<none>" + }, Log.DEBUG); + } + return parentClassLoader; + } + + /** * Are we processing something that has been declared as an * errorpage? @@ -297,7 +339,7 @@ /** * Get the full value of a URI relative to this compilations context */ - public String resolveRelativeUri(String uri) + public String resolveRelativeUri(String uri, String baseUri) { if (uri.charAt(0) == '/') { @@ -305,9 +347,9 @@ } else { - String actURI = req.getServletPath(); - String baseURI = actURI.substring(0, actURI.lastIndexOf('/')); - return baseURI + '/' + uri; + // String actURI = req.getServletPath(); + //String baseURI = actURI.substring(0, actURI.lastIndexOf('/')); + return baseUri + '/' + uri; } } @@ -349,11 +391,12 @@ implementation ( TagLibReader ). */ public void readTLD( TagLibraries libs, - TagLibraryInfoImpl tl, String prefix, String uri ) + TagLibraryInfoImpl tl, String prefix, String uri, + String uriBase ) throws IOException, JasperException { TagLibReader reader=new TagLibReader( this, libs ); - reader.readTagLib( tl, prefix, uri ); + reader.readTLD( tl, prefix, uri, uriBase ); } 1.5 +152 -381 jakarta-tomcat-jasper/jasper34/liaison/org/apache/jasper34/servlet/JspServlet.java Index: JspServlet.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-jasper/jasper34/liaison/org/apache/jasper34/servlet/JspServlet.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- JspServlet.java 2001/06/12 15:39:25 1.4 +++ JspServlet.java 2001/06/16 21:06:14 1.5 @@ -77,6 +77,7 @@ import org.apache.jasper34.core.*; import org.apache.jasper34.generator.*; import org.apache.jasper34.jsptree.*; +import org.apache.jasper34.javacompiler.*; import org.apache.jasper34.liaison.*; import org.apache.jasper34.core.Compiler; @@ -92,158 +93,20 @@ Log loghelper = Log.getLog("JASPER_LOG", "JspServlet"); - class JspServletWrapper { - Servlet theServlet; - String jspUri; - boolean isErrorPage; - // ServletWrapper will set this - Class servletClass; - - JspServletWrapper(String jspUri, boolean isErrorPage) { - this.jspUri = jspUri; - this.isErrorPage = isErrorPage; - this.theServlet = null; - } - - private void load() throws JasperException, ServletException { - try { - // Class servletClass = (Class) loadedJSPs.get(jspUri); - // This is to maintain the original protocol. - destroy(); - - theServlet = (Servlet) servletClass.newInstance(); - } catch (Exception ex) { - throw new JasperException(ex); - } - theServlet.init(JspServlet.this.config); - if (theServlet instanceof HttpJspBase) { - HttpJspBase h = (HttpJspBase) theServlet; - h.setClassLoader(JspServlet.this.parentClassLoader); - } - } - - private void loadIfNecessary(HttpServletRequest req, HttpServletResponse res) - throws JasperException, ServletException, FileNotFoundException - { - // First try context attribute; if that fails then use the - // classpath init parameter. - - // Should I try to concatenate them if both are non-null? - - String cp = (String) context.getAttribute(Constants.SERVLET_CLASSPATH); - - String accordingto; - - if (cp == null || cp.equals("")) { - accordingto = "according to the init parameter"; - cp = options.getClassPath(); - } else - accordingto = "according to the Servlet Engine"; - - ContainerLiaison.message("jsp.message.cp_is", - new Object[] { - accordingto, - cp == null ? "" : cp - }, - Log.INFORMATION); - - if ( loadJSP(jspUri, cp, isErrorPage, req, res) - || theServlet == null) { - load(); - } - } - - public void service(HttpServletRequest request, - HttpServletResponse response, - boolean precompile) - throws ServletException, IOException, FileNotFoundException - { - try { - loadIfNecessary(request, response); - - // If a page is to only to be precompiled return. - if (precompile) - return; + protected ServletContext context = null; - if (theServlet instanceof SingleThreadModel) { - // sync on the wrapper so that the freshness - // of the page is determined right before servicing - synchronized (this) { - theServlet.service(request, response); - } - } else { - theServlet.service(request, response); - } + // XXX Is it the config of JspServlet or of the jsp page ? + protected ServletConfig config; - } catch (FileNotFoundException ex) { - try { - if (insecure_TMI) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - ContainerLiaison.getString - ("jsp.error.file.not.found.TMI", - new Object[] { - ex.getMessage() - })); - } else { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - ContainerLiaison.getString - ("jsp.error.file.not.found", - new Object[] { - // Too Much Information -- ex.getMessage() - })); - } - } catch (IllegalStateException ise) { - // logs are presumed to be secure, thus the TMI info can be logged - ContainerLiaison.message(ContainerLiaison.getString - ("jsp.error.file.not.found.TMI", - new Object[] { - ex.getMessage() - }), - Log.ERROR); - // rethrow FileNotFoundException so someone higher up can handle - if (insecure_TMI) - throw ex; - else - throw new FileNotFoundException(ContainerLiaison.getString - ("jsp.error.file.not.found", - new Object[] { - // Too Much Information -- ex.getMessage() - })); - } - return; - } - } + protected String serverInfo; - public void destroy() { - if (theServlet != null) - theServlet.destroy(); - } - } - - - protected ServletContext context = null; protected Hashtable jsps = new Hashtable(); - // protected Hashtable loadedJSPs = new Hashtable(); - protected ServletConfig config; - protected ClassLoader loader; + protected Options options; - protected ClassLoader parentClassLoader; - // protected ServletEngine engine; - protected String serverInfo; - + /** Set to true to provide Too Much Information on errors */ private final boolean insecure_TMI = false; - static boolean firstTime = true; - static boolean jdk12=false; - static { - try { - Class.forName( "java.security.PrivilegedAction" ); - jdk12=true; - } catch(Throwable ex ) { - } - } - public void init(ServletConfig config) throws ServletException { @@ -253,98 +116,16 @@ this.serverInfo = context.getServerInfo(); options = new OptionsServletConfig(config, context); + // if( debug>0 ) + log("Init " + config ); - parentClassLoader = (ClassLoader) context.getAttribute(Constants.SERVLET_CLASS_LOADER); - if (parentClassLoader == null) - parentClassLoader = this.getClass().getClassLoader(); - - // getClass().getClassLoader() returns null in JDK 1.1.6/1.1.8 - if (parentClassLoader != null) { - ContainerLiaison.message("jsp.message.parent_class_loader_is", - new Object[] { - parentClassLoader.toString() - }, Log.DEBUG); - } - else { - ContainerLiaison.message("jsp.message.parent_class_loader_is", - new Object[] { - "<none>" - }, Log.DEBUG); - } - // System.out.println("JspServlet: init " + config.getServletName() ); - if( loader==null ) { - if( jdk12 ) { - try { - Class ld=Class.forName("org.apache.jasper34.servlet.JasperLoader12"); - loader=(JasperLoader)ld.newInstance(); - } catch(Throwable t ) { - loghelper.log("Loading org.apache.jasper34.servlet.JasperLoader12", t); - } - } - if( loader==null ) - loader = new JasperLoader(); - - ((JasperLoader)loader).setParentClassLoader(parentClassLoader); - ((JasperLoader)loader).setScratchDir(options.getScratchDir().toString()); - Object pd=context.getAttribute("org.apache.tomcat.protection_domain"); - ((JasperLoader)loader).setProtectionDomain( pd ); - } - if (firstTime) { - firstTime = false; - ContainerLiaison.message("jsp.message.scratch.dir.is", - new Object[] { - options.getScratchDir().toString() - }, Log.INFORMATION ); - ContainerLiaison.message("jsp.message.dont.modify.servlets", Log.INFORMATION); + // XXX each generate servlet will check that - so it works with JSPC + // and without JspServlet + if( JspFactory.getDefaultFactory() ==null ) JspFactory.setDefaultFactory(new JspFactoryImpl()); - } } - private void serviceJspFile(HttpServletRequest request, - HttpServletResponse response, String jspUri, - Throwable exception, boolean precompile) - throws ServletException, IOException - { - boolean isErrorPage = exception != null; - - JspServletWrapper wrapper = (JspServletWrapper) jsps.get(jspUri); - if (wrapper == null) { - wrapper = new JspServletWrapper(jspUri, isErrorPage); - jsps.put(jspUri, wrapper); - } - - wrapper.service(request, response, precompile); - } - - boolean preCompile(HttpServletRequest request) - throws ServletException - { - boolean precompile = false; - String precom = request.getParameter(Constants.PRECOMPILE); - String qString = request.getQueryString(); - - if (precom != null) { - if (precom.equals("true")) - precompile = true; - else if (precom.equals("false")) - precompile = false; - else { - // This is illegal. - throw new ServletException("Can't have request parameter " + - Constants.PRECOMPILE + " set to " + precom); - } - } - else if (qString != null && (qString.startsWith(Constants.PRECOMPILE) || - qString.indexOf("&" + Constants.PRECOMPILE) - != -1)) - precompile = true; - - return precompile; - } - - - public void service (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException @@ -359,34 +140,37 @@ jspUri = request.getServletPath(); else jspUri = includeUri; + + boolean precompile = isPreCompile(request); -// System.out.println("JspServletWrapper: " + includeUri + " " + -// jspUri + -// (String) request.getAttribute( -// Constants.INC_REQUEST_URI)); + // XXX This seemed to be true all the time. + // When do we have exception ?? + boolean isErrorPage = false; //exception != null; + + JspServletWrapper wrapper = (JspServletWrapper) jsps.get(jspUri); + if( debug>0 ) + log("Service " + jspUri + " " + wrapper ); + if (wrapper == null) { + wrapper = new JspServletWrapper(jspUri, isErrorPage); + jsps.put(jspUri, wrapper); + } - boolean precompile = preCompile(request); + wrapper.initWrapper( context, options, request, response); -// Log jasperLog = Constants.jasperLog; + if( wrapper.isOutDated() ) { + compileJsp(wrapper, wrapper.jspUri, wrapper.isErrorPage, + request, response); + } -// if (jasperLog != null && -// jasperLog.getLevel() >= Log.INFORMATION) -// { -// jasperLog.log("JspEngine --> "+jspUri); -// jasperLog.log("\t ServletPath: "+request.getServletPath()); -// jasperLog.log("\t PathInfo: "+request.getPathInfo()); -// jasperLog.log("\t RealPath: " -// +getServletConfig().getServletContext().getRealPath(jspUri)); -// jasperLog.log("\t RequestURI: "+request.getRequestURI()); -// jasperLog.log("\t QueryString: "+request.getQueryString()); -// jasperLog.log("\t Request Params: "); -// Enumeration e = request.getParameterNames(); -// while (e.hasMoreElements()) { -// String name = (String) e.nextElement(); -// jasperLog.log("\t\t "+name+" = "+request.getParameter(name)); -// } -// } - serviceJspFile(request, response, jspUri, null, precompile); + + // If a page is to only to be precompiled return. + if (precompile) + return; + + wrapper.service(request, response); + + } catch (FileNotFoundException ex) { + handleFileNotFoundException( ex, response ); } catch (RuntimeException e) { throw e; } catch (ServletException e) { @@ -396,17 +180,94 @@ } catch (Throwable e) { throw new ServletException(e); } + } - // It's better to throw the exception - we don't - // know if we can deal with sendError ( buffer may be - // commited ) - // catch (Throwable t) { - // unknownException(response, t); - // } + void compileJsp(JspServletWrapper jsw,String jspUri, boolean isErrorPage, + HttpServletRequest req, HttpServletResponse res) + throws JasperException, FileNotFoundException + { + synchronized ( this ) { + try { + // second check - maybe it was compiled while we + // waited for the sync + if ( ! jsw.isOutDated() ) + return; + + Compiler compiler = new Compiler(jsw.containerL); + compiler.jsp2java( jsw.pageInfo ); + String javaFile= + jsw.pageInfo.getMangler().getJavaFileName(); + + JavaCompiler javaC= + compiler.createJavaCompiler( jsw.pageInfo ); + compiler.prepareCompiler( javaC, jsw.pageInfo ); + boolean status = javaC.compile( javaFile ); + + if (status == false) { + String msg = javaC.getCompilerMessage(); + throw new JasperException("Unable to compile " + msg); + // XXX remember this - until the file is changed !! + } + + // remove java file if !keepgenerated, etc + compiler.postCompile(jsw.pageInfo); + + if( jsw.theServlet == null) { + // A (re)load happened - need to init the servlet + jsw.load( this.config ); + } + } catch (ClassNotFoundException cex) { + throw new JasperException( + ContainerLiaison.getString("jsp.error.unable.load"),cex); + } catch (FileNotFoundException ex) { + throw ex; + } catch (JasperException ex) { + throw ex; + } catch (Exception ex) { + throw new JasperException( + ContainerLiaison.getString("jsp.error.unable.compile"), ex); + } + } + } + + // XXX Do we need all this ??? + private void handleFileNotFoundException( IOException ex, + HttpServletResponse response) + throws IOException, IllegalStateException + { + try { + if (insecure_TMI) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + ContainerLiaison.getString + ("jsp.error.file.not.found.TMI", + new Object[] { ex.getMessage() })); + } else { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + ContainerLiaison.getString + ("jsp.error.file.not.found", + new Object[] {})); + } + } catch (IllegalStateException ise) { + // logs are presumed to be secure, + // thus the TMI info can be logged + ContainerLiaison.message(ContainerLiaison.getString + ("jsp.error.file.not.found.TMI", + new Object[] { ex.getMessage()}), + Log.ERROR); + // rethrow FileNotFoundException so someone higher + // up can handle + if (insecure_TMI) + throw ex; + else + throw new FileNotFoundException(ContainerLiaison.getString + ("jsp.error.file.not.found", + new Object[] {})); + } } + /** Destroy all generated Jsp Servlets + */ public void destroy() { - // if (Constants.jasperLog != null) ContainerLiaison.message("JspServlet.destroy()", Log.INFORMATION); Enumeration servlets = jsps.elements(); @@ -414,133 +275,43 @@ ((JspServletWrapper) servlets.nextElement()).destroy(); } - /* Check if we need to reload a JSP page. - * - * Side-effect: re-compile the JSP page. - * - * @param classpath explicitly set the JSP compilation path. - * @return true if JSP files is newer - */ - boolean loadJSP(String jspUri, String classpath, - boolean isErrorPage, HttpServletRequest req, HttpServletResponse res) - throws JasperException, FileNotFoundException - { - // Loader knows how to set the right priviledges, and call - // doLoadeJsp - return ((JasperLoader)loader).loadJSP( this,jspUri, classpath, isErrorPage, req, res ); - } - + + // -------------------- Utils -------------------- - /* Check if we need to reload a JSP page. - * - * Side-effect: re-compile the JSP page. - * - * @param classpath explicitly set the JSP compilation path. - * @return true if JSP files is newer + /** Detect if we're in a precompile request */ - protected boolean doLoadJSP(String jspUri, String classpath, - boolean isErrorPage, HttpServletRequest req, HttpServletResponse res) - throws JasperException, FileNotFoundException + private boolean isPreCompile(HttpServletRequest request) + throws ServletException { - JspServletWrapper jsw=(JspServletWrapper) jsps.get(jspUri); - if( jsw==null ) { - throw new JasperException("Can't happen - JspServletWrapper=null"); - } - // Class jspClass = (Class) loadedJSPs.get(jspUri); - boolean firstTime = jsw.servletClass == null; - JspEngineContext ctxt = new JspEngineContext(loader, classpath, - context, jspUri, - isErrorPage, options, - req, res); - - boolean outDated = false; - ContainerLiaison containerL=ctxt; - - Compiler compiler = new Compiler(ctxt); - //compiler.setJavaCompiler(ctxt.getJavaCompiler()); - - ManglerOld mangler=new ManglerOld(); - JspPageInfo pageInfo=new JspPageInfo( ctxt, options, - mangler ); - - pageInfo.setJspFile( jspUri ); - pageInfo.setErrorPage( isErrorPage ); - - mangler.init(pageInfo.getJspFile(), containerL.getOutputDir()); - // compiler.setMangler( mangler ); - + boolean precompile = false; + String precom = request.getParameter(Constants.PRECOMPILE); + String qString = request.getQueryString(); - try { - outDated = isOutDated( containerL, pageInfo.getJspFile(), mangler); - if ( (jsw.servletClass == null) || outDated ) { - synchronized ( this ) { - if ((jsw.servletClass == null) || - ( isOutDated(containerL, pageInfo.getJspFile(), - mangler) )) { - outDated = compiler.compile(pageInfo, - ctxt.getJavaCompiler()); - } - } - } - } catch (FileNotFoundException ex) { - compiler.removeGeneratedFiles(pageInfo); - throw ex; - } catch (JasperException ex) { - throw ex; - } catch (Exception ex) { - throw new JasperException(ContainerLiaison.getString("jsp.error.unable.compile"), - ex); - } - - // Reload only if it's outdated - if((jsw.servletClass == null) || outDated) { - try { -// if( null ==ctxt.getServletClassName() ) { -// compiler.computeServletClassName(); -// } - jsw.servletClass = - loader.loadClass(pageInfo.getFullClassName()); - //loadClass(ctxt.getFullClassName(), true); - } catch (ClassNotFoundException cex) { - throw new JasperException(ContainerLiaison.getString("jsp.error.unable.load"), - cex); + if (precom != null) { + if (precom.equals("true")) + precompile = true; + else if (precom.equals("false")) + precompile = false; + else { + // This is illegal. + throw new ServletException("Can't have request parameter " + + Constants.PRECOMPILE + + " set to " + precom); } - - // loadedJSPs.put(jspUri, jspClass); - } - - return outDated; + } else if (qString != null && + (qString.startsWith(Constants.PRECOMPILE) || + qString.indexOf("&" + Constants.PRECOMPILE) != -1)) + precompile = true; + + return precompile; } + - /** - * Determines whether the current JSP class is older than the JSP file - * from whence it came - */ - public boolean isOutDated(ContainerLiaison containerL, String jspS, - Mangler mangler) - { - boolean outDated=false; - File jsp=new File( jspS ); - File jspReal = null; - - String realPath = containerL.getRealPath(jsp.getPath()); - if (realPath == null) - return true; + private int debug=10; + public void log( String s ) { + System.out.println("JspServlet: " + s ); + } - jspReal = new File(realPath); - - if(!jspReal.exists()){ - return true; - } - - File classFile = new File(mangler.getClassFileName()); - if (classFile.exists()) { - outDated = classFile.lastModified() < jspReal.lastModified(); - } else { - outDated = true; - } - return outDated; - } }