You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2001/05/28 04:18:59 UTC
cvs commit: jakarta-tomcat-jasper/jasper34/liaison/org/apache/jasper34/tomcat33 JasperEngineContext.java JasperOptionsImpl.java JspInterceptor.java
costin 01/05/27 19:18:59
Added: jasper34/liaison/org/apache/jasper34/tomcat33
JasperEngineContext.java JasperOptionsImpl.java
JspInterceptor.java
Log:
Added tomcat33 specific interface ( will be compiled only if 33 is detected).
This is few times faster than the servlet and the default for 3.3.
Revision Changes Path
1.1 jakarta-tomcat-jasper/jasper34/liaison/org/apache/jasper34/tomcat33/JasperEngineContext.java
Index: JasperEngineContext.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.jasper34.tomcat33;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.jasper34.generator.*;
import org.apache.jasper34.generator.Compiler;
import org.apache.jasper34.core.*;
import org.apache.jasper34.runtime.*;
import java.util.*;
import java.io.*;
import java.net.*;
//import org.apache.jasper.JspCompilationContext;
/** Alternative implementation of JspCompilationContext ( in addition
to the servlet and standalone ). Used by JspInterceptor - but
it's in no way specific to tomcat.
*/
public class JasperEngineContext implements JspCompilationContext {
JspReader reader;
ServletWriter writer;
ServletContext context;
ClassLoader loader;
boolean isErrPage;
String jspFile;
String servletClassName;
String servletPackageName;
String servletJavaFileName;
String contentType;
Options options;
String cpath; // for compiling JSPs.
ServletContext sctx;
String outputDir;
public JasperEngineContext()
{
}
public void setClassPath( String s ) {
cpath=s;
}
/**
* The classpath that is passed off to the Java compiler.
*/
public String getClassPath() {
return cpath;
}
/**
* Get the input reader for the JSP text.
*/
public JspReader getReader() {
if( debug>0 ) log("getReader " + reader );
return reader;
}
/**
* Where is the servlet being generated?
*/
public ServletWriter getWriter() {
if( debug>0 ) log("getWriter " + writer );
return writer;
}
public void setServletContext( Object o ) {
sctx=(ServletContext)o;
}
/**
* Get the ServletContext for the JSP we're processing now.
*/
public ServletContext getServletContext() {
if( debug>0 ) log("getCtx " + sctx );
return sctx;
}
/**
* What class loader to use for loading classes while compiling
* this JSP? I don't think this is used right now -- akv.
*/
public ClassLoader getClassLoader() {
if( debug>0 ) log("getLoader " + loader );
return loader;
}
public void setClassLoader( ClassLoader cl ) {
loader=cl;
}
public void addJar( String jar ) throws IOException {
if( debug>0 ) log("Add jar " + jar);
//loader.addJar( jar );
}
/**
* Are we processing something that has been declared as an
* errorpage?
*/
public boolean isErrorPage() {
if( debug>0 ) log("isErrorPage " + isErrPage );
return isErrPage;
}
/**
* What is the scratch directory we are generating code into?
* FIXME: In some places this is called scratchDir and in some
* other places it is called outputDir.
*/
public String getOutputDir() {
if( debug>0 ) log("getOutputDir " + outputDir );
return outputDir;
}
public void setOutputDir(String s ) {
outputDir=s;
}
/**
* Path of the JSP URI. Note that this is not a file name. This is
* the context rooted URI of the JSP file.
*/
public String getJspFile() {
if( debug>0 ) log("getJspFile " + jspFile);
return jspFile;
}
public void setJspFile( String s ) {
jspFile=s;
}
/**
* Just the class name (does not include package name) of the
* generated class.
*/
public String getServletClassName() {
if( debug>0 ) log("getServletClassName " + servletClassName);
return servletClassName;
}
public void setServletClassName( String s ) {
servletClassName=s;
}
/**
* The package name into which the servlet class is generated.
*/
public String getServletPackageName() {
if( debug>0 ) log("getServletPackageName " +
servletPackageName );
return servletPackageName;
}
/**
* Utility method to get the full class name from the package and
* class name.
*/
public final String getFullClassName() {
if( debug>0 ) log("getServletPackageName " +
servletPackageName + "." + servletClassName);
if (servletPackageName == null)
return servletClassName;
return servletPackageName + "." + servletClassName;
}
/**
* Full path name of the Java file into which the servlet is being
* generated.
*/
public String getServletJavaFileName() {
if( debug>0 ) log("getServletPackageName " +
servletPackageName + "." + servletClassName);
return servletJavaFileName;
}
/**
* Are we keeping generated code around?
*/
public boolean keepGenerated() {
return options.getKeepGenerated();
}
/**
* What's the content type of this JSP? Content type includes
* content type and encoding.
*/
public String getContentType() {
return contentType;
}
/**
* Get hold of the Options object for this context.
*/
public Options getOptions() {
return options;
}
public void setOptions(Options options) {
this.options=options;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public void setReader(JspReader reader) {
this.reader = reader;
}
public void setWriter(ServletWriter writer) {
this.writer = writer;
}
public void setServletPackageName(String servletPackageName) {
this.servletPackageName = servletPackageName;
}
public void setServletJavaFileName(String servletJavaFileName) {
this.servletJavaFileName = servletJavaFileName;
}
public void setErrorPage(boolean isErrPage) {
this.isErrPage = isErrPage;
}
public Compiler createCompiler() throws JasperException {
if( debug>0 ) log("createCompiler ");
return null;
}
public String resolveRelativeUri(String uri)
{
if( debug>0 ) log("resolveRelativeUri " + uri);
if (uri.charAt(0) == '/') {
return uri;
} else {
String baseURI = jspFile.substring(0, jspFile.lastIndexOf('/'));
return baseURI + '/' + uri;
}
}
public java.io.InputStream getResourceAsStream(String res)
{
if( debug>0 ) log("getResourceAsStream " + res);
return sctx.getResourceAsStream(res);
}
/**
* Gets the actual path of a URI relative to the context of
* the compilation.
*/
public String getRealPath(String path)
{
if( debug>0 ) log("getRealPath " + path + " = " +
sctx.getRealPath( path ));
return sctx.getRealPath( path );
}
// development tracing
private static int debug=0;
private void log( String s ) {
System.out.println("JasperEngineContext: "+ s);
}
}
1.1 jakarta-tomcat-jasper/jasper34/liaison/org/apache/jasper34/tomcat33/JasperOptionsImpl.java
Index: JasperOptionsImpl.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.jasper34.tomcat33;
import java.util.*;
import java.io.*;
import java.net.*;
import org.apache.jasper34.core.*;
//import org.apache.jasper.Options;
/** Another implementation of Options, backed by a Properties file
* and with no external dependencies.
*/
public class JasperOptionsImpl implements Options {
static final String ieClassId =
"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93";
// cache
private Class jspCompilerPlugin = null;
// special property.
private Object protectionDomain;
Properties args;
public JasperOptionsImpl( Properties args ) {
this.args=args;
}
// -------------------- Options implementation --------------------
public boolean getKeepGenerated() {
return s2b( args.getProperty("keepgenerated", "true") );
}
public String getJavaEncoding() {
return args.getProperty("javaEncoding", "UTF8");
}
public boolean getLargeFile() {
return s2b( args.getProperty("largefile", "false"));
}
public boolean getMappedFile() {
return s2b( args.getProperty("mappedfile"));
}
public boolean getSendErrorToClient() {
return s2b( args.getProperty( "sendErrToClient" ));
}
public boolean getClassDebugInfo() {
return s2b( args.getProperty( "classDebugInfo" ));
}
public String getIeClassId() {
return args.getProperty( "ieClassId" , ieClassId);
}
public File getScratchDir() {
if( debug>0 ) log("Options: getScratchDir " );
return new File( args.getProperty( "scratchdir" ));
}
public final Object getProtectionDomain() {
if( debug>0 ) log("Options: GetPD" );
return protectionDomain;
}
public String getClassPath() {
if( debug>0 ) log("Options: GetCP " );
return args.getProperty( "classpath" );
}
public Class getJspCompilerPlugin() {
if( debug>0 ) log("Options: getJspCompilerPlugin " );
if( jspCompilerPlugin!= null ) return jspCompilerPlugin;
String type=args.getProperty( "jspCompilerPlugin" );
if( type != null ) {
try {
jspCompilerPlugin=Class.forName(type);
} catch(Exception ex ) {
ex.printStackTrace();
}
}
return jspCompilerPlugin;
}
public String getJspCompilerPath() {
return args.getProperty( "jspCompilerPath" );
}
// -------------------- Setters --------------------
public void setProtectionDomain( Object pd ) {
protectionDomain=pd;
}
// --------------------
private boolean s2b( String s ) {
return new Boolean( s ).booleanValue();
}
// trace for development purpose --------------------
private static int debug=0;
private void log(String s) {
System.err.println(s);
}
}
1.1 jakarta-tomcat-jasper/jasper34/liaison/org/apache/jasper34/tomcat33/JspInterceptor.java
Index: JspInterceptor.java
===================================================================
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.jasper34.tomcat33;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.HttpJspPage;
import javax.servlet.jsp.JspFactory;
import java.util.*;
import java.io.*;
import java.net.*;
import org.apache.tomcat.util.log.Log;
import org.apache.tomcat.util.res.StringManager;
import org.apache.tomcat.util.depend.*;
import org.apache.tomcat.util.compat.*;
import org.apache.jasper34.core.*;
import org.apache.jasper34.runtime.*;
import org.apache.jasper34.generator.*;
import org.apache.jasper34.generator.Compiler;
import org.apache.tomcat.core.*;
import org.apache.tomcat.facade.*;
/**
* Plug in the JSP engine (a.k.a Jasper)!
* Tomcat uses a "built-in" mapping for jsps ( *.jsp -> jsp ). "jsp"
* can be either a real servlet (JspServlet) that compiles the jsp
* and include the resource, or we can "intercept" and do the
* compilation and mapping in requestMap stage.
*
* JspInterceptor will be invoked once per jsp, and will add an exact
* mapping - all further invocation are identical with servlet invocations
* with direct maps, with no extra overhead.
*
* Future - better abstraction for jsp->java converter ( jasper ), better
* abstraction for java->class, plugin other jsp implementations,
* better scalability.
*
* @author Anil K. Vijendran
* @author Harish Prabandham
* @author Costin Manolache
*/
public class JspInterceptor extends BaseInterceptor {
static final String JIKES="org.apache.jasper.compiler.JikesJavaCompiler";
static final String JSP_SERVLET="org.apache.jasper34.servlet.JspServlet";
Properties args=new Properties(); // args for jasper
boolean useJspServlet=false;
String jspServletCN=JSP_SERVLET;
String runtimePackage;
// -------------------- Jasper options --------------------
// Options that affect jasper functionality. Will be set on
// JspServlet ( if useJspServlet="true" ) or TomcatOptions.
// IMPORTANT: periodically test for new jasper options
/**
* Are we keeping generated code around?
*/
public void setKeepGenerated( String s ) {
args.put( "keepgenerated", s );
}
/**
* Are we supporting large files?
*/
public void setLargeFile( String s ) {
args.put( "largefile", s );
}
/**
* Are we supporting HTML mapped servlets?
*/
public void setMappedFile( String s ) {
args.put( "mappedfile", s );
}
/**
* Should errors be sent to client or thrown into stderr?
*/
public void setSendErrToClient( String s ) {
args.put( "sendErrToClient", s );
}
/**
* Class ID for use in the plugin tag when the browser is IE.
*/
public void setIEClassId( String s ) {
args.put( "ieClassId", s );
}
/**
* What classpath should I use while compiling the servlets
* generated from JSP files?
*/
public void setClassPath( String s ) {
args.put( "classpath", s );
}
/**
* What is my scratch dir?
*/
public void setScratchdir( String s ) {
args.put( "scratchdir", s );
}
/**
* Path of the compiler to use for compiling JSP pages.
*/
public void setJspCompilerPath( String s ) {
args.put( "jspCompilerPath", s );
}
/**
* What compiler plugin should I use to compile the servlets
* generated from JSP files?
* @deprecated Use setJavaCompiler instead
*/
public void setJspCompilerPlugin( String s ) {
args.put( "jspCompilerPlugin", s );
}
/** Include debug information in generated classes
*/
public void setClassDebugInfo( String s ) {
args.put("classDebugInfo", s );
}
public void setProperty( String n, String v ) {
args.put( n, v );
}
// -------------------- JspInterceptor properties --------------------
/** Use the old JspServlet to execute Jsps, instead of the
new code. Note that init() never worked (AFAIK) and it'll
be slower - but given the stability of JspServlet it may
be a safe option. This will significantly slow down jsps.
Default is false.
*/
public void setUseJspServlet( boolean b ) {
useJspServlet=b;
}
/** Specify the implementation class of the jsp servlet.
*/
public void setJspServlet( String s ) {
jspServletCN=s;
}
/**
* What compiler should I use to compile the servlets
* generated from JSP files? Default is "javac" ( you can use
* "jikes" as a shortcut ).
*/
public void setJavaCompiler( String type ) {
if( "jikes".equals( type ) )
type=JIKES;
if( "javac".equals( type ) )
type="org.apache.jasper.compiler.SunJavaCompiler";
args.put( "jspCompilerPlugin", type );
}
int pageContextPoolSize=JspFactoryImpl.DEFAULT_POOL_SIZE;
/** Set the PageContext pool size for jasper factory.
0 will disable pooling of PageContexts.
*/
public void setPageContextPoolSize(int i) {
pageContextPoolSize=i;
}
/** The generator will produce code using a different
runtime ( default is org.apache.jasper.runtime ).
The runtime must use the same names for classes as the
default one, so the code will compile.
*/
public void setRuntimePackage(String rp ) {
runtimePackage=rp;
}
// -------------------- Hooks --------------------
/**
* Jasper-specific initializations, add work dir to classpath,
*/
public void addContext(ContextManager cm, Context ctx)
throws TomcatException
{
if( runtimePackage!=null ) {
Constants.JSP_RUNTIME_PACKAGE=runtimePackage;
Constants.JSP_SERVLET_BASE=runtimePackage+".HttpJspBase";
}
JspFactoryImpl factory=new JspFactoryImpl(pageContextPoolSize);
JspFactory.setDefaultFactory(factory);
// jspServlet uses it's own loader. We need to add workdir
// to the context classpath to use URLLoader and normal
// operation
// XXX alternative: use WEB-INF/classes for generated files
if( ! useJspServlet ) {
try {
// Note: URLClassLoader in JDK1.2.2 doesn't work with file URLs
// that contain '\' characters. Insure only '/' is used.
// jspServlet uses it's own mechanism
URL url=new URL( "file", null,
ctx.getWorkDir().getAbsolutePath().replace('\\','/') + "/");
ctx.addClassPath( url );
if( debug > 9 ) log( "Added to classpath: " + url );
} catch( MalformedURLException ex ) {
}
}
}
/** Do the needed initialization if jspServlet is used.
* It must be called after Web.xml is read ( WebXmlReader ).
*/
public void contextInit(Context ctx)
throws TomcatException
{
if( useJspServlet ) {
// prepare jsp servlet.
Handler jasper=ctx.getServletByName( "jsp" );
if ( debug>10) log( "Got jasper servlet " + jasper );
ServletHandler jspServlet=(ServletHandler)jasper;
if( jspServlet.getServletClassName() == null ) {
log( "Jsp already defined in web.xml " +
jspServlet.getServletClassName() );
return;
}
if( debug>-1)
log( "jspServlet=" + jspServlet.getServletClassName());
Enumeration enum=args.keys();
while( enum.hasMoreElements() ) {
String s=(String)enum.nextElement();
String v=(String)args.get(s);
if( debug>0 ) log( "Setting " + s + "=" + v );
jspServlet.getServletInfo().addInitParam(s, v );
}
if( debug > 0 ) {
//enable jasperServlet logging
log( "Seetting debug on jsp servlet");
Constants.jasperLog= loghelper;
// org.apache.jasper.Constants.jasperLog.
// setVerbosityLevel("debug");
}
jspServlet.setServletClassName(jspServletCN);
} else {
ctx.addServlet( new JspPrecompileH());
}
}
/** Set the HttpJspBase classloader before init,
* as required by Jasper
*/
public void preServletInit( Context ctx, Handler sw )
throws TomcatException
{
if( ! (sw instanceof ServletHandler) )
return;
try {
// requires that everything is compiled
Servlet theServlet = ((ServletHandler)sw).getServlet();
if (theServlet instanceof HttpJspBase) {
if( debug > 9 )
log( "PreServletInit: HttpJspBase.setParentClassLoader" +
sw );
HttpJspBase h = (HttpJspBase) theServlet;
h.setClassLoader(ctx.getClassLoader());
}
} catch(Exception ex ) {
throw new TomcatException( ex );
}
}
//-------------------- Main hook - compile the jsp file if needed
/** Detect if the request is for a JSP page and if it is find
the associated servlet name and compile if needed.
That insures that init() will take place on the equivalent
servlet - and behave exactly like a servlet.
A request is for a JSP if:
- the handler is a ServletHandler ( i.e. defined in web.xml
or dynamically loaded servlet ) and it has a "path" instead of
class name
- the handler has a special name "jsp". That means a *.jsp -> jsp
needs to be defined. This is a tomcat-specific mechanism ( not
part of the standard ) and allow users to associate other extensions
with JSP by using the "fictious" jsp handler.
An (cleaner?) alternative for mapping other extensions would be
to set them on JspInterceptor.
*/
public int requestMap( Request req ) {
if( useJspServlet ) {
// no further processing - jspServlet will take care
// of the processing as before ( all processing
// will happen in the handle() pipeline.
return 0;
}
Handler wrapper=req.getHandler();
if( wrapper==null )
return 0;
// It's not a jsp if it's not "*.jsp" mapped or a servlet
if( (! "jsp".equals( wrapper.getName())) &&
(! (wrapper instanceof ServletHandler)) ) {
return 0;
}
ServletHandler handler=null;
String jspFile=null;
// There are 2 cases: extension mapped and exact map with
// a <servlet> with file-name declaration
// note that this code is called only the first time
// the jsp page is called - all other calls will treat the jsp
// as a regular servlet, nothing is special except the initial
// processing.
// XXX deal with jsp_compile
if( "jsp".equals( wrapper.getName())) {
// if it's an extension mapped file, construct and map a handler
jspFile=req.servletPath().toString();
// extension mapped jsp - define a new handler,
// add the exact mapping to avoid future overhead
handler= mapJspPage( req.getContext(), jspFile );
req.setHandler( handler );
} else if( wrapper instanceof ServletHandler) {
// if it's a simple servlet, we don't care about it
handler=(ServletHandler)wrapper;
jspFile=handler.getServletInfo().getJspFile();
if( jspFile==null )
return 0; // not a jsp
}
// if it's a jsp_precompile request, don't execute - just
// compile ( if needed ). Since we'll compile the jsp on
// the first request the only special thing is to not
// execute the jsp if jsp_precompile param is in parameters.
String qString=req.queryString().toString();
// look for ?jsp_precompile or &jsp_precompile
// quick test to see if we need to worry about params
// ( preserve lazy eval for parameters )
boolean pre_compile=false;
int i=(qString==null) ? -1: qString.indexOf( "jsp_precompile" );
if( i>= 0 ) {
// Probably we are in the problem case.
req.parameters().handleQueryParameters();
String p=req.parameters().getParameter( "jsp_precompile");
if( p==null || p.equalsIgnoreCase("true")) {
pre_compile=true;
}
}
// Each .jsp file is compiled to a servlet, and will
// have a dependency to check if it's expired
Dependency dep= handler.getServletInfo().getDependency();
if( dep!=null && ! dep.isExpired() ) {
// if the jspfile is older than the class - we're ok
// this happens if the .jsp file was compiled in a previous
// run of tomcat.
return 0;
}
// we need to compile... ( or find previous .class )
JasperLiaison liasion=new JasperLiaison(getLog(), debug);
liasion.processJspFile(req, jspFile, handler, args);
if( pre_compile ) {
// we may have compiled the page ( if needed ), but
// we can't execute it. The handler will just
// report that we detected the trick.
// Future: detail information about compile results
// and if indeed we had to do something or not
req.setHandler( ctx.
getServletByName( "tomcat.jspPrecompileHandler"));
}
return 0;
}
// -------------------- Utils --------------------
private static final String SERVLET_NAME_PREFIX="TOMCAT/JSP";
/** Add an exact map that will avoid *.jsp mapping and intermediate
* steps. It's equivalent with declaring
* <servlet-name>tomcat.jsp.[uri]</>
* <servlet-mapping><servlet-name>tomcat.jsp.[uri]</>
* <url-pattern>[uri]</></>
*/
private ServletHandler mapJspPage( Context ctx, String uri)
{
String servletName= SERVLET_NAME_PREFIX + uri;
if( debug>0)
log( "mapJspPage " + ctx + " " + " " + servletName + " " + uri );
Handler h=ctx.getServletByName( servletName );
if( h!= null ) {
log( "Name already exists " + servletName +
" while mapping " + uri);
return (ServletHandler)h; // exception ?
}
ServletHandler wrapper=new ServletHandler();
wrapper.setModule( this );
wrapper.setContext(ctx);
wrapper.setName(servletName);
wrapper.getServletInfo().setJspFile( uri );
// add the mapping - it's a "invoker" map ( i.e. it
// can be removed to keep memory under control.
// The memory usage is smaller than JspSerlvet anyway, but
// can be further improved.
try {
ctx.addServlet( wrapper );
ctx.addServletMapping( uri ,
servletName );
if( debug > 0 )
log( "Added mapping " + uri + " path=" + servletName );
} catch( TomcatException ex ) {
log("mapJspPage: ctx=" + ctx +
", servletName=" + servletName, ex);
return null;
}
return wrapper;
}
}
// -------------------- Jsp_precompile handler --------------------
/** What to do for jsp precompile
*/
class JspPrecompileH extends Handler {
static StringManager sm=StringManager.
getManager("org.apache.tomcat.resources");
JspPrecompileH() {
name="tomcat.jspPrecompileHandler";
}
public void doService(Request req, Response res)
throws Exception
{
res.setContentType("text/html");
String msg="<h1>Jsp Precompile Done</h1>";
res.setContentLength(msg.length());
res.getBuffer().write( msg );
}
}
// -------------------- The main Jasper Liaison --------------------
final class JasperLiaison {
Log log;
final int debug;
JasperLiaison( Log log, int debug ) {
this.log=log;
this.debug=debug;
}
/** Generate mangled names, check for previous versions,
* generate the .java file, compile it - all the expensive
* operations. This happens only once ( or when the jsp file
* changes ).
*/
int processJspFile(Request req, String jspFile,
ServletHandler handler, Properties args)
{
// ---------- Expensive part - compile and load
// If dep==null, the handler was never used - we need
// to either compile it or find the previous compiled version
// If dep.isExpired() we need to recompile.
if( debug > 10 ) log.log( "Before compile sync " + jspFile );
synchronized( handler ) {
// double check - maybe another thread did that for us
Dependency dep= handler.getServletInfo().getDependency();
if( dep!=null && ! dep.isExpired() ) {
// if the jspfile is older than the class - we're ok
return 0;
}
Context ctx=req.getContext();
// Mangle the names - expensive operation, but nothing
// compared with a compilation :-)
JasperMangler mangler=
new JasperMangler(ctx.getWorkDir().getAbsolutePath(),
ctx.getAbsolutePath(),
jspFile );
// register the handler as dependend of the jspfile
if( dep==null ) {
dep=setDependency( ctx, mangler, handler );
// update the servlet class name
handler.setServletClassName( mangler.getServletClassName() );
// check again - maybe we just found a compiled class from
// a previous run
if( ! dep.isExpired() )
return 0;
}
// if( debug > 3)
ctx.log( "Compiling: " + jspFile + " to " +
mangler.getServletClassName());
//XXX old servlet - destroy();
// jump version number - the file needs to be recompiled
// reset the handler error, un-initialize the servlet
handler.setErrorException( null );
handler.setState( Handler.STATE_ADDED );
// Move to the next class name
mangler.nextVersion();
// record time of attempted translate-and-compile
// if the compilation fails, we'll not try again
// until the jsp file changes
dep.setLastModified( System.currentTimeMillis() );
// Update the class name in wrapper
if( debug> 1 )
log.log( "Update class Name " + mangler.getServletClassName());
handler.setServletClassName( mangler.getServletClassName() );
try {
Options options=new JasperOptionsImpl(args);
JspCompilationContext ctxt=createCompilationContext(req,
jspFile,
options,
mangler);
jsp2java( mangler, ctxt );
javac( options, ctxt, mangler );
if(debug>0)log.log( "Generated " +
mangler.getClassFileName() );
} catch( Exception ex ) {
if( ctx!=null )
ctx.log("compile error: req="+req, ex);
else
log.log("compile error: req="+req, ex);
handler.setErrorException(ex);
handler.setState(Handler.STATE_DISABLED);
// until the jsp cahnges, when it'll be enabled again
return 500;
}
dep.setExpired( false );
}
return 0;
}
/** Convert the .jsp file to a java file, then compile it to class
*/
void jsp2java(JasperMangler mangler, JspCompilationContext ctxt)
throws Exception
{
if( debug > 0 ) log.log( "Generating " + mangler.getJavaFileName());
// make sure we have the directories
String javaFileName=mangler.getJavaFileName();
File javaFile=new File(javaFileName);
// make sure the directory is created
new File( javaFile.getParent()).mkdirs();
Compiler compiler=new Compiler(ctxt);
compiler.setMangler( mangler );
// we will compile ourself
compiler.setJavaCompiler( null );
synchronized ( mangler ) {
compiler.compile();
}
if( debug > 0 ) {
File f = new File( mangler.getJavaFileName());
log.log( "Created file : " + f + " " + f.lastModified());
}
}
String javaEncoding = "UTF8"; // perhaps debatable?
static String sep = System.getProperty("path.separator");
private void prepareCompiler( JavaCompiler javac,
Options options,
JspCompilationContext ctxt )
throws JasperException
{
String compilerPath = options.getJspCompilerPath();
if (compilerPath != null)
javac.setCompilerPath(compilerPath);
javac.setClassDebugInfo(options.getClassDebugInfo());
javac.setEncoding(javaEncoding);
String cp=System.getProperty("java.class.path")+ sep +
ctxt.getClassPath() + sep + ctxt.getOutputDir();
javac.setClasspath( cp );
javac.setOutputDir(ctxt.getOutputDir());
if( debug>5) log.log( "ClassPath " + cp);
}
static boolean tryJikes=true;
static Class jspCompilerPlugin = null;
/** Compile a java to class. This should be moved to util, togheter
with JavaCompiler - it's a general purpose code, no need to
keep it part of jasper
*/
void javac(Options options, JspCompilationContext ctxt,
Mangler mangler)
throws JasperException
{
String javaFileName = mangler.getJavaFileName();
if( debug>0 ) log.log( "Compiling java file " + javaFileName);
boolean status=true;
if( jspCompilerPlugin == null ) {
jspCompilerPlugin=options.getJspCompilerPlugin();
}
// If no explicit compiler, and we never tried before
if( jspCompilerPlugin==null && tryJikes ) {
ByteArrayOutputStream out = new ByteArrayOutputStream (256);
try {
jspCompilerPlugin=Class.
forName("org.apache.jasper.compiler.JikesJavaCompiler");
JavaCompiler javaC=createJavaCompiler( jspCompilerPlugin );
prepareCompiler( javaC, options, ctxt );
javaC.setMsgOutput(out);
status = javaC.compile(javaFileName);
} catch( Exception ex ) {
log.log("Guess java compiler: no jikes " + ex.toString());
status=false;
}
if( status==false ) {
log.log("Guess java compiler: no jikes ");
log.log("Guess java compiler: OUT " + out.toString());
jspCompilerPlugin=null;
tryJikes=false;
} else {
log.log("Guess java compiler: using jikes ");
}
}
JavaCompiler javaC=createJavaCompiler( jspCompilerPlugin );
prepareCompiler( javaC, options, ctxt );
ByteArrayOutputStream out = new ByteArrayOutputStream (256);
javaC.setMsgOutput(out);
status = javaC.compile(javaFileName);
if (!ctxt.keepGenerated()) {
File javaFile = new File(javaFileName);
javaFile.delete();
}
if (status == false) {
String msg = out.toString ();
throw new JasperException("Unable to compile "
+ msg);
}
if( debug > 0 ) log.log("Compiled ok");
}
/** tool for customizing javac.
*/
public JavaCompiler createJavaCompiler(Class jspCompilerPlugin )
throws JasperException
{
JavaCompiler javac;
if (jspCompilerPlugin != null) {
try {
javac = (JavaCompiler) jspCompilerPlugin.newInstance();
} catch (Exception ex) {
Constants.message("jsp.warning.compiler.class.cantcreate",
new Object[] { jspCompilerPlugin, ex },
Log.FATAL);
javac = new SunJavaCompiler();
}
} else {
javac = new SunJavaCompiler();
}
return javac;
}
private String computeClassPath(Context ctx) {
String separator = System.getProperty("path.separator", ":");
URL classP[]=ctx.getClassPath();
String cpath = "";
cpath+=extractClassPath(classP);
Jdk11Compat jdkProxy=Jdk11Compat.getJdkCompat();
URL appsCP[];
URL commonCP[];
ClassLoader parentLoader=ctx.getContextManager().getParentLoader();
appsCP=jdkProxy.getParentURLs(parentLoader);
commonCP=jdkProxy.getURLs(parentLoader);
if( appsCP!=null )
cpath+=separator+extractClassPath(appsCP);
if( commonCP!=null )
cpath+=separator+extractClassPath(commonCP);
return cpath;
}
String extractClassPath(URL urls[]){
String separator = System.getProperty("path.separator", ":");
String cpath="";
for(int i=0; i< urls.length; i++ ) {
URL cp = urls[i];
if( cp == null ) {
continue;
}
File f = new File( cp.getFile());
if (cpath.length()>0) cpath += separator;
cpath += f;
}
return cpath;
}
private JspCompilationContext createCompilationContext( Request req,
String jspFile,
Options opt,
Mangler mangler)
{
JasperEngineContext ctxt = new JasperEngineContext();
ctxt.setServletClassName( mangler.getClassName());
// ctxt.setJspFile( req.servletPath().toString());
ctxt.setJspFile( jspFile );
ctxt.setClassPath( computeClassPath( req.getContext()) );
// System.out.println("computeClasspath:"+ctxt.getClassPath());
ctxt.setServletContext( req.getContext().getFacade());
ctxt.setOptions( opt );
ctxt.setClassLoader( req.getContext().getClassLoader());
ctxt.setOutputDir(req.getContext().getWorkDir().getAbsolutePath());
return ctxt;
}
// Add an "expire check" to the generated servlet.
private Dependency setDependency( Context ctx, JasperMangler mangler,
ServletHandler handler )
{
ServletInfo info=handler.getServletInfo();
// create a lastModified checker.
if( debug>0) log.log("Registering dependency for " + handler );
Dependency dep=new Dependency();
dep.setOrigin( new File(mangler.getJspFilePath()) );
dep.setTarget( handler );
dep.setLocal( true );
File f=new File( mangler.getClassFileName() );
if( mangler.getVersion() > 0 ) {
// it has a previous version
dep.setLastModified(f.lastModified());
// update the "expired" variable
dep.checkExpiry();
} else {
dep.setLastModified( -1 );
dep.setExpired( true );
}
if( debug>0 )
log.log( "file = " + mangler.getClassFileName() + " " +
f.lastModified() );
if( debug>0 )
log.log("origin = " + dep.getOrigin() + " " +
dep.getOrigin().lastModified());
try {
DependManager dm=(DependManager)ctx.getContainer().
getNote("DependManager");
if( dm!=null ) {
dm.addDependency( dep );
}
} catch( TomcatException ex ) {
ex.printStackTrace();
}
info.setDependency( dep );
return dep;
}
}