Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9A96496AD for ; Thu, 10 May 2012 23:52:02 +0000 (UTC) Received: (qmail 30894 invoked by uid 500); 10 May 2012 23:52:02 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 30859 invoked by uid 500); 10 May 2012 23:52:02 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 30851 invoked by uid 99); 10 May 2012 23:52:02 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 10 May 2012 23:52:02 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 10 May 2012 23:51:51 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 5C848238897A; Thu, 10 May 2012 23:51:28 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1336969 - in /sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp: ./ jasper/ jasper/compiler/ jasper/servlet/ Date: Thu, 10 May 2012 23:51:27 -0000 To: commits@sling.apache.org From: cziegeler@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120510235128.5C848238897A@eris.apache.org> Author: cziegeler Date: Thu May 10 23:51:27 2012 New Revision: 1336969 URL: http://svn.apache.org/viewvc?rev=1336969&view=rev Log: SLING-2471 : Free classloaders as soon as possible Removed: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspServletWrapperAdapter.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JasperLoader.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspCServletContext.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServlet.java Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/Compiler.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/JspRuntimeContext.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/Node.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/TagLibraryInfoImpl.java sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java?rev=1336969&r1=1336968&r2=1336969&view=diff ============================================================================== --- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java (original) +++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/JspScriptEngineFactory.java Thu May 10 23:51:27 2012 @@ -49,11 +49,11 @@ import org.apache.sling.commons.classloa import org.apache.sling.commons.classloader.DynamicClassLoaderManager; import org.apache.sling.scripting.api.AbstractScriptEngineFactory; import org.apache.sling.scripting.api.AbstractSlingScriptEngine; -import org.apache.sling.scripting.jsp.jasper.JasperException; import org.apache.sling.scripting.jsp.jasper.Options; import org.apache.sling.scripting.jsp.jasper.compiler.JspRuntimeContext; import org.apache.sling.scripting.jsp.jasper.runtime.AnnotationProcessor; import org.apache.sling.scripting.jsp.jasper.runtime.JspApplicationContextImpl; +import org.apache.sling.scripting.jsp.jasper.servlet.JspServletWrapper; import org.apache.sling.scripting.jsp.util.TagUtil; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.ComponentContext; @@ -181,7 +181,7 @@ public class JspScriptEngineFactory io.setRequestResourceResolver(resolver); jspFactoryHandler.incUsage(); try { - final JspServletWrapperAdapter errorJsp = getJspWrapperAdapter(scriptName); + final JspServletWrapper errorJsp = getJspWrapper(scriptName, slingBindings); errorJsp.service(slingBindings); // The error page could be inside an include. @@ -225,10 +225,11 @@ public class JspScriptEngineFactory io.setRequestResourceResolver(resolver); jspFactoryHandler.incUsage(); try { - final JspServletWrapperAdapter jsp = getJspWrapperAdapter(scriptHelper); - // create a SlingBindings object final SlingBindings slingBindings = new SlingBindings(); slingBindings.putAll(bindings); + + final JspServletWrapper jsp = getJspWrapper(scriptHelper, slingBindings); + // create a SlingBindings object jsp.service(slingBindings); } finally { jspFactoryHandler.decUsage(); @@ -236,42 +237,40 @@ public class JspScriptEngineFactory } } - private JspServletWrapperAdapter getJspWrapperAdapter(final String scriptName) + private JspServletWrapper getJspWrapper(final String scriptName, final SlingBindings bindings) throws SlingException { - final JspRuntimeContext rctxt = jspRuntimeContext; + JspRuntimeContext rctxt = this.getJspRuntimeContext(); - JspServletWrapperAdapter wrapper = (JspServletWrapperAdapter) rctxt.getWrapper(scriptName); + JspServletWrapper wrapper = rctxt.getWrapper(scriptName); if (wrapper != null) { - return wrapper; + if ( wrapper.isValid() ) { + return wrapper; + } + rctxt.removeWrapper(wrapper.getJspUri()); + this.renewJspRuntimeContext(); + rctxt = this.getJspRuntimeContext(); + wrapper = null; } synchronized (rctxt) { - wrapper = (JspServletWrapperAdapter) rctxt.getWrapper(scriptName); + wrapper = rctxt.getWrapper(scriptName); if (wrapper != null) { return wrapper; } - try { - - wrapper = new JspServletWrapperAdapter(servletConfig, options, - scriptName, false, rctxt); - rctxt.addWrapper(scriptName, wrapper); + wrapper = new JspServletWrapper(servletConfig, options, + scriptName, false, rctxt); + rctxt.addWrapper(scriptName, wrapper); - return wrapper; - } catch (JasperException je) { - if (je.getCause() != null) { - throw new SlingException(je.getMessage(), je.getCause()); - } - throw new SlingException("Cannot create JSP: " + scriptName, je); - } + return wrapper; } } - private JspServletWrapperAdapter getJspWrapperAdapter(final SlingScriptHelper scriptHelper) + private JspServletWrapper getJspWrapper(final SlingScriptHelper scriptHelper, final SlingBindings bindings) throws SlingException { final SlingScript script = scriptHelper.getScript(); final String scriptName = script.getScriptResource().getPath(); - return getJspWrapperAdapter(scriptName); + return getJspWrapper(scriptName, bindings); } // ---------- SCR integration ---------------------------------------------- @@ -297,10 +296,6 @@ public class JspScriptEngineFactory options = new JspServletOptions(slingServletContext, ioProvider, componentContext, tldLocationsCache); - // Initialize the JSP Runtime Context - this.jspRuntimeContext = new JspRuntimeContext(slingServletContext, - options, ioProvider); - jspServletContext = new JspServletContext(ioProvider, slingServletContext, tldLocationsCache); @@ -340,13 +335,7 @@ public class JspScriptEngineFactory this.eventHandlerRegistration = null; } if (jspRuntimeContext != null) { - try { - jspRuntimeContext.destroy(); - } catch (NullPointerException npe) { - // SLING-530, might be thrown on system shutdown in a servlet - // container when using the Equinox servlet container bridge - logger.debug("deactivate: ServletContext might already be unavailable", npe); - } + this.destroyJspRuntimeContext(this.jspRuntimeContext); jspRuntimeContext = null; } @@ -484,6 +473,31 @@ public class JspScriptEngineFactory } } + private void destroyJspRuntimeContext(final JspRuntimeContext jrc) { + if (jrc != null) { + try { + jrc.destroy(); + } catch (NullPointerException npe) { + // SLING-530, might be thrown on system shutdown in a servlet + // container when using the Equinox servlet container bridge + logger.debug("deactivate: ServletContext might already be unavailable", npe); + } + } + } + + private JspRuntimeContext getJspRuntimeContext() { + if ( this.jspRuntimeContext == null ) { + synchronized ( this ) { + if ( this.jspRuntimeContext == null ) { + // Initialize the JSP Runtime Context + this.jspRuntimeContext = new JspRuntimeContext(slingServletContext, + options, ioProvider); + } + } + } + return this.jspRuntimeContext; + } + /** * Fixes {@link ScriptException} that overwrites the * {@link ScriptException#getMessage()} method to display its own @@ -500,7 +514,7 @@ public class JspScriptEngineFactory private static final long serialVersionUID = -6490165487977283019L; - public BetterScriptException(String message, Exception cause) { + public BetterScriptException(final String message, final Exception cause) { super(message); this.initCause(cause); } @@ -510,10 +524,27 @@ public class JspScriptEngineFactory /** * @see org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event) */ - public void handleEvent(Event event) { + public void handleEvent(final Event event) { final String path = (String)event.getProperty(SlingConstants.PROPERTY_PATH); if ( path != null ) { - this.jspRuntimeContext.handleModification(path); + final JspRuntimeContext rctxt = this.jspRuntimeContext; + if ( rctxt != null && rctxt.handleModification(path) ) { + renewJspRuntimeContext(); + } } } + + private void renewJspRuntimeContext() { + final JspRuntimeContext jrc; + synchronized ( this ) { + jrc = this.jspRuntimeContext; + this.jspRuntimeContext = null; + } + final Thread t = new Thread() { + public void run() { + destroyJspRuntimeContext(jrc); + } + }; + t.start(); + } } Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java?rev=1336969&r1=1336968&r2=1336969&view=diff ============================================================================== --- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java (original) +++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/IsolatedClassLoader.java Thu May 10 23:51:27 2012 @@ -33,13 +33,11 @@ public final class IsolatedClassLoader private final IOProvider ioProvider; - public IsolatedClassLoader(final ClassLoader parent, - final IOProvider ioProvider) { - super(parent); + public IsolatedClassLoader(final IOProvider ioProvider) { + super(ioProvider.getClassLoader()); this.ioProvider = ioProvider; } - //---------- Class loader overwrites ------------------------------------- /** Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java?rev=1336969&r1=1336968&r2=1336969&view=diff ============================================================================== --- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java (original) +++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/JspCompilationContext.java Thu May 10 23:51:27 2012 @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.sling.scripting.jsp.jasper; import java.io.File; @@ -32,6 +31,7 @@ import javax.servlet.ServletContext; import javax.servlet.jsp.tagext.TagInfo; import org.apache.sling.scripting.jsp.jasper.compiler.Compiler; +import org.apache.sling.scripting.jsp.jasper.compiler.JDTCompiler; import org.apache.sling.scripting.jsp.jasper.compiler.JspRuntimeContext; import org.apache.sling.scripting.jsp.jasper.compiler.JspUtil; import org.apache.sling.scripting.jsp.jasper.compiler.Localizer; @@ -54,42 +54,32 @@ import org.apache.sling.scripting.jsp.ja */ public class JspCompilationContext { - protected org.apache.juli.logging.Log log = - org.apache.juli.logging.LogFactory.getLog(JspCompilationContext.class); - - protected Map tagFileJarUrls; - protected boolean isPackagedTagFile; + private Map tagFileJarUrls; - protected String className; - protected String jspUri; - protected boolean isErrPage; - protected String basePackageName; - protected String derivedPackageName; - protected String servletJavaFileName; - protected String javaPath; - protected String classFileName; - protected String contentType; - protected ServletWriter writer; - protected Options options; - protected JspServletWrapper jsw; - protected Compiler jspCompiler; - protected String classPath; - - protected String baseURI; - protected String outputDir; - protected ServletContext context; - - protected JspRuntimeContext rctxt; - - protected int removed = 0; - - protected URL baseUrl; - protected Class servletClass; - - protected boolean isTagFile; - protected boolean protoTypeMode; - protected TagInfo tagInfo; - protected URL tagFileJarUrl; + private String className; + private String jspUri; + private boolean isErrPage; + private String basePackageName; + private String derivedPackageName; + private String servletJavaFileName; + private String javaPath; + private String classFileName; + private String contentType; + private ServletWriter writer; + private Options options; + private JspServletWrapper jsw; + private Compiler jspCompiler; + + private String baseURI; + private String outputDir; + private ServletContext context; + + private JspRuntimeContext rctxt; + + private boolean isTagFile; + private boolean protoTypeMode; + private TagInfo tagInfo; + private URL tagFileJarUrl; // jspURI _must_ be relative to the context public JspCompilationContext(String jspUri, @@ -134,9 +124,6 @@ public class JspCompilationContext { this.isTagFile = true; this.tagInfo = tagInfo; this.tagFileJarUrl = tagFileJarUrl; - if (tagFileJarUrl != null) { - isPackagedTagFile = true; - } } /** @@ -195,9 +182,9 @@ public class JspCompilationContext { * plus the directory derived from the package name. */ public String getOutputDir() { - if (outputDir == null) { - createOutputDir(); - } + if (outputDir == null) { + createOutputDir(); + } return outputDir; } @@ -207,57 +194,23 @@ public class JspCompilationContext { * is not done yet. Right now we're just hardcoding the actual * compilers that are created. */ - public Compiler createCompiler() throws JasperException { + private Compiler createCompiler() { if (jspCompiler != null ) { return jspCompiler; } - jspCompiler = null; - if (options.getCompilerClassName() != null) { - jspCompiler = createCompiler(options.getCompilerClassName()); - } else { - if (options.getCompiler() == null) { - jspCompiler = createCompiler("org.apache.sling.scripting.jsp.jasper.compiler.JDTCompiler"); - if (jspCompiler == null) { - jspCompiler = createCompiler("org.apache.sling.scripting.jsp.jasper.compiler.AntCompiler"); - } - } else { - jspCompiler = createCompiler("org.apache.sling.scripting.jsp.jasper.compiler.AntCompiler"); - if (jspCompiler == null) { - jspCompiler = createCompiler("org.apache.sling.scripting.jsp.jasper.compiler.JDTCompiler"); - } - } - } - if (jspCompiler == null) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); - } - jspCompiler.init(this, jsw); + jspCompiler = new JDTCompiler(); + jspCompiler.init(this); return jspCompiler; } - protected Compiler createCompiler(String className) { - Compiler compiler = null; - try { - compiler = (Compiler) this.getClass().getClassLoader().loadClass(className).newInstance(); - } catch (InstantiationException e) { - log.warn(Localizer.getMessage("jsp.error.compiler"), e); - } catch (IllegalAccessException e) { - log.warn(Localizer.getMessage("jsp.error.compiler"), e); - } catch (NoClassDefFoundError e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), e); - } - } catch (ClassNotFoundException e) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), e); - } - } - return compiler; - } - public Compiler getCompiler() { return jspCompiler; } + public void reset() { + this.jspCompiler = null; + } + /** ---------- Access resources in the webapp ---------- */ /** @@ -543,60 +496,37 @@ public class JspCompilationContext { return getOptions().getKeepGenerated(); } - // ==================== Removal ==================== - - public void incrementRemoved() { - if (removed == 0 && rctxt != null) { - rctxt.removeWrapper(jspUri); - } - removed++; - } - - public boolean isRemoved() { - if (removed > 1 ) { - return true; - } - return false; - } - // ==================== Compile and reload ==================== - public void compile() throws JasperException, IOException, FileNotFoundException { - createCompiler(); - if (isPackagedTagFile || jspCompiler.isOutDated()) { - try { - jspCompiler.removeGeneratedFiles(); - jspCompiler.compile(); - jsw.setReload(true); - jsw.setCompilationException(null); - this.getRuntimeContext().addJspDependencies(jsw); - } catch (JasperException ex) { - // Cache compilation exception - jsw.setCompilationException(ex); - throw ex; - } catch (IOException ioe) { - JasperException je = new JasperException( + public JasperException compile() { + final Compiler c = createCompiler(); + try { + c.removeGeneratedFiles(); + c.compile(); + this.getRuntimeContext().addJspDependencies(jsw); + } catch (final JasperException ex) { + return ex; + } catch (final IOException ioe) { + final JasperException je = new JasperException( + Localizer.getMessage("jsp.error.unable.compile"), + ioe); + return je; + } catch (final Exception ex) { + JasperException je = new JasperException( Localizer.getMessage("jsp.error.unable.compile"), - ioe); - // Cache compilation exception - jsw.setCompilationException(je); - throw ioe; - } catch (Exception ex) { - JasperException je = new JasperException( - Localizer.getMessage("jsp.error.unable.compile"), - ex); - // Cache compilation exception - jsw.setCompilationException(je); - throw je; - } + ex); + return je; + } finally { + c.clean(); } + + return null; } // ==================== Manipulating the class ==================== public Class load() - throws JasperException, FileNotFoundException - { + throws JasperException { try { String name; if (isTagFile()) { @@ -604,7 +534,8 @@ public class JspCompilationContext { } else { name = getServletPackageName() + "." + getServletClassName(); } - servletClass = getClassLoader().loadClass(name); + final Class servletClass = getClassLoader().loadClass(name); + return servletClass; } catch (ClassNotFoundException cex) { throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), cex); @@ -612,57 +543,40 @@ public class JspCompilationContext { throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), ex); } - removed = 0; - return servletClass; } // ==================== protected methods ==================== - static Object outputDirLock = new Object(); - public void checkOutputDir() { - if (outputDir != null) { - if (!(new File(outputDir)).exists()) { - makeOutputDir(); - } - } else { - createOutputDir(); - } + getOutputDir(); } - protected boolean makeOutputDir() { - synchronized(outputDirLock) { - return getRuntimeContext().getIOProvider().mkdirs(outputDir); - } + private boolean makeOutputDir() { + return getRuntimeContext().getIOProvider().mkdirs(outputDir); } - protected void createOutputDir() { + private void createOutputDir() { String path = null; if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); + String tagName = tagInfo.getTagClassName(); path = tagName.replace('.', '/'); - path = path.substring(0, path.lastIndexOf('/')); + path = path.substring(0, path.lastIndexOf('/')); } else { path = getServletPackageName().replace('.', '/'); - } + } - // Append servlet or tag handler path to scratch dir - try { - baseUrl = new File(options.getScratchDir()).toURI().toURL(); - outputDir = options.getScratchDir() + File.separator + path + File.separator; - if (!makeOutputDir()) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder")); - } - } catch (MalformedURLException e) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e); - } + // Append servlet or tag handler path to scratch dir + outputDir = options.getScratchDir() + File.separator + path + File.separator; + if (!makeOutputDir()) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder")); + } } - protected static final boolean isPathSeparator(char c) { + private static final boolean isPathSeparator(char c) { return (c == '/' || c == '\\'); } - protected static final String canonicalURI(String s) { + private static final String canonicalURI(String s) { if (s == null) return null; StringBuffer result = new StringBuffer(); final int len = s.length(); Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/Compiler.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/Compiler.java?rev=1336969&r1=1336968&r2=1336969&view=diff ============================================================================== --- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/Compiler.java (original) +++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/Compiler.java Thu May 10 23:51:27 2012 @@ -22,15 +22,11 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLConnection; -import java.util.Iterator; -import java.util.List; import org.apache.sling.scripting.jsp.jasper.JasperException; import org.apache.sling.scripting.jsp.jasper.JspCompilationContext; import org.apache.sling.scripting.jsp.jasper.Options; -import org.apache.sling.scripting.jsp.jasper.servlet.JspServletWrapper; +import org.apache.sling.scripting.jsp.jasper.compiler.Node.CustomTag; /** * Main JSP compiler class. This class uses Ant for compiling. @@ -55,8 +51,6 @@ public abstract class Compiler { protected PageInfo pageInfo; - protected JspServletWrapper jsw; - protected TagFileProcessor tfp; protected Options options; @@ -65,8 +59,7 @@ public abstract class Compiler { // ------------------------------------------------------------ Constructor - public void init(JspCompilationContext ctxt, JspServletWrapper jsw) { - this.jsw = jsw; + public void init(final JspCompilationContext ctxt) { this.ctxt = ctxt; this.options = ctxt.getOptions(); } @@ -340,100 +333,6 @@ public abstract class Compiler { } /** - * This is a protected method intended to be overridden by subclasses of - * Compiler. This is used by the compile method to do all the compilation. - */ - public boolean isOutDated() { - return isOutDated(true); - } - - /** - * Determine if a compilation is necessary by checking the time stamp of the - * JSP page with that of the corresponding .class or .java file. If the page - * has dependencies, the check is also extended to its dependeants, and so - * on. This method can by overidden by a subclasses of Compiler. - * - * @param checkClass - * If true, check against .class file, if false, check against - * .java file. - */ - public boolean isOutDated(final boolean checkClass) { - final long lastModifiedTest = jsw.getLastModificationTest(); - if ( lastModifiedTest > 0 ) { - return false; - } else if ( lastModifiedTest < 0 ) { - return true; - } - final String jsp = ctxt.getJspFile(); - - long jspRealLastModified = ctxt.getRuntimeContext().getIOProvider().lastModified(jsp); - - long targetLastModified = 0; - String targetFile; - - if (checkClass) { - targetFile = ctxt.getClassFileName(); - } else { - targetFile = ctxt.getServletJavaFileName(); - } - - targetLastModified = ctxt.getRuntimeContext().getIOProvider().lastModified(targetFile); - if (targetLastModified < 0) { - return true; - } - - if (checkClass && jsw != null) { - jsw.setServletClassLastModifiedTime(targetLastModified); - } - if (targetLastModified < jspRealLastModified) { - if (log.isDebugEnabled()) { - log.debug("Compiler: outdated: " + targetFile + " " - + targetLastModified); - } - return true; - } - - // determine if source dependent files (e.g. includes using include - // directives) have been changed. - if (jsw == null) { - return false; - } - - List depends = jsw.getDependants(); - if (depends == null) { - return false; - } - - final Iterator it = depends.iterator(); - while (it.hasNext()) { - final String include = it.next(); - // ignore tag libs, we are reloaded if a taglib changes anyway - if ( include.startsWith("tld:") ) { - continue; - } - try { - final URL includeUrl = ctxt.getResource(include); - if (includeUrl == null) { - return true; - } - - URLConnection includeUconn = includeUrl.openConnection(); - long includeLastModified = includeUconn.getLastModified(); - includeUconn.getInputStream().close(); - - if (includeLastModified > targetLastModified) { - return true; - } - } catch (Exception e) { - return true; - } - } - - return false; - - } - - /** * Gets the error dispatcher. */ public ErrorDispatcher getErrorDispatcher() { @@ -492,4 +391,23 @@ public abstract class Compiler { // Remove as much as possible, ignore possible exceptions } } + + public void clean() { + if ( this.pageNodes != null ) { + try { + pageNodes.visit(new CleanVisitor()); + } catch ( final JasperException ignore) { + // ignore + } + } + + } + + private static final class CleanVisitor extends Node.Visitor { + + public void visit(final CustomTag n) throws JasperException { + n.clean(); + visitBody(n); + } + } } Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/JspRuntimeContext.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/JspRuntimeContext.java?rev=1336969&r1=1336968&r2=1336969&view=diff ============================================================================== --- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/JspRuntimeContext.java (original) +++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/JspRuntimeContext.java Thu May 10 23:51:27 2012 @@ -66,17 +66,7 @@ import org.apache.sling.scripting.jsp.ja public final class JspRuntimeContext { // Logger - private Log log = LogFactory.getLog(JspRuntimeContext.class); - - /** - * Prefixes, in which repository paths and script paths can differ. - */ - private static final String[] PATH_PREFIXES = {"", "/WEB-INF/tags"}; - - /* - * Counts how many times the webapp's JSPs have been reloaded. - */ - private int jspReloadCount; + private final Log log = LogFactory.getLog(JspRuntimeContext.class); /** The {@link IOProvider} used to get access to output */ private final IOProvider ioProvider; @@ -214,28 +204,6 @@ public final class JspRuntimeContext { this.context = context; this.options = options; this.ioProvider = ioProvider; -/* - // Get the parent class loader - parentClassLoader = Thread.currentThread().getContextClassLoader(); - if (parentClassLoader == null) { - parentClassLoader = this.getClass().getClassLoader(); - } - - if (log.isDebugEnabled()) { - if (parentClassLoader != null) { - log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is", - parentClassLoader.toString())); - } else { - log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is", - "")); - } - } - - initClassPath(); -*/ - if (context instanceof org.apache.sling.scripting.jsp.jasper.servlet.JspCServletContext) { - return; - } if (Constants.IS_SECURITY_ENABLED) { initSecurity(); @@ -249,20 +217,17 @@ public final class JspRuntimeContext { */ private ServletContext context; private Options options; -// private ClassLoader parentClassLoader; private PermissionCollection permissionCollection; - private CodeSource codeSource; - // private String classpath; /** * Maps JSP pages to their JspServletWrapper's */ - private Map jsps = new ConcurrentHashMap(); + private final Map jsps = new ConcurrentHashMap(); /** * Maps dependencies to the using jsp. */ - private Map> depToJsp = new HashMap>(); + private final Map> depToJsp = new HashMap>(); // ------------------------------------------------------ Public Methods @@ -283,56 +248,48 @@ public final class JspRuntimeContext { } } - private void invalidate(final JspServletWrapper jsw) { - log.debug("Invalidating script " + jsw.getJspUri()); - jsw.clearLastModificationTest(); - } + /** + * Handle jsp modifications + */ + public boolean handleModification(final String scriptName) { + JspServletWrapper wrapper = jsps.remove(scriptName); - public void handleModification(final String repositoryPath) { - final String scriptName = getScriptPath(repositoryPath); - synchronized ( this ) { - // first check if jsps contains this - JspServletWrapper wrapper = jsps.get(scriptName); - if ( wrapper != null ) { - invalidate(wrapper); - } - if (wrapperIsValid(wrapper)) { - synchronized ( depToJsp ) { - final Set deps = depToJsp.get(scriptName); - if ( deps != null ) { - for(final String jspName : deps) { - wrapper = jsps.get(jspName); - if ( wrapper != null ) { - invalidate(wrapper); - } - } - } - } - } - } - } + // first check if jsps contains this + boolean removed = this.invalidate(wrapper); - private String getScriptPath(String repositoryPath) { - for (final String prefix : PATH_PREFIXES) { - final String path = prefix + repositoryPath; - if (depToJsp.containsKey(path)) { - return path; + final Set deps; + synchronized ( depToJsp ) { + deps = depToJsp.remove(scriptName); + } + if ( deps != null ) { + for(final String dep : deps) { + wrapper = jsps.remove(dep); + removed |= this.invalidate(wrapper); } } - return repositoryPath; + return removed; } - private boolean wrapperIsValid(JspServletWrapper wrapper) { - return wrapper == null || wrapper.getLastModificationTest() == -1; + /** + * Invalidate a wrapper and destroy it. + */ + private boolean invalidate(final JspServletWrapper wrapper) { + if ( wrapper != null ) { + log.debug("Invalidating jsp " + wrapper.getJspUri()); + this.ioProvider.delete(wrapper.getJspUri()); + wrapper.destroy(true); + return true; + } + return false; } /** - * Add a new JspServletWrapper. + * Add a new wrapper * * @param jspUri JSP URI * @param jsw Servlet wrapper for JSP */ - public void addWrapper(String jspUri, JspServletWrapper jsw) { + public void addWrapper(final String jspUri, final JspServletWrapper jsw) { jsps.put(jspUri, jsw); addJspDependencies(jsw); } @@ -343,17 +300,10 @@ public final class JspRuntimeContext { * @param jspUri JSP URI * @return JspServletWrapper for JSP */ - public JspServletWrapper getWrapper(String jspUri) { + public JspServletWrapper getWrapper(final String jspUri) { return jsps.get(jspUri); } - public JspServletWrapper getAWrapper() { - if ( jsps.size() > 0 ) { - return jsps.values().iterator().next(); - } - return null; - } - /** * Remove a JspServletWrapper. * @@ -364,87 +314,20 @@ public final class JspRuntimeContext { } /** - * Returns the number of JSPs for which JspServletWrappers exist, i.e., - * the number of JSPs that have been loaded into the webapp. - * - * @return The number of JSPs that have been loaded into the webapp - */ - public int getJspCount() { - return jsps.size(); - } - - /** - * Get the SecurityManager Policy CodeSource for this web - * applicaiton context. - * - * @return CodeSource for JSP - */ - public CodeSource getCodeSource() { - return codeSource; - } - - /** - * Get the parent URLClassLoader. - * - * @return URLClassLoader parent - public ClassLoader getParentClassLoader() { - return parentClassLoader; - } - */ - - /** - * Get the SecurityManager PermissionCollection for this - * web application context. - * - * @return PermissionCollection permissions - */ - public PermissionCollection getPermissionCollection() { - return permissionCollection; - } - - /** * Process a "destroy" event for this web application context. */ public void destroy() { Iterator servlets = jsps.values().iterator(); while (servlets.hasNext()) { - servlets.next().destroy(); + servlets.next().destroy(false); + } + jsps.clear(); + synchronized ( depToJsp ) { + depToJsp.clear(); } } /** - * Increments the JSP reload counter. - */ - public synchronized void incrementJspReloadCount() { - jspReloadCount++; - } - - /** - * Resets the JSP reload counter. - * - * @param count Value to which to reset the JSP reload counter - */ - public synchronized void setJspReloadCount(int count) { - this.jspReloadCount = count; - } - - /** - * Gets the current value of the JSP reload counter. - * - * @return The current value of the JSP reload counter - */ - public int getJspReloadCount() { - return jspReloadCount; - } - - /** - * The classpath that is passed off to the Java compiler. - public String getClassPath() { - return classpath; - } - */ - - /** * Returns the current {@link IOProvider} of this context. */ public IOProvider getIOProvider() { @@ -453,41 +336,6 @@ public final class JspRuntimeContext { // -------------------------------------------------------- Private Methods - - /** - * Method used to initialize classpath for compiles. - private void initClassPath() { - - StringBuffer cpath = new StringBuffer(); - String sep = System.getProperty("path.separator"); - - if (parentClassLoader instanceof URLClassLoader) { - URL[] urls = ((URLClassLoader) parentClassLoader).getURLs(); - - for (int i = 0; i < urls.length; i++) { - // Tomcat 4 can use URL's other than file URL's, - // a protocol other than file: will generate a - // bad file system path, so only add file: - // protocol URL's to the classpath. - - if (urls[i].getProtocol().equals("file")) { - cpath.append(urls[i].getFile() + sep); - } - } - } - - cpath.append(options.getScratchDir() + sep); - - String cp = (String) context.getAttribute(Constants.SERVLET_CLASSPATH); - - classpath = cpath.toString() + cp; - - if(log.isDebugEnabled()) { - log.debug("Compilation classpath initialized: " + getClassPath()); - } - } - */ - /** * Method used to initialize SecurityManager data. */ @@ -511,7 +359,7 @@ public final class JspRuntimeContext { } File contextDir = new File(codeBase); URL url = contextDir.getCanonicalFile().toURL(); - codeSource = new CodeSource(url,(Certificate[])null); + final CodeSource codeSource = new CodeSource(url,(Certificate[])null); permissionCollection = policy.getPermissions(codeSource); // Create a file read permission for web app context directory @@ -541,37 +389,7 @@ public final class JspRuntimeContext { // Allow the JSP to access org.apache.sling.scripting.jsp.jasper.runtime.HttpJspBase permissionCollection.add( new RuntimePermission( "accessClassInPackage.org.apache.jasper.runtime") ); -/* - if (parentClassLoader instanceof URLClassLoader) { - URL [] urls = ((URLClassLoader) parentClassLoader).getURLs(); - String jarUrl = null; - String jndiUrl = null; - for (int i=0; i -- nesting level 0 -- nesting level 1 * -- nesting level 2 -- nesting level 1 * - * + * * @return Custom tag's nesting level */ private int makeCustomNestingLevel() { @@ -1761,7 +1761,7 @@ abstract class Node implements TagConsta /** * Returns true if this custom action has an empty body, and false * otherwise. - * + * * A custom action is considered to have an empty body if the following * holds true: - getBody() returns null, or - all immediate children are * jsp:attribute actions, or - the action's jsp:body is empty. @@ -1786,6 +1786,19 @@ abstract class Node implements TagConsta return hasEmptyBody; } + + public void clean() { + tagHandlerClass = null; + jspAttrs = null; + tagData = null; + tagInfo = null; + tagFileInfo = null; + varInfos = null; + atBeginScriptingVars = null; + atEndScriptingVars = null; + nestedScriptingVars = null; + tagPluginContext = null; + } } /** @@ -2033,7 +2046,7 @@ abstract class Node implements TagConsta /** * Add a source to Java line mapping - * + * * @param srcLine * The postion of the source line, relative to the line at * the start of this node. The corresponding java line is @@ -2057,7 +2070,7 @@ abstract class Node implements TagConsta /** * Represents attributes that can be request time expressions. - * + * * Can either be a plain attribute, an attribute that represents a request * time expression value, or a named attribute (specified using the * jsp:attribute standard action). @@ -2104,7 +2117,7 @@ abstract class Node implements TagConsta /** * Allow node to validate itself - * + * * @param ef * @param ctx * @throws ELException @@ -2162,7 +2175,7 @@ abstract class Node implements TagConsta } /** - * + * * @return return true if there's TagAttributeInfo meaning we need to * assign a ValueExpression */ @@ -2171,7 +2184,7 @@ abstract class Node implements TagConsta } /** - * + * * @return return true if there's TagAttributeInfo meaning we need to * assign a MethodExpression */ @@ -2195,7 +2208,7 @@ abstract class Node implements TagConsta } return "java.lang.Object"; } - + public String[] getParameterTypeNames() { if (this.tai != null) { if (this.isDeferredMethodInput()) { @@ -2219,7 +2232,7 @@ abstract class Node implements TagConsta /** * Only makes sense if namedAttribute is false. - * + * * @return the value for the attribute, or the expression string * (stripped of "<%=", "%>", "%=", or "%" but containing "${" * and "}" for EL expressions) @@ -2230,7 +2243,7 @@ abstract class Node implements TagConsta /** * Only makes sense if namedAttribute is true. - * + * * @return the nodes that evaluate to the body of this attribute. */ public NamedAttribute getNamedAttributeNode() { @@ -2306,7 +2319,7 @@ abstract class Node implements TagConsta /** * Appends a node to the list - * + * * @param n * The node to add */ @@ -2317,7 +2330,7 @@ abstract class Node implements TagConsta /** * Removes the given node from the list. - * + * * @param n * The node to be removed */ @@ -2327,7 +2340,7 @@ abstract class Node implements TagConsta /** * Visit the nodes in the list with the supplied visitor - * + * * @param v * The visitor used */ Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/TagLibraryInfoImpl.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/TagLibraryInfoImpl.java?rev=1336969&r1=1336968&r2=1336969&view=diff ============================================================================== --- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/TagLibraryInfoImpl.java (original) +++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/compiler/TagLibraryInfoImpl.java Thu May 10 23:51:27 2012 @@ -5,9 +5,9 @@ * The ASF licenses this file to You 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. @@ -54,7 +54,7 @@ import org.apache.sling.scripting.jsp.ja /** * Implementation of the TagLibraryInfo class from the JSP spec. - * + * * @author Anil K. Vijendran * @author Mandar Raje * @author Pierre Delisle @@ -67,7 +67,7 @@ class TagLibraryInfoImpl extends TagLibr private Log log = LogFactory.getLog(TagLibraryInfoImpl.class); private JspCompilationContext ctxt; - + private PageInfo pi; private ErrorDispatcher err; @@ -162,7 +162,7 @@ class TagLibraryInfoImpl extends TagLibr parseTLD(ctxt, location[0], in, null); // Add TLD to dependency list - PageInfo pageInfo = ctxt.createCompiler().getPageInfo(); + PageInfo pageInfo = ctxt.getCompiler().getPageInfo(); if (pageInfo != null) { pageInfo.addDependant(location[0]); } @@ -204,7 +204,7 @@ class TagLibraryInfoImpl extends TagLibr Collection coll = pi.getTaglibs(); return (TagLibraryInfo[]) coll.toArray(new TagLibraryInfo[0]); } - + /* * @param ctxt The JSP compilation context @param uri The TLD's uri @param * in The TLD's input stream @param jarFileUrl The JAR file containing the @@ -301,7 +301,7 @@ class TagLibraryInfoImpl extends TagLibr /* * @param uri The uri of the TLD @param ctxt The compilation context - * + * * @return String array whose first element denotes the path to the TLD. If * the path to the TLD points to a jar file, then the second element denotes * the name of the TLD entry in the jar file, which is hardcoded to @@ -438,11 +438,11 @@ class TagLibraryInfoImpl extends TagLibr /* * Parses the tag file directives of the given TagFile and turns them into a * TagInfo. - * + * * @param elem The element in the TLD @param uri The location of * the TLD, in case the tag file is specified relative to it @param jarFile * The JAR file, in case the tag file is packaged in a JAR - * + * * @return TagInfo correspoding to tag file directives */ private TagFileInfo createTagFileInfo(TreeNode elem, String uri, @@ -463,8 +463,8 @@ class TagLibraryInfoImpl extends TagLibr // Ignore element: Bugzilla 33538 } else if ("tag-extension".equals(tname)) { // Ignore element: Bugzilla 33538 - } else if ("icon".equals(tname) - || "display-name".equals(tname) + } else if ("icon".equals(tname) + || "display-name".equals(tname) || "description".equals(tname)) { // Ignore these elements: Bugzilla 38015 } else { @@ -580,7 +580,7 @@ class TagLibraryInfoImpl extends TagLibr // translation time) the type is fixed at java.lang.String. type = "java.lang.String"; } - + return new TagAttributeInfo(name, required, type, rtexprvalue, isFragment, null, deferredValue, deferredMethod, expectedType, methodSignature); @@ -732,7 +732,7 @@ class TagLibraryInfoImpl extends TagLibr /** * The instance (if any) for the TagLibraryValidator class. - * + * * @return The TagLibraryValidator instance, if any. */ public TagLibraryValidator getTagLibraryValidator() { @@ -743,7 +743,7 @@ class TagLibraryInfoImpl extends TagLibr * Translation-time validation of the XML document associated with the JSP * page. This is a convenience method on the associated TagLibraryValidator * class. - * + * * @param thePage * The JSP page object * @return A string indicating whether the page is valid or not. Modified: sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java?rev=1336969&r1=1336968&r2=1336969&view=diff ============================================================================== --- sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java (original) +++ sling/trunk/bundles/scripting/jsp/src/main/java/org/apache/sling/scripting/jsp/jasper/servlet/JspServletWrapper.java Thu May 10 23:51:27 2012 @@ -17,9 +17,11 @@ package org.apache.sling.scripting.jsp.jasper.servlet; -import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; +import java.net.URLConnection; +import java.util.Iterator; +import java.util.List; import javax.servlet.Servlet; import javax.servlet.ServletConfig; @@ -34,9 +36,14 @@ import javax.servlet.jsp.tagext.TagInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.sling.api.SlingException; +import org.apache.sling.api.SlingHttpServletRequest; +import org.apache.sling.api.SlingIOException; +import org.apache.sling.api.SlingServletException; import org.apache.sling.api.scripting.ScriptEvaluationException; +import org.apache.sling.api.scripting.SlingBindings; import org.apache.sling.commons.classloader.DynamicClassLoader; import org.apache.sling.scripting.jsp.SlingPageException; +import org.apache.sling.scripting.jsp.jasper.IsolatedClassLoader; import org.apache.sling.scripting.jsp.jasper.JasperException; import org.apache.sling.scripting.jsp.jasper.JspCompilationContext; import org.apache.sling.scripting.jsp.jasper.Options; @@ -68,36 +75,34 @@ import org.apache.sling.scripting.jsp.ja public class JspServletWrapper { // Logger - private Log log = LogFactory.getLog(JspServletWrapper.class); + private final Log log = LogFactory.getLog(JspServletWrapper.class); private Servlet theServlet; - private String jspUri; - private Class servletClass; - private Class tagHandlerClass; - private JspCompilationContext ctxt; + private final String jspUri; + private final JspCompilationContext ctxt; private long available = 0L; - private ServletConfig config; - private Options options; - private boolean firstTime = true; - private volatile boolean reload = true; - private boolean isTagFile; - private int tripCount; - private JasperException compileException; - private long servletClassLastModifiedTime; - private volatile long lastModificationTest = 0L; + private final ServletConfig config; + private final Options options; + private final boolean isTagFile; + private volatile JasperException compileException; + private volatile long lastModificationTest = -1L; + private volatile int tripCount; - /* + private volatile List dependents; + + /** * JspServletWrapper for JSP pages. */ - public JspServletWrapper(ServletConfig config, Options options, String jspUri, - boolean isErrorPage, JspRuntimeContext rctxt) - throws JasperException { - - this.isTagFile = false; + public JspServletWrapper(final ServletConfig config, + final Options options, + final String jspUri, + final boolean isErrorPage, + final JspRuntimeContext rctxt) { + this.isTagFile = false; this.config = config; this.options = options; this.jspUri = jspUri; - ctxt = new JspCompilationContext(jspUri, isErrorPage, options, + this.ctxt = new JspCompilationContext(jspUri, isErrorPage, options, config.getServletContext(), this, rctxt); } @@ -105,19 +110,18 @@ public class JspServletWrapper { /** * JspServletWrapper for tag files. */ - public JspServletWrapper(ServletContext servletContext, - Options options, - String tagFilePath, - TagInfo tagInfo, - JspRuntimeContext rctxt, - URL tagFileJarUrl) + public JspServletWrapper(final ServletContext servletContext, + final Options options, + final String tagFilePath, + final TagInfo tagInfo, + final JspRuntimeContext rctxt, + final URL tagFileJarUrl) throws JasperException { this.isTagFile = true; this.config = null; // not used this.options = options; this.jspUri = tagFilePath; - this.tripCount = 0; - ctxt = new JspCompilationContext(jspUri, tagInfo, options, + this.ctxt = new JspCompilationContext(jspUri, tagInfo, options, servletContext, this, rctxt, tagFileJarUrl); } @@ -126,135 +130,63 @@ public class JspServletWrapper { return ctxt; } - public void setReload(boolean reload) { - this.reload = reload; - } - - public Servlet getServlet() - throws ServletException, IOException, FileNotFoundException - { - // check if the used class loader is still alive - if (!reload) { - if ( servletClass.getClassLoader() instanceof DynamicClassLoader ) { - reload = !((DynamicClassLoader)servletClass.getClassLoader()).isLive(); + public boolean isValid() { + if ( theServlet != null ) { + if ( theServlet.getClass().getClassLoader() instanceof DynamicClassLoader ) { + return ((DynamicClassLoader)theServlet.getClass().getClassLoader()).isLive(); } } - if (reload) { - synchronized (this) { - // Synchronizing on jsw enables simultaneous loading - // of different pages, but not the same page. - if (reload) { - // This is to maintain the original protocol. - destroy(); - - Servlet servlet = null; - - try { - servletClass = ctxt.load(); - servlet = (Servlet) servletClass.newInstance(); - AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName()); - if (annotationProcessor != null) { - annotationProcessor.processAnnotations(servlet); - annotationProcessor.postConstruct(servlet); - } - } catch (IllegalAccessException e) { - throw new JasperException(e); - } catch (InstantiationException e) { - throw new JasperException(e); - } catch (IOException e) { - throw e; - } catch (Exception e) { - throw new JasperException(e); - } - - servlet.init(config); + return false; + } - if (!firstTime) { - ctxt.getRuntimeContext().incrementJspReloadCount(); - } + private Servlet loadServlet() + throws ServletException, IOException { + Servlet servlet = null; - theServlet = servlet; - reload = false; - } + try { + servlet = (Servlet) ctxt.load().newInstance(); + AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName()); + if (annotationProcessor != null) { + annotationProcessor.processAnnotations(servlet); + annotationProcessor.postConstruct(servlet); } + } catch (IllegalAccessException e) { + throw new JasperException(e); + } catch (InstantiationException e) { + throw new JasperException(e); + } catch (Exception e) { + throw new JasperException(e); } - return theServlet; - } - public ServletContext getServletContext() { - return config.getServletContext(); - } + servlet.init(config); - /** - * Sets the compilation exception for this JspServletWrapper. - * - * @param je The compilation exception - */ - public void setCompilationException(JasperException je) { - this.compileException = je; - } - - /** - * Sets the last-modified time of the servlet class file associated with - * this JspServletWrapper. - * - * @param lastModified Last-modified time of servlet class - */ - public void setServletClassLastModifiedTime(long lastModified) { - if (this.servletClassLastModifiedTime < lastModified) { - synchronized (this) { - if (this.servletClassLastModifiedTime < lastModified) { - this.servletClassLastModifiedTime = lastModified; - reload = true; - } - } - } + return servlet; } /** * Compile (if needed) and load a tag file */ public Class loadTagFile() throws JasperException { - - try { - if (ctxt.isRemoved()) { - throw new FileNotFoundException(jspUri); - } - if (firstTime || this.lastModificationTest <= 0) { - synchronized (this) { - if (firstTime || this.lastModificationTest <= 0 ) { - ctxt.compile(); - this.lastModificationTest = System.currentTimeMillis(); - firstTime = false; - } else if ( compileException != null ) { - // Throw cached compilation exception + if (this.lastModificationTest <= 0) { + synchronized (this) { + if (this.lastModificationTest <= 0 ) { + this.compileException = ctxt.compile(); + this.lastModificationTest = System.currentTimeMillis(); + if ( compileException != null ) { throw compileException; } - } - } else { - if (compileException != null) { + } else if ( compileException != null ) { + // Throw cached compilation exception throw compileException; } } - - if (!reload) { - if ( tagHandlerClass.getClassLoader() instanceof DynamicClassLoader ) { - reload = !((DynamicClassLoader)tagHandlerClass.getClassLoader()).isLive(); - } - } - if (reload) { - synchronized ( this ) { - if ( reload ) { - tagHandlerClass = ctxt.load(); - reload = false; - } - } + } else { + if (compileException != null) { + throw compileException; } - } catch (IOException ex) { - throw new JasperException(ex); - } + } - return tagHandlerClass; + return ctxt.load(); } /** @@ -264,7 +196,6 @@ public class JspServletWrapper { * generated and compiled. */ public Class loadTagFilePrototype() throws JasperException { - ctxt.setPrototypeMode(true); try { return loadTagFile(); @@ -277,33 +208,26 @@ public class JspServletWrapper { * Get a list of files that the current page has source dependency on. */ @SuppressWarnings("unchecked") - public java.util.List getDependants() { - try { - Object target; - if (isTagFile) { - if (!reload) { - if ( tagHandlerClass.getClassLoader() instanceof DynamicClassLoader ) { - reload = !((DynamicClassLoader)tagHandlerClass.getClassLoader()).isLive(); - } + public List getDependants() { + if ( this.dependents == null ) { + try { + Object target; + if (isTagFile) { + target = ctxt.load().newInstance(); + } else { + // we load the servlet with a separate class loader + final String name = this.ctxt.getServletPackageName() + "." + this.ctxt.getServletClassName(); + final ClassLoader cl = new IsolatedClassLoader(this.ctxt.getRuntimeContext().getIOProvider()); + target = cl.loadClass(name).newInstance(); } - if (reload) { - synchronized ( this ) { - if ( reload ) { - tagHandlerClass = ctxt.load(); - reload = false; - } - } + if (target != null && target instanceof JspSourceDependent) { + this.dependents = (List) ((JspSourceDependent) target).getDependants(); } - target = tagHandlerClass.newInstance(); - } else { - target = getServlet(); + } catch (final Throwable ex) { + // ignore } - if (target != null && target instanceof JspSourceDependent) { - return ((java.util.List) ((JspSourceDependent) target).getDependants()); - } - } catch (Throwable ex) { } - return null; + return this.dependents; } public boolean isTagFile() { @@ -322,17 +246,116 @@ public class JspServletWrapper { return jspUri; } - public void service(HttpServletRequest request, - HttpServletResponse response, - boolean precompile) - throws ServletException, IOException, FileNotFoundException { + private boolean isOutDated() { + final String jsp = ctxt.getJspFile(); - try { + long jspRealLastModified = ctxt.getRuntimeContext().getIOProvider().lastModified(jsp); + + long targetLastModified = 0; + final String targetFile = ctxt.getClassFileName(); + + targetLastModified = ctxt.getRuntimeContext().getIOProvider().lastModified(targetFile); + if (targetLastModified < 0) { + return true; + } + + if (targetLastModified < jspRealLastModified) { + if (log.isDebugEnabled()) { + log.debug("Compiler: outdated: " + targetFile + " " + + targetLastModified); + } + return true; + } + + final List depends = this.getDependants(); + if (depends == null) { + return false; + } + + final Iterator it = depends.iterator(); + while (it.hasNext()) { + final String include = it.next(); + // ignore tag libs, we are reloaded if a taglib changes anyway + if ( include.startsWith("tld:") ) { + continue; + } + try { + final URL includeUrl = ctxt.getResource(include); + if (includeUrl == null) { + return true; + } + + URLConnection includeUconn = includeUrl.openConnection(); + long includeLastModified = includeUconn.getLastModified(); + includeUconn.getInputStream().close(); + + if (includeLastModified > targetLastModified) { + return true; + } + } catch (Exception e) { + return true; + } + } + + return false; + + } - if (ctxt.isRemoved()) { - throw new FileNotFoundException(jspUri); + /** + * Prepare the servlet: + * - compile it if it either hasn't been compiled yet or is out dated + * - load the servlet + * + */ + private void prepareServlet(final HttpServletRequest request, + final HttpServletResponse response) + throws IOException, ServletException { + if ( isOutDated() ) { + // Compile... + log.debug("Compiling " + this.jspUri); + this.compileException = ctxt.compile(); + if ( compileException != null ) { + throw compileException; } + } + + // (Re)load servlet class file + log.debug("Loading " + this.jspUri); + this.theServlet = this.loadServlet(); + } + /** + * @param bindings + * @throws SlingIOException + * @throws SlingServletException + * @throws IllegalArgumentException if the Jasper Precompile controller + * request parameter has an illegal value. + */ + public void service(final SlingBindings bindings) { + final SlingHttpServletRequest request = bindings.getRequest(); + final Object oldValue = request.getAttribute(SlingBindings.class.getName()); + try { + request.setAttribute(SlingBindings.class.getName(), bindings); + service(request, bindings.getResponse()); + } catch (SlingException se) { + // rethrow as is + throw se; + } catch (IOException ioe) { + throw new SlingIOException(ioe); + } catch (ServletException se) { + throw new SlingServletException(se); + } finally { + request.setAttribute(SlingBindings.class.getName(), oldValue); + } + } + + /** + * Process the request. + */ + public void service(final HttpServletRequest request, + final HttpServletResponse response) + throws ServletException, IOException { + try { if ((available > 0L) && (available < Long.MAX_VALUE)) { if (available > System.currentTimeMillis()) { response.setDateHeader("Retry-After", available); @@ -344,72 +367,18 @@ public class JspServletWrapper { // Wait period has expired. Reset. available = 0; } - - /* - * (1) Compile - */ - if (firstTime || this.lastModificationTest <= 0 ) { - synchronized (this) { - if (firstTime || this.lastModificationTest <= 0 ) { - // The following sets reload to true, if necessary - ctxt.compile(); - this.lastModificationTest = System.currentTimeMillis(); - firstTime = false; - } else if ( compileException != null ) { - // Throw cached compilation exception - throw compileException; - + if ( theServlet == null ) { + synchronized ( this ) { + if ( theServlet == null ) { + this.prepareServlet(request, response); } } - } else if (compileException != null) { - // Throw cached compilation exception - throw compileException; - } - - /* - * (2) (Re)load servlet class file - */ - getServlet(); - - // If a page is to be precompiled only, return. - if (precompile) { - return; } - - } catch (FileNotFoundException ex) { - ctxt.incrementRemoved(); - 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); - } - try { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - ex.getMessage()); - } catch (IllegalStateException ise) { - log.error(Localizer.getMessage("jsp.error.file.not.found", - ex.getMessage()), - ex); + if ( compileException != null ) { + throw compileException; } - return; - } catch (final ServletException ex) { - handleJspException(ex); - } catch (final IOException ex) { - handleJspException(ex); - } catch (final IllegalStateException ex) { - handleJspException(ex); - } catch (final Exception ex) { - handleJspException(ex); - } - try { - - /* - * (3) Service request - */ + // Service request if (theServlet instanceof SingleThreadModel) { // sync on the wrapper so that the freshness // of the page is determined right before servicing @@ -420,7 +389,7 @@ public class JspServletWrapper { theServlet.service(request, response); } - } catch (UnavailableException ex) { + } catch (final UnavailableException ex) { String includeRequestUri = (String) request.getAttribute("javax.servlet.include.request_uri"); if (includeRequestUri != null) { @@ -452,8 +421,14 @@ public class JspServletWrapper { } } - public void destroy() { + public void destroy(boolean deleteGeneratedFiles) { if (theServlet != null) { + if ( deleteGeneratedFiles ) { + final org.apache.sling.scripting.jsp.jasper.compiler.Compiler c = this.ctxt.getCompiler(); + if ( c != null ) { + c.removeGeneratedFiles(); + } + } theServlet.destroy(); AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName()); if (annotationProcessor != null) { @@ -465,23 +440,11 @@ public class JspServletWrapper { e.getMessage()), e); } } + theServlet = null; } } /** - * @return Returns the lastModificationTest. - */ - public long getLastModificationTest() { - return lastModificationTest; - } - /** - *Clea the lastModificationTest. - */ - public void clearLastModificationTest() { - this.lastModificationTest = -1; - } - - /** *

Attempts to construct a JasperException that contains helpful information * about what went wrong. Uses the JSP compiler system to translate the line * number in the generated servlet that originated the exception to a line @@ -531,7 +494,7 @@ public class JspServletWrapper { StackTraceElement jspFrame = null; for (int i=0; i