FileDocCategorySizeDatePackage
JspServlet.javaAPI DocGlassfish v2 API30294Fri May 04 22:36:06 BST 2007com.sun.enterprise.web.jsp

JspServlet

public class JspServlet extends HttpServlet
This is an iPlanet adaptation of the Apache Jasper JSPServlet. This servlet has several performance enhancements over the Apache JspServlet. These include: - Reducing the overall number of file stats per request - Checking for JSP modifications based on a reload interval - Caching compilation exceptions and recompiling the JSP only when it is modified

Fields Summary
protected ServletContext
context
protected Map
jsps
protected ServletConfig
config
protected org.apache.jasper.Options
options
protected URLClassLoader
parentClassLoader
private PermissionCollection
permissionCollection
private CodeSource
codeSource
private long
reloadInterval
private boolean
checkJSPmods
private boolean
debugLogEnabled
String
outputDir
URL[]
loaderURLs
static boolean
firstTime
Constructors Summary
Methods Summary
public voiddestroy()

        if (Constants.jasperLog != null)
            Constants.jasperLog.log("JspServlet.destroy()", Logger.INFORMATION);

        // ensure that only one thread destroys the jsps
        synchronized (this) {
            Iterator iter = jsps.values().iterator();
            while (iter.hasNext())
                ((JspServletWrapper)iter.next()).destroy();

            jsps.clear();
        }
    
private synchronized com.sun.enterprise.web.jsp.JspServlet$JspServletWrappergetWrapper(java.lang.String jspUri)
The following methods allow synchronized access to the jsps map as well and perform refcounting on the wrappers as well. These methods are called only when we check for JSP modifications

        JspServletWrapper wrapper = (JspServletWrapper) jsps.get(jspUri);
        if (wrapper != null)
            wrapper.incrementRefCount();
        return wrapper;
    
public voidinit(javax.servlet.ServletConfig config)


       
          

        super.init(config);
        this.config = config;
        this.context = config.getServletContext();
        
        Constants.jasperLog = new DefaultLogger(this.context);
        Constants.jasperLog.setName("JASPER_LOG");
        Constants.jasperLog.setTimestamp("false");
        Constants.jasperLog.setVerbosityLevel(
                   config.getInitParameter("logVerbosityLevel"));

        debugLogEnabled = Constants.jasperLog.matchVerbosityLevel(Logger.DEBUG);

        // reload-interval (specified in seconds) is the interval at which
        // JSP files are checked for modifications. Values that have 'special'
        // significance are: 
        //   0 : Check JSPs for modifications on every request 
        //  -1 : do not check for JSP modifications and disable recompilation
        String interval = config.getInitParameter("reload-interval");
        if (interval != null) {
            try {
                this.reloadInterval = Integer.parseInt(interval) * 1000;
                if (this.reloadInterval < 0) {
                    checkJSPmods = false;
                    Constants.message("jsp.message.recompile.disabled", 
                                      Logger.INFORMATION );
                } else if (this.reloadInterval > 0) {
                    Constants.message("jsp.message.reload.interval", 
                              new Object[] {interval}, Logger.INFORMATION );
                }
            } catch (NumberFormatException nfe) {
                Constants.message("jsp.warning.interval.invalid", 
                              new Object[] {interval}, Logger.WARNING );
            }
        }

        // In case of checking JSP for mods, use a HashMap instead of a
        // Hashtable since we anyway synchronize on all accesses to the jsp
        // wrappers for the sake of ref counting, so this avoids double
        // synchronization
        if (checkJSPmods)
            jsps = new HashMap();
        else
            jsps = new Hashtable();

        options = new EmbededServletOptions(config, context);

        outputDir = options.getScratchDir().toString();

        // set the loader urls to the output dir since that is where the
        // java classes corresponding to the jsps can be found
        File f = new File(outputDir);

        // If the toplevel output directory does not exist, then
        // create it at this point before adding it to the classloader path
        // If the directory does not exist when adding to the classloader,
        // the classloader has problems loading the classes later
        if (f.exists() == false) {
            f.mkdirs();
        }
        
        loaderURLs = new URL[1];
        try {
            loaderURLs[0] = f.toURL();
        } catch(MalformedURLException mfe) {
            throw new ServletException(mfe);
        }

        // Get the parent class loader. The servlet container is responsible
        // for providing a URLClassLoader for the web application context
        // the JspServlet is being used in.
        parentClassLoader =
            (URLClassLoader) Thread.currentThread().getContextClassLoader();
        if (parentClassLoader == null)
            parentClassLoader = (URLClassLoader)this.getClass().getClassLoader();
        String loaderString = "<none>";
        if (parentClassLoader != null)
            loaderString = parentClassLoader.toString();

        if (debugLogEnabled)
            Constants.message("jsp.message.parent_class_loader_is",
                              new Object[] {loaderString}, Logger.DEBUG);

        // Setup the PermissionCollection for this web app context
        // based on the permissions configured for the root of the
        // web app context directory, then add a file read permission
        // for that directory.
        Policy policy = Policy.getPolicy();
        if( policy != null ) {
            try {          
                // Get the permissions for the web app context
                String contextDir = context.getRealPath("/");
                if( contextDir == null )
                    contextDir = outputDir;
                URL url = new URL("file:" + contextDir);
                codeSource = new CodeSource(url,null);
                permissionCollection = policy.getPermissions(codeSource);
                // Create a file read permission for web app context directory
                if (contextDir.endsWith(File.separator))
                    contextDir = contextDir + "-";
                else
                    contextDir = contextDir + File.separator + "-";
                permissionCollection.add( new FilePermission(contextDir,"read") );
                // Allow the JSP to access org.apache.jasper.runtime.HttpJspBase
                permissionCollection.add( new RuntimePermission(
                    "accessClassInPackage.org.apache.jasper.runtime") );
                if (parentClassLoader instanceof URLClassLoader) {
                    URL [] urls = parentClassLoader.getURLs();
                    String jarUrl = null;
                    String jndiUrl = null;
                    for (int i=0; i<urls.length; i++) {
                        if (jndiUrl == null && urls[i].toString().startsWith("jndi:") ) {
                            jndiUrl = urls[i].toString() + "-";
                        }
                        if (jarUrl == null && urls[i].toString().startsWith("jar:jndi:") ) {
                            jarUrl = urls[i].toString();
                            jarUrl = jarUrl.substring(0,jarUrl.length() - 2);
                            jarUrl = jarUrl.substring(0,jarUrl.lastIndexOf('/")) + "/-";
                        }
                    }
                    if (jarUrl != null) {
                        permissionCollection.add( new FilePermission(jarUrl,"read") );
                        permissionCollection.add( new FilePermission(jarUrl.substring(4),"read") );
                    }
                    if (jndiUrl != null)
                        permissionCollection.add( new FilePermission(jndiUrl,"read") );
                }
            } catch(MalformedURLException mfe) {}
        }

        if (firstTime) {
            firstTime = false;
            if( System.getSecurityManager() != null ) {
                // Make sure classes needed at runtime by a JSP servlet
                // are already loaded by the class loader so that we
                // don't get a defineClassInPackage security exception.
                String apacheBase = "org.apache.jasper.";
                String iplanetBase = "com.sun.enterprise.web.jsp.";
                try {
                    parentClassLoader.loadClass( apacheBase +
                        "runtime.JspFactoryImpl$PrivilegedGetPageContext");
                    parentClassLoader.loadClass( apacheBase +
                        "runtime.JspFactoryImpl$PrivilegedReleasePageContext");
                    parentClassLoader.loadClass( apacheBase +
                        "runtime.JspRuntimeLibrary");
                    parentClassLoader.loadClass( apacheBase +
                        "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper");
                    parentClassLoader.loadClass( apacheBase +
                        "runtime.ServletResponseWrapperInclude");
                    this.getClass().getClassLoader().loadClass( iplanetBase +
                        "JspServlet$JspServletWrapper");
                } catch (ClassNotFoundException ex) {
                    Constants.jasperLog.log(
                        Constants.getString("jsp.message.preload.failure"),
                        ex, Logger.WARNING);
                }
            }
            Constants.message("jsp.message.scratch.dir.is", 
                              new Object[] {outputDir}, Logger.INFORMATION );
            Constants.message("jsp.message.dont.modify.servlets", Logger.INFORMATION);
            JspFactory.setDefaultFactory(new JspFactoryImpl());
        }
    
booleanpreCompile(javax.servlet.http.HttpServletRequest request)

Look for a precompilation request as described in Section 8.4.2 of the JSP 1.2 Specification. WARNING we cannot use request.getParameter() for this, because that will trigger parsing all of the request parameters, and not give a servlet the opportunity to call request.setCharacterEncoding() first.

param
request The servlet requset we are processing
exception
ServletException if an invalid parameter value for the jsp_precompile parameter name is specified


        String queryString = request.getQueryString();
        if (queryString == null)
            return (false);
        int start = queryString.indexOf(Constants.PRECOMPILE);
        if (start < 0)
            return (false);
        queryString =
            queryString.substring(start + Constants.PRECOMPILE.length());
        if (queryString.length() == 0)
            return (true);             // ?jsp_precompile
        if (queryString.startsWith("&"))
            return (true);             // ?jsp_precompile&foo=bar...
        if (!queryString.startsWith("="))
            return (false);            // part of some other name or value
        int limit = queryString.length();
        int ampersand = queryString.indexOf("&");
        if (ampersand > 0)
            limit = ampersand;
        String value = queryString.substring(1, limit);
        if (value.equals("true"))
            return (true);             // ?jsp_precompile=true
        else if (value.equals("false"))
            return (true);             // ?jsp_precompile=false
        else
            throw new ServletException("Cannot have request parameter " +
                                       Constants.PRECOMPILE + " set to " +
                                       value);
    
private synchronized voidputWrapper(java.lang.String jspUri, com.sun.enterprise.web.jsp.JspServlet$JspServletWrapper wrapper)

        wrapper.incrementRefCount();
        JspServletWrapper replaced =
                          (JspServletWrapper)jsps.put(jspUri, wrapper);

        // flag the wrapper that was replaced for destruction
        if (replaced != null)
            replaced.tryDestroy();
    
private synchronized voidreleaseWrapper(com.sun.enterprise.web.jsp.JspServlet$JspServletWrapper wrapper)

        if (wrapper != null)
            wrapper.decrementRefCount();
    
private synchronized voidremoveWrapper(java.lang.String jspUri)

        JspServletWrapper removed = (JspServletWrapper)jsps.remove(jspUri);

        // flag the wrapper that was removed for destruction
        if (removed != null)
            removed.tryDestroy();
    
public voidservice(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)

        try {
            String jspUri;
            String includeUri 
                = (String) request.getAttribute(Constants.INC_SERVLET_PATH);

            if (includeUri == null)
                jspUri = request.getServletPath();
            else
                jspUri = includeUri;

            String jspFile = (String) request.getAttribute(Constants.JSP_FILE);
            if (jspFile != null)
                jspUri = jspFile;

            if (debugLogEnabled) {
                Logger jasperLog = Constants.jasperLog;
                jasperLog.log("JspEngine --> "+jspUri);
                jasperLog.log("   ServletPath: "+request.getServletPath());
                jasperLog.log("      PathInfo: "+request.getPathInfo());
                jasperLog.log("      RealPath: "+context.getRealPath(jspUri));
                jasperLog.log("    RequestURI: "+request.getRequestURI());
                jasperLog.log("   QueryString: "+request.getQueryString());
            }

            serviceJspFile(request, response, jspUri);

        } catch (RuntimeException e) {
            throw e;
        } catch (ServletException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        } catch (Throwable e) {
            throw new ServletException(e);
        }
    
private voidserviceJspFile(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.String jspUri)
This is the main service function which creates the wrapper, loads the JSP if not loaded, checks for JSP modifications if specified, recompiles the JSP if needed and finally calls the service function on the wrapper.


        JspServletWrapper wrapper = null;
        try {
            if (checkJSPmods) {
                // this increments the refcount
                wrapper = getWrapper(jspUri);
                if (wrapper == null) {
                    // ensure that only one thread creates the wrapper
                    synchronized (this) {
                        wrapper = getWrapper(jspUri);
                        if (wrapper == null) {
                            // create a new wrapper and load the jsp inside it
                            wrapper = new JspServletWrapper(jspUri);
                            wrapper.loadJSP(request, response);

                            // add the new wrapper to the map, this increments
                            // the refcount as well
                            putWrapper(jspUri, wrapper);
                        }
                    }
                } else if (wrapper.isJspFileModified()) {
                    // create a new wrapper and load the jsp inside it
                    JspServletWrapper newWrapper =
                                      new JspServletWrapper(jspUri);
                    newWrapper.loadJSP(request, response);

                    // add the new wrapper to the map, this increments the
                    // refcount as well
                    putWrapper(jspUri, newWrapper);

                    // decrement the refcount on the old wrapper
                    releaseWrapper(wrapper);
                    wrapper = newWrapper;
                }
            } else {
                wrapper = (JspServletWrapper) jsps.get(jspUri);
                if (wrapper == null) {
                    // ensure that only one thread creates the wrapper
                    synchronized (this) {
                        wrapper = (JspServletWrapper) jsps.get(jspUri);
                        if (wrapper == null) {
                            // create a new wrapper and load the jsp inside it
                            wrapper = new JspServletWrapper(jspUri);
                            wrapper.loadJSP(request, response);

                            // add the new wrapper to the map
                            jsps.put(jspUri, wrapper);
                        }
                    }
                }
            }

            // throw any compile exception generated during compilation
            JasperException compileException = wrapper.getCompileException();
            if (compileException != null)
                throw compileException;

            // service the request if it is not a precompile request
            if (!preCompile(request))
                wrapper.service(request, response);

        } catch (FileNotFoundException ex) {
            // remove the wrapper from the map. In the case where we are not
            // checking for JSP mods, the wrapper would never have been in
            // the map since the exception would be thrown in loadJSP
            if (checkJSPmods)
                removeWrapper(jspUri);

            String includeRequestUri = (String)
                request.getAttribute("javax.servlet.include.request_uri");
            if (includeRequestUri != null) {
                // This file was included. Throw an exception as
                // a response.sendError() will be ignored by the
                // servlet engine.
                throw new ServletException(ex);
            } else {
                try {
                    response.sendError(HttpServletResponse.SC_NOT_FOUND, 
                                       ex.getMessage());
                } catch (IllegalStateException ise) {
                    Constants.jasperLog.log(Constants.getString
                                            ("jsp.error.file.not.found",
                                             new Object[] {ex.getMessage()}),
                                             ex, Logger.ERROR);
                }
            }
        } finally {
            // decrement the refcount even in case of an exception
            if (checkJSPmods)
                releaseWrapper(wrapper);
        }