ASF Bugzilla – Attachment 24684 Details for
Bug 48358
JSP-unloading reloaded
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch including tests that fixed the problem for us.
tc7_jsps.diff (text/plain), 15.20 KB, created by
Isabel Drost
on 2009-12-09 06:58:37 UTC
(
hide
)
Description:
Patch including tests that fixed the problem for us.
Filename:
MIME Type:
Creator:
Isabel Drost
Created:
2009-12-09 06:58:37 UTC
Size:
15.20 KB
patch
obsolete
>Index: test/org/apache/jasper/EmbeddedServletOptionsTest.java >=================================================================== >--- test/org/apache/jasper/EmbeddedServletOptionsTest.java (revision 0) >+++ test/org/apache/jasper/EmbeddedServletOptionsTest.java (revision 0) >@@ -0,0 +1,56 @@ >+package org.apache.jasper; >+ >+import javax.servlet.ServletContext; >+ >+import org.apache.catalina.Container; >+import org.apache.catalina.Engine; >+import org.apache.catalina.core.ApplicationContext; >+import org.apache.catalina.core.StandardContext; >+import org.apache.catalina.core.StandardEngine; >+import org.apache.catalina.core.StandardService; >+import org.apache.catalina.core.StandardWrapper; >+ >+import junit.framework.TestCase; >+ >+/** >+ * Currently only tests whether maxLoadedJsps initializes correctly. >+ * */ >+public class EmbeddedServletOptionsTest extends TestCase { >+ StandardWrapper config; >+ ServletContext context; >+ >+ protected void setUp() throws Exception { >+ super.setUp(); >+ config = new StandardWrapper(); >+ StandardContext std1 = new StandardContext(); >+ StandardContext std2 = new StandardContext(); >+ Engine std3 = new StandardEngine(); >+ std3.setService(new StandardService()); >+ std2.setParent(std3); >+ std1.setParent(std2); >+ context = new ApplicationContext(std1); >+ } >+ >+ public void testGetMaxLoadedJspsNegative() { >+ config.addInitParameter("maxLoadedJsps", "-1"); >+ EmbeddedServletOptions options = new EmbeddedServletOptions(config, context); >+ assertEquals(-1, options.getMaxLoadedJsps()); >+ } >+ >+ public void testGetMaxLoadedJspsDefault() { >+ EmbeddedServletOptions options = new EmbeddedServletOptions(config, context); >+ assertEquals(-1, options.getMaxLoadedJsps()); >+ } >+ >+ public void testGetMaxLoadedJspsPositive() { >+ config.addInitParameter("maxLoadedJsps", "2000"); >+ EmbeddedServletOptions options = new EmbeddedServletOptions(config, context); >+ assertEquals(2000, options.getMaxLoadedJsps()); >+ } >+ >+ public void testGetMaxLoadedJspsException() { >+ config.addInitParameter("maxLoadedJsps", "2000abc"); >+ EmbeddedServletOptions options = new EmbeddedServletOptions(config, context); >+ assertEquals(-1, options.getMaxLoadedJsps()); >+ } >+} >Index: test/org/apache/jasper/compiler/JspRuntimeContextTest.java >=================================================================== >--- test/org/apache/jasper/compiler/JspRuntimeContextTest.java (revision 0) >+++ test/org/apache/jasper/compiler/JspRuntimeContextTest.java (revision 0) >@@ -0,0 +1,82 @@ >+package org.apache.jasper.compiler; >+ >+import static org.easymock.EasyMock.*; >+ >+import org.apache.catalina.Engine; >+import org.apache.catalina.core.ApplicationContext; >+import org.apache.catalina.core.StandardContext; >+import org.apache.catalina.core.StandardEngine; >+import org.apache.catalina.core.StandardService; >+import org.apache.catalina.core.StandardWrapper; >+import org.apache.jasper.EmbeddedServletOptions; >+import org.apache.jasper.JasperException; >+import org.apache.jasper.Options; >+import org.apache.jasper.servlet.JspServletWrapper; >+ >+import junit.framework.TestCase; >+ >+public class JspRuntimeContextTest extends TestCase { >+ >+ JspRuntimeContext context; >+ ApplicationContext ctxt; >+ Options options; >+ >+ protected void setUp() throws Exception { >+ super.setUp(); >+ StandardWrapper config = new StandardWrapper(); >+ config.addInitParameter("maxLoadedJsps", "2"); >+ StandardContext std1 = new StandardContext(); >+ StandardContext std2 = new StandardContext(); >+ Engine std3 = new StandardEngine(); >+ std3.setService(new StandardService()); >+ std2.setParent(std3); >+ std1.setParent(std2); >+ ctxt = new ApplicationContext(std1); >+ options = new EmbeddedServletOptions(config, ctxt); >+ >+ context = new JspRuntimeContext(ctxt, options); >+ } >+ >+ public void testCheckUnloadDisabled() { >+ options = (Options) createMock(Options.class); >+ expect(options.getScratchDir()).andReturn(null); >+ expect(options.getClassPath()).andReturn(null); >+ expect(options.getDevelopment()).andReturn(false); >+ expect(options.getMaxLoadedJsps()).andReturn(-1); >+ replay(options); >+ context = new JspRuntimeContext(ctxt, options); >+ context.checkUnload(); >+ verify(options); >+ } >+ >+ public void testCheckUnloadEnabledSizeTooFewJsps() { >+ options = (Options) createMock(Options.class); >+ expect(options.getScratchDir()).andReturn(null); >+ expect(options.getClassPath()).andReturn(null); >+ expect(options.getDevelopment()).andReturn(false); >+ expect(options.getMaxLoadedJsps()).andReturn(1); >+ expect(options.getCheckInterval()).andReturn(0); >+ expect(options.getMaxLoadedJsps()).andReturn(1); >+ replay(options); >+ context = new JspRuntimeContext(ctxt, options); >+ context.checkUnload(); >+ verify(options); >+ } >+ >+ public void testCheckUnloadEnabledSizeEnoughJsps() throws JasperException { >+ options = (Options) createMock(Options.class); >+ expect(options.getScratchDir()).andReturn(null); >+ expect(options.getClassPath()).andReturn(null); >+ expect(options.getDevelopment()).andReturn(false); >+ expect(options.getMaxLoadedJsps()).andReturn(1); >+ expect(options.getCheckInterval()).andReturn(0); >+ expect(options.getMaxLoadedJsps()).andReturn(1); >+ expect(options.getMaxLoadedJsps()).andReturn(1); >+ replay(options); >+ context = new JspRuntimeContext(ctxt, options); >+ context.addWrapper("first", new JspServletWrapper(new StandardWrapper(), options, "/first.jsp", false, context)); >+ context.addWrapper("second", new JspServletWrapper(new StandardWrapper(), options, "/second.jsp", false, context)); >+ context.checkUnload(); >+ verify(options); >+ } >+} >Index: java/org/apache/jasper/JspC.java >=================================================================== >--- java/org/apache/jasper/JspC.java (revision 888769) >+++ java/org/apache/jasper/JspC.java (working copy) >@@ -447,6 +447,10 @@ > return cache; > } > >+ public int getMaxLoadedJsps() { >+ return -1; >+ } >+ > /** > * Background compilation check intervals in seconds > */ >Index: java/org/apache/jasper/servlet/JspServlet.java >=================================================================== >--- java/org/apache/jasper/servlet/JspServlet.java (revision 888769) >+++ java/org/apache/jasper/servlet/JspServlet.java (working copy) >@@ -286,6 +286,7 @@ > > > public void periodicEvent() { >+ rctxt.checkUnload(); > rctxt.checkCompile(); > } > >Index: java/org/apache/jasper/servlet/JspServletWrapper.java >=================================================================== >--- java/org/apache/jasper/servlet/JspServletWrapper.java (revision 888769) >+++ java/org/apache/jasper/servlet/JspServletWrapper.java (working copy) >@@ -81,6 +81,7 @@ > private JasperException compileException; > private long servletClassLastModifiedTime; > private long lastModificationTest = 0L; >+ private long lastExecutionTime = 0L; > > /* > * JspServletWrapper for JSP pages. >@@ -310,6 +311,10 @@ > > // The following sets reload to true, if necessary > ctxt.compile(); >+ >+ if (options.getDevelopment() && options.getMaxLoadedJsps() > 0) { >+ ctxt.getRuntimeContext().unloadJsp(); >+ } > } > } else { > if (compileException != null) { >@@ -371,7 +376,7 @@ > } else { > theServlet.service(request, response); > } >- >+ this.lastExecutionTime = System.currentTimeMillis(); > } catch (UnavailableException ex) { > String includeRequestUri = (String) > request.getAttribute("javax.servlet.include.request_uri"); >@@ -418,6 +423,10 @@ > } > } > >+ public long getLastExecutionTime() { >+ return lastExecutionTime; >+ } >+ > public void destroy() { > if (theServlet != null) { > theServlet.destroy(); >Index: java/org/apache/jasper/EmbeddedServletOptions.java >=================================================================== >--- java/org/apache/jasper/EmbeddedServletOptions.java (revision 888769) >+++ java/org/apache/jasper/EmbeddedServletOptions.java (working copy) >@@ -181,6 +181,12 @@ > private boolean displaySourceFragment = true; > > >+ /** >+ * The maxim number of loaded jsps per web-application. If there are more >+ * jsps loaded, they will be unloaded. >+ */ >+ private int maxLoadedJsps = -1; >+ > public String getProperty(String name ) { > return settings.getProperty( name ); > } >@@ -371,6 +377,14 @@ > } > > /** >+ * Should any jsps be unloaded? If set to a value greater than 0 eviction of jsps >+ * is started. Default: -1 >+ * */ >+ public int getMaxLoadedJsps() { >+ return maxLoadedJsps; >+ } >+ >+ /** > * Create an EmbeddedServletOptions object using data available from > * ServletConfig and ServletContext. > */ >@@ -639,6 +653,17 @@ > } > } > >+ String maxLoadedJsps = config.getInitParameter("maxLoadedJsps"); >+ if (maxLoadedJsps != null) { >+ try { >+ this.maxLoadedJsps = Integer.parseInt(maxLoadedJsps); >+ } catch(NumberFormatException ex) { >+ if (log.isWarnEnabled()) { >+ log.warn(Localizer.getMessage("jsp.warning.maxLoadedJsps", ""+this.maxLoadedJsps)); >+ } >+ } >+ } >+ > // Setup the global Tag Libraries location cache for this > // web-application. > tldLocationsCache = new TldLocationsCache(context); >Index: java/org/apache/jasper/compiler/JspRuntimeContext.java >=================================================================== >--- java/org/apache/jasper/compiler/JspRuntimeContext.java (revision 888769) >+++ java/org/apache/jasper/compiler/JspRuntimeContext.java (working copy) >@@ -28,6 +28,7 @@ > import java.security.cert.Certificate; > import java.util.Iterator; > import java.util.Map; >+import java.util.Map.Entry; > import java.util.concurrent.ConcurrentHashMap; > import java.util.concurrent.atomic.AtomicInteger; > >@@ -43,6 +44,7 @@ > import org.apache.juli.logging.Log; > import org.apache.juli.logging.LogFactory; > >+ > /** > * Class for tracking JSP compile time file dependencies when the > * &060;%@include file="..."%&062; directive is used. >@@ -171,7 +173,6 @@ > * Maps JSP pages to their JspServletWrapper's > */ > private Map<String, JspServletWrapper> jsps = new ConcurrentHashMap<String, JspServletWrapper>(); >- > > // ------------------------------------------------------ Public Methods > >@@ -468,5 +469,53 @@ > return new SecurityHolder(source, permissions); > } > >+ /** Returns a JspServletWrapper that should be destroyed. Default strategy: Least recently used. */ >+ public JspServletWrapper getJspForUnload(final int maxLoadedJsps) { >+ if( jsps.size() > maxLoadedJsps ) { >+ synchronized( jsps ) { >+ Entry<String, JspServletWrapper> oldest = null; >+ for (Entry<String, JspServletWrapper> jsw : jsps.entrySet()) { >+ if (!jsw.getValue().isTagFile()) { >+ if (oldest == null || oldest.getValue().getLastExecutionTime() > jsw.getValue().getLastExecutionTime()) { >+ oldest = jsw; >+ } >+ } >+ } > >+ if (oldest != null) { >+ removeWrapper(oldest.getKey()); >+ return oldest.getValue(); >+ } >+ } >+ } >+ return null; >+ } >+ >+ /** >+ * Method used by background thread to check if any JSP's should be destroyed. >+ * If JSP's to be unloaded are found, they will be destroyed. >+ * Uses the lastCheck time from background compiler to determine if it is time to unload JSP's. >+ */ >+ public void checkUnload() { >+ if (options.getMaxLoadedJsps() > 0) { >+ long now = System.currentTimeMillis(); >+ if (now > (lastCheck + (options.getCheckInterval() * 1000L))) { >+ while (unloadJsp()); >+ } >+ } >+ } >+ >+ /** >+ * Checks whether there is a jsp to unload, if one is found, it is destroyed. >+ * */ >+ public boolean unloadJsp() { >+ JspServletWrapper jsw = getJspForUnload(options.getMaxLoadedJsps()); >+ if( null != jsw ) { >+ synchronized(jsw) { >+ jsw.destroy(); >+ return true; >+ } >+ } >+ return false; >+ } > } >Index: java/org/apache/jasper/Options.java >=================================================================== >--- java/org/apache/jasper/Options.java (revision 888769) >+++ java/org/apache/jasper/Options.java (working copy) >@@ -194,4 +194,10 @@ > */ > public Map<String, TagLibraryInfo> getCache(); > >+ /** >+ * The maxim number of loaded jsps per web-application. If there are more >+ * jsps loaded, they will be unloaded. If unset or less than 0, no jsps >+ * are unloaded. >+ */ >+ public int getMaxLoadedJsps(); > } >Index: build.xml >=================================================================== >--- build.xml (revision 888769) >+++ build.xml (working copy) >@@ -859,6 +859,12 @@ > <param name="destfile" value="${commons-daemon.jar}"/> > </antcall> > >+ <mkdir dir="${easymock.dir}" /> >+ <antcall target="downloadfile"> >+ <param name="sourcefile" value="${easymock.loc}"/> >+ <param name="destfile" value="${easymock.jar}"/> >+ </antcall> >+ > <!-- Build Tomcat DBCP bundle --> > <antcall target="downloadgz"> > <param name="sourcefile" value="${commons-pool-src.loc}"/> >@@ -884,7 +890,7 @@ > <param name="basedir" value="${jasper-jdt.home}" /> > </antcall> > >- <antcall target="downloadzip"> >+ <antcall target="downloadzip"> > <param name="sourcefile" value="${nsis.loc}"/> > <param name="destfile" value="${nsis.exe}"/> > <param name="destdir" value="${nsis.home}/.."/> >Index: .classpath >=================================================================== >--- .classpath (revision 888769) >+++ .classpath (working copy) >@@ -7,6 +7,7 @@ > <classpathentry kind="var" path="TOMCAT_LIBS_BASE/eclipse/plugins/org.eclipse.jdt.core_3.3.1.v_780_R33x.jar"/> > <classpathentry kind="var" path="TOMCAT_LIBS_BASE/json-20080701/json.jar"/> > <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/> >+ <classpathentry kind="var" path="TOMCAT_LIBS_BASE/easymock/easymock.2.4.jar"/> > <classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/> > <classpathentry kind="lib" path="output/extras/webservices/jaxrpc.jar"/> > <classpathentry kind="lib" path="output/extras/webservices/wsdl4j.jar"/> >Index: build.properties.default >=================================================================== >--- build.properties.default (revision 888769) >+++ build.properties.default (working copy) >@@ -50,6 +50,12 @@ > # Mirror, was used when there were problems with the main SF downloads site > # base-sf.loc=http://sunet.dl.sourceforge.net > >+# ----- Easymock ---- >+easymock.version=2.4 >+easymock.loc=http://mirrors.ibiblio.org/pub/mirrors/maven2/org/easymock/easymock/${easymock.version}/easymock_{easymock.version}.jar >+easymock.dir=${base.path}/easymock/ >+easymock.jar=${easymock.dir}/easymock.${easymock.version}.jar >+ > # ----- Commons Logging, version 1.1 or later ----- > commons-logging-version=1.1.1 > commons-logging-src.loc=${base-commons.loc}/logging/source/commons-logging-${commons-logging-version}-src.tar.gz
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 48358
:
24684
|
24707
|
26571