alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *  Copyright 1999-2004 The Apache Software Foundation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.apache.tomcat.facade;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;

import javax.servlet.Servlet;
import javax.servlet.jsp.JspFactory;

import org.apache.jasper.Constants;
import org.apache.jasper.JasperEngineContext;
import org.apache.jasper.JasperException;
import org.apache.jasper.JasperOptionsImpl;
import org.apache.jasper.JspCompilationContext;
import org.apache.jasper.Options;
import org.apache.jasper.compiler.Compiler;
import org.apache.jasper.compiler.JasperMangler;
import org.apache.jasper.compiler.JavaCompiler;
import org.apache.jasper.compiler.JikesJavaCompiler;
import org.apache.jasper.compiler.Mangler;
import org.apache.jasper.compiler.SunJavaCompiler;
import org.apache.jasper.runtime.HttpJspBase;
import org.apache.jasper.runtime.JspFactoryImpl;
import org.apache.tomcat.core.BaseInterceptor;
import org.apache.tomcat.core.Context;
import org.apache.tomcat.core.ContextManager;
import org.apache.tomcat.core.Handler;
import org.apache.tomcat.core.Request;
import org.apache.tomcat.core.Response;
import org.apache.tomcat.core.TomcatException;
import org.apache.tomcat.util.compat.Jdk11Compat;
import org.apache.tomcat.util.depend.DependManager;
import org.apache.tomcat.util.depend.Dependency;
import org.apache.tomcat.util.log.Log;

/**
 * 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.jasper.servlet.JspServlet";
    
    Properties args=new Properties(); // args for jasper
    boolean useJspServlet=false; 
    boolean useWebAppCL=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 );
    }

    public void setJikesClasspath( String cp ) {
        if( cp != null ) {
            System.getProperties().put("jikes.class.path", cp);
            if( debug > 0 )
                log("Setting jikes.class.path to " + cp);
        }
    }

    // -------------------- 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;
    }

    /** Compile using the web application classloader.  This
        was added as part of dealing a problem with
        tools.jar on some HP-UX systems.
     */
    public void setUseWebAppCL(boolean b) {
        useWebAppCL=b;
    }
    
    // -------------------- 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 ) {
                ex.printStackTrace();
	    }
	}

        if( (useJspServlet && !ctx.isTrusted())
                || useWebAppCL ) {
            try {
                File f=new File( cm.getInstallDir(),
                                 "lib/container/jasper.jar" );
                URL url=new URL( "file", null,
                                 f.getAbsolutePath().replace('\\','/') );
                ctx.addClassPath( url );
                if( debug > 9 ) log( "Added to classpath: " + url );

                f=new File( System.getProperty( "java.home" ) +
                                 "/../lib/tools.jar");
                if( ! f.exists() ) {
                    // On some systems java.home gets set to the root of jdk.
                    // That's a bug, but we can work around and be nice.
                    f=new File( System.getProperty( "java.home" ) +
                                     "/lib/tools.jar");
                    if( ! f.exists() ) {
                        log("Tools.jar not found " +
                            System.getProperty( "java.home" ));
                    } else {
                        log("Detected wrong java.home value " +
                            System.getProperty( "java.home" ));
                    }
                }
                url=new URL( "file", "" , f.getAbsolutePath() );
                ctx.addClassPath( url );
                if( debug > 9 ) log( "Added to classpath: " + url );
	    } catch( MalformedURLException ex ) {
                ex.printStackTrace();
            }
        }
    }

    /** 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(ctx.getContainer("*.jsp") == null)
	    ctx.addServletMapping( "*.jsp", "jsp");

	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");
		org.apache.jasper.Constants.jasperLog=
		    loghelper;
		// 		org.apache.jasper.Constants.jasperLog.
		// 		    setVerbosityLevel("debug");
	    }

	    jspServlet.setServletClassName(jspServletCN);
	}

        if( useWebAppCL ) {
            //Extra test/warnings for tools.jar
            try {
                ctx.getClassLoader().loadClass( "sun.tools.javac.Main" );
                if( debug>0) log( "Found javac in context init");
            } catch( ClassNotFoundException ex ) {
                if( debug>0) log( "javac not found in context init");
            }
        }
    }

    /** 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  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
	}
	return 0;
    }

    /** Check if the JSP page needs to be re-compiled.
     */
    public int preInitCheck(Request req, Handler sw)
	throws TomcatException {
	
	if(sw == null || !(sw instanceof ServletHandler))
	    return 0;
	ServletHandler handler = (ServletHandler)sw;
	String jspFile=handler.getServletInfo().getJspFile();
	if(jspFile == null)
	    return 0;

	// 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;
	boolean do_compile=true;
	int i=(qString==null) ? -1: qString.indexOf( "jsp_precompile" );
	if( i>= 0 ) {
	    // Probably we are in the problem case. 
	    pre_compile=true;
	    req.parameters().handleQueryParameters();
	    String p=req.parameters().getParameter( "jsp_precompile");
	    if( "false".equalsIgnoreCase(p) ) {
		do_compile=false;
	    } else  if( p!=null && ! p.equalsIgnoreCase("true") ) {
		req.setAttribute("javax.servlet.error.message",
				 "Invalid value to jsp_precompile");
		return 500;
	    }
	}
	
	// Each .jsp file is compiled to a servlet, and will
	// have a dependency to check if it's expired
	// 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.
	Dependency dep= handler.getServletInfo().getDependency();
	if( (dep==null ||  dep.isExpired()) && do_compile ) {
	    // we need to compile... ( or find previous .class )
	    JasperLiaison liasion=new JasperLiaison(getLog(), debug,
                        useWebAppCL);
	    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
	    doPreCompileService(req);
	    return 200;
	}
	
	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
     *  tomcat.jsp.[uri]
     *  tomcat.jsp.[uri]
     *                   [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;
    }

    private void doPreCompileService(Request req) {
	Response res = req.getResponse();
	if( res == null || res.getBuffer() == null){
	    return; // A load-on-startup Request
	}
	try {
	    res.setContentType("text/html");	

	    String msg="

Jsp Precompile Done

"; res.setContentLength(msg.length()); res.getBuffer().write( msg ); } catch(IOException iex) { log("Pre-compile error",iex); } } } // -------------------- The main Jasper Liaison -------------------- final class JasperLiaison { Log log; final int debug; boolean useWebAppCL; JasperLiaison( Log log, int debug, boolean useWebAppCL ) { this.log=log; this.debug=debug; this.useWebAppCL=useWebAppCL; } /** 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 ); // If unsafe path or JSP file doesn't exist, return "not found" // Avoids creating work directories for non-existent JSP files String path=mangler.getJspFilePath(); if( path == null ) return 404; File f = new File( path ); if( !f.exists() ) return 404; // register the handler as dependent on the jspfile if( dep==null ) { dep=setDependency( ctx, mangler, handler ); // if dep is null then path is unsafe, return "not found" if( dep == null ) { return 404; } // 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() ); // May be called from include, we need to set the context class // loader // for jaxp1.1 to work using the container class loader //Extra test/warnings for tools.jar ClassLoader savedContextCL= containerCCL( ctx.getContextManager() .getContainerLoader() ); if( useWebAppCL ) { try { ctx.getClassLoader().loadClass( "sun.tools.javac.Main" ); if(debug>0) log.log( "Found javac using context loader"); } catch( ClassNotFoundException ex ) { if(debug>0) log.log( "javac not found using context loader"); } try { ctx.getContextManager().getContainerLoader(). loadClass( "sun.tools.javac.Main" ); if( debug > 0 ) log.log( "Found javac using container loader"); } catch( ClassNotFoundException ex ) { if( debug > 0 ) log.log( "javac not found using container loader"); } } try { Options options=new JasperOptionsImpl(args); JspCompilationContext ctxt=createCompilationContext(req, jspFile, options, mangler); jsp2java( mangler, ctxt ); javac( req, options, ctxt, mangler ); if(debug>0)log.log( "Generated " + mangler.getClassFileName() ); } catch ( java.io.FileNotFoundException fnfex ){ containerCCL( savedContextCL ); return 404; } 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 containerCCL( savedContextCL ); return 500; } containerCCL( savedContextCL ); dep.setExpired( false ); } return 0; } static final Jdk11Compat jdk11Compat=Jdk11Compat.getJdkCompat(); ClassLoader containerCCL( ClassLoader cl ) { ClassLoader orig= jdk11Compat.getContextClassLoader(); jdk11Compat.setContextClassLoader( cl ); return orig; } /** 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( Request req, 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=""; if( javac instanceof JikesJavaCompiler ) { if( !System.getProperty("java.version").startsWith("1.1") ) { cp=System.getProperty("java.home") + File.separator + "lib" + File.separator + "rt.jar" + sep; } String jikesCP = System.getProperty("jikes.class.path"); if( jikesCP != null && jikesCP.length() > 0 ) cp+=jikesCP + sep; } cp+=System.getProperty("java.class.path")+ sep + ctxt.getClassPath() + sep + ctxt.getOutputDir(); javac.setClasspath( cp ); javac.setOutputDir(ctxt.getOutputDir()); if( javac instanceof SunJavaCompiler && useWebAppCL ) { ClassLoader cl=req.getContext().getClassLoader(); ((SunJavaCompiler)javac).setLoader( cl ); } if( debug>5) log.log( "ClassPath " + cp); } static boolean tryJikes=false; 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(Request req, 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( req, 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( req, 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 loader=ctx.getClassLoader(); //The next will be the container classpath in trusted apps if( jdkProxy.isJava2() ) { appsCP=jdkProxy.getURLs(loader,2); commonCP=jdkProxy.getURLs(loader,3); } else { appsCP=jdkProxy.getURLs(loader,1); commonCP=jdkProxy.getURLs(loader,2); } if( appsCP!=null ) cpath+=separator+extractClassPath(appsCP); if( commonCP!=null ) cpath+=separator+extractClassPath(commonCP); // System.out.println("classpath: " + cpath ); 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(); String jspFilePath = mangler.getJspFilePath(); // if unsafe path, return null if( jspFilePath == null ) return null; dep.setOrigin( new File(jspFilePath) ); 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; } }
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.