View | Details | Raw Unified | Return to bug 48358
Collapse All | Expand All

(-)test/org/apache/jasper/EmbeddedServletOptionsTest.java (+56 lines)
Line 0 Link Here
1
package org.apache.jasper;
2
3
import javax.servlet.ServletContext;
4
5
import org.apache.catalina.Container;
6
import org.apache.catalina.Engine;
7
import org.apache.catalina.core.ApplicationContext;
8
import org.apache.catalina.core.StandardContext;
9
import org.apache.catalina.core.StandardEngine;
10
import org.apache.catalina.core.StandardService;
11
import org.apache.catalina.core.StandardWrapper;
12
13
import junit.framework.TestCase;
14
15
/**
16
 * Currently only tests whether maxLoadedJsps initializes correctly.
17
 * */
18
public class EmbeddedServletOptionsTest extends TestCase {
19
  StandardWrapper config;
20
  ServletContext context;
21
22
  protected void setUp() throws Exception {
23
    super.setUp();
24
    config = new StandardWrapper();
25
    StandardContext std1 = new StandardContext();
26
    StandardContext std2 = new StandardContext();
27
    Engine std3 = new StandardEngine();
28
    std3.setService(new StandardService());
29
    std2.setParent(std3);
30
    std1.setParent(std2);
31
    context = new ApplicationContext(std1);
32
  }
33
  
34
  public void testGetMaxLoadedJspsNegative() {
35
    config.addInitParameter("maxLoadedJsps", "-1");
36
    EmbeddedServletOptions options = new EmbeddedServletOptions(config, context);
37
    assertEquals(-1, options.getMaxLoadedJsps());
38
  }
39
40
  public void testGetMaxLoadedJspsDefault() {
41
    EmbeddedServletOptions options = new EmbeddedServletOptions(config, context);
42
    assertEquals(-1, options.getMaxLoadedJsps());
43
  }
44
45
  public void testGetMaxLoadedJspsPositive() {
46
    config.addInitParameter("maxLoadedJsps", "2000");
47
    EmbeddedServletOptions options = new EmbeddedServletOptions(config, context);
48
    assertEquals(2000, options.getMaxLoadedJsps());
49
  }
50
51
  public void testGetMaxLoadedJspsException() {
52
    config.addInitParameter("maxLoadedJsps", "2000abc");
53
    EmbeddedServletOptions options = new EmbeddedServletOptions(config, context);
54
    assertEquals(-1, options.getMaxLoadedJsps());
55
  }
56
}
(-)test/org/apache/jasper/compiler/JspRuntimeContextTest.java (+82 lines)
Line 0 Link Here
1
package org.apache.jasper.compiler;
2
3
import static org.easymock.EasyMock.*;
4
5
import org.apache.catalina.Engine;
6
import org.apache.catalina.core.ApplicationContext;
7
import org.apache.catalina.core.StandardContext;
8
import org.apache.catalina.core.StandardEngine;
9
import org.apache.catalina.core.StandardService;
10
import org.apache.catalina.core.StandardWrapper;
11
import org.apache.jasper.EmbeddedServletOptions;
12
import org.apache.jasper.JasperException;
13
import org.apache.jasper.Options;
14
import org.apache.jasper.servlet.JspServletWrapper;
15
16
import junit.framework.TestCase;
17
18
public class JspRuntimeContextTest extends TestCase {
19
20
  JspRuntimeContext context;
21
  ApplicationContext ctxt;
22
  Options options;
23
24
  protected void setUp() throws Exception {
25
    super.setUp();
26
    StandardWrapper config = new StandardWrapper();
27
    config.addInitParameter("maxLoadedJsps", "2");
28
    StandardContext std1 = new StandardContext();
29
    StandardContext std2 = new StandardContext();
30
    Engine std3 = new StandardEngine();
31
    std3.setService(new StandardService());
32
    std2.setParent(std3);
33
    std1.setParent(std2);
34
    ctxt = new ApplicationContext(std1);
35
    options = new EmbeddedServletOptions(config, ctxt);
36
37
    context = new JspRuntimeContext(ctxt, options);
38
  }
39
40
  public void testCheckUnloadDisabled() {
41
    options = (Options) createMock(Options.class);
42
    expect(options.getScratchDir()).andReturn(null);
43
    expect(options.getClassPath()).andReturn(null);
44
    expect(options.getDevelopment()).andReturn(false);
45
    expect(options.getMaxLoadedJsps()).andReturn(-1);
46
    replay(options);
47
    context = new JspRuntimeContext(ctxt, options);
48
    context.checkUnload();
49
    verify(options);
50
  }
51
52
  public void testCheckUnloadEnabledSizeTooFewJsps() {
53
    options = (Options) createMock(Options.class);
54
    expect(options.getScratchDir()).andReturn(null);
55
    expect(options.getClassPath()).andReturn(null);
56
    expect(options.getDevelopment()).andReturn(false);
57
    expect(options.getMaxLoadedJsps()).andReturn(1);
58
    expect(options.getCheckInterval()).andReturn(0);
59
    expect(options.getMaxLoadedJsps()).andReturn(1);
60
    replay(options);
61
    context = new JspRuntimeContext(ctxt, options);
62
    context.checkUnload();
63
    verify(options);
64
  }
65
66
  public void testCheckUnloadEnabledSizeEnoughJsps() throws JasperException {
67
    options = (Options) createMock(Options.class);
68
    expect(options.getScratchDir()).andReturn(null);
69
    expect(options.getClassPath()).andReturn(null);
70
    expect(options.getDevelopment()).andReturn(false);
71
    expect(options.getMaxLoadedJsps()).andReturn(1);
72
    expect(options.getCheckInterval()).andReturn(0);
73
    expect(options.getMaxLoadedJsps()).andReturn(1);
74
    expect(options.getMaxLoadedJsps()).andReturn(1);
75
    replay(options);
76
    context = new JspRuntimeContext(ctxt, options);
77
    context.addWrapper("first", new JspServletWrapper(new StandardWrapper(), options, "/first.jsp", false, context));
78
    context.addWrapper("second", new JspServletWrapper(new StandardWrapper(), options, "/second.jsp", false, context));
79
    context.checkUnload();
80
    verify(options);
81
  }
82
}
(-)java/org/apache/jasper/JspC.java (+4 lines)
Lines 447-452 Link Here
447
        return cache;
447
        return cache;
448
    }
448
    }
449
449
450
    public int getMaxLoadedJsps() {
451
        return -1;
452
    }
453
450
    /**
454
    /**
451
     * Background compilation check intervals in seconds
455
     * Background compilation check intervals in seconds
452
     */
456
     */
(-)java/org/apache/jasper/servlet/JspServlet.java (+1 lines)
Lines 286-291 Link Here
286
286
287
287
288
    public void periodicEvent() {
288
    public void periodicEvent() {
289
    	  rctxt.checkUnload();
289
        rctxt.checkCompile();
290
        rctxt.checkCompile();
290
    }
291
    }
291
292
(-)java/org/apache/jasper/servlet/JspServletWrapper.java (-1 / +10 lines)
Lines 81-86 Link Here
81
    private JasperException compileException;
81
    private JasperException compileException;
82
    private long servletClassLastModifiedTime;
82
    private long servletClassLastModifiedTime;
83
    private long lastModificationTest = 0L;
83
    private long lastModificationTest = 0L;
84
    private long lastExecutionTime = 0L;
84
85
85
    /*
86
    /*
86
     * JspServletWrapper for JSP pages.
87
     * JspServletWrapper for JSP pages.
Lines 310-315 Link Here
310
311
311
                    // The following sets reload to true, if necessary
312
                    // The following sets reload to true, if necessary
312
                    ctxt.compile();
313
                    ctxt.compile();
314
                    
315
                    if (options.getDevelopment() && options.getMaxLoadedJsps() > 0) {
316
                      ctxt.getRuntimeContext().unloadJsp();
317
                    }
313
                }
318
                }
314
            } else {
319
            } else {
315
                if (compileException != null) {
320
                if (compileException != null) {
Lines 371-377 Link Here
371
            } else {
376
            } else {
372
                theServlet.service(request, response);
377
                theServlet.service(request, response);
373
            }
378
            }
374
379
            this.lastExecutionTime = System.currentTimeMillis();            
375
        } catch (UnavailableException ex) {
380
        } catch (UnavailableException ex) {
376
            String includeRequestUri = (String)
381
            String includeRequestUri = (String)
377
                request.getAttribute("javax.servlet.include.request_uri");
382
                request.getAttribute("javax.servlet.include.request_uri");
Lines 418-423 Link Here
418
        }
423
        }
419
    }
424
    }
420
425
426
    public long getLastExecutionTime() {
427
      return lastExecutionTime;
428
    }
429
421
    public void destroy() {
430
    public void destroy() {
422
        if (theServlet != null) {
431
        if (theServlet != null) {
423
            theServlet.destroy();
432
            theServlet.destroy();
(-)java/org/apache/jasper/EmbeddedServletOptions.java (+25 lines)
Lines 181-186 Link Here
181
    private boolean displaySourceFragment = true;
181
    private boolean displaySourceFragment = true;
182
182
183
    
183
    
184
    /**
185
     * The maxim number of loaded jsps per web-application. If there are more
186
     * jsps loaded, they will be unloaded.
187
     */
188
    private int maxLoadedJsps = -1;
189
184
    public String getProperty(String name ) {
190
    public String getProperty(String name ) {
185
        return settings.getProperty( name );
191
        return settings.getProperty( name );
186
    }
192
    }
Lines 371-376 Link Here
371
    }
377
    }
372
378
373
    /**
379
    /**
380
     * Should any jsps be unloaded? If set to a value greater than 0 eviction of jsps
381
     * is started. Default: -1
382
     * */
383
    public int getMaxLoadedJsps() {
384
        return maxLoadedJsps;
385
    }
386
387
    /**
374
     * Create an EmbeddedServletOptions object using data available from
388
     * Create an EmbeddedServletOptions object using data available from
375
     * ServletConfig and ServletContext. 
389
     * ServletConfig and ServletContext. 
376
     */
390
     */
Lines 639-644 Link Here
639
            }
653
            }
640
        }
654
        }
641
        
655
        
656
        String maxLoadedJsps = config.getInitParameter("maxLoadedJsps");
657
        if (maxLoadedJsps != null) {
658
            try {
659
                this.maxLoadedJsps = Integer.parseInt(maxLoadedJsps);
660
            } catch(NumberFormatException ex) {
661
                if (log.isWarnEnabled()) {
662
                    log.warn(Localizer.getMessage("jsp.warning.maxLoadedJsps", ""+this.maxLoadedJsps));
663
                }
664
            }
665
        }
666
642
        // Setup the global Tag Libraries location cache for this
667
        // Setup the global Tag Libraries location cache for this
643
        // web-application.
668
        // web-application.
644
        tldLocationsCache = new TldLocationsCache(context);
669
        tldLocationsCache = new TldLocationsCache(context);
(-)java/org/apache/jasper/compiler/JspRuntimeContext.java (-1 / +50 lines)
Lines 28-33 Link Here
28
import java.security.cert.Certificate;
28
import java.security.cert.Certificate;
29
import java.util.Iterator;
29
import java.util.Iterator;
30
import java.util.Map;
30
import java.util.Map;
31
import java.util.Map.Entry;
31
import java.util.concurrent.ConcurrentHashMap;
32
import java.util.concurrent.ConcurrentHashMap;
32
import java.util.concurrent.atomic.AtomicInteger;
33
import java.util.concurrent.atomic.AtomicInteger;
33
34
Lines 43-48 Link Here
43
import org.apache.juli.logging.Log;
44
import org.apache.juli.logging.Log;
44
import org.apache.juli.logging.LogFactory;
45
import org.apache.juli.logging.LogFactory;
45
46
47
46
/**
48
/**
47
 * Class for tracking JSP compile time file dependencies when the
49
 * Class for tracking JSP compile time file dependencies when the
48
 * &060;%@include file="..."%&062; directive is used.
50
 * &060;%@include file="..."%&062; directive is used.
Lines 171-177 Link Here
171
     * Maps JSP pages to their JspServletWrapper's
173
     * Maps JSP pages to their JspServletWrapper's
172
     */
174
     */
173
    private Map<String, JspServletWrapper> jsps = new ConcurrentHashMap<String, JspServletWrapper>();
175
    private Map<String, JspServletWrapper> jsps = new ConcurrentHashMap<String, JspServletWrapper>();
174
 
175
176
176
    // ------------------------------------------------------ Public Methods
177
    // ------------------------------------------------------ Public Methods
177
178
Lines 468-472 Link Here
468
        return new SecurityHolder(source, permissions);
469
        return new SecurityHolder(source, permissions);
469
    }
470
    }
470
471
472
    /** Returns a JspServletWrapper that should be destroyed. Default strategy: Least recently used. */
473
    public JspServletWrapper getJspForUnload(final int maxLoadedJsps) {
474
      if( jsps.size() > maxLoadedJsps ) {
475
        synchronized( jsps ) {
476
          Entry<String, JspServletWrapper> oldest = null;
477
          for (Entry<String, JspServletWrapper> jsw : jsps.entrySet()) {
478
            if (!jsw.getValue().isTagFile()) {
479
              if (oldest == null || oldest.getValue().getLastExecutionTime() > jsw.getValue().getLastExecutionTime()) {
480
                oldest = jsw;
481
              }
482
            }
483
          }
471
484
485
          if (oldest != null) {
486
            removeWrapper(oldest.getKey());
487
            return oldest.getValue();
488
          }
489
        }
490
      }
491
      return null;
492
    }
493
494
    /**
495
     * Method used by background thread to check if any JSP's should be destroyed.
496
     * If JSP's to be unloaded are found, they will be destroyed.
497
     * Uses the lastCheck time from background compiler to determine if it is time to unload JSP's.
498
     */
499
    public void checkUnload() {    	
500
      if (options.getMaxLoadedJsps() > 0) {
501
        long now = System.currentTimeMillis();
502
        if (now > (lastCheck + (options.getCheckInterval() * 1000L))) {
503
          while (unloadJsp());
504
        }
505
      }
506
    }
507
    
508
    /**
509
     * Checks whether there is a jsp to unload, if one is found, it is destroyed. 
510
     * */
511
    public boolean unloadJsp() {
512
      JspServletWrapper jsw = getJspForUnload(options.getMaxLoadedJsps());
513
      if( null != jsw ) {
514
        synchronized(jsw) {
515
	  jsw.destroy();
516
	  return true;
517
        }
518
      }
519
      return false;
520
    }
472
}
521
}
(-)java/org/apache/jasper/Options.java (+6 lines)
Lines 194-197 Link Here
194
     */
194
     */
195
    public Map<String, TagLibraryInfo> getCache();
195
    public Map<String, TagLibraryInfo> getCache();
196
    
196
    
197
    /**
198
     * The maxim number of loaded jsps per web-application. If there are more
199
     * jsps loaded, they will be unloaded. If unset or less than 0, no jsps
200
     * are unloaded.
201
     */
202
    public int getMaxLoadedJsps();
197
}
203
}
(-)build.xml (-1 / +7 lines)
Lines 859-864 Link Here
859
      <param name="destfile" value="${commons-daemon.jar}"/>
859
      <param name="destfile" value="${commons-daemon.jar}"/>
860
    </antcall>
860
    </antcall>
861
861
862
    <mkdir dir="${easymock.dir}" />
863
    <antcall target="downloadfile">
864
      <param name="sourcefile" value="${easymock.loc}"/>
865
      <param name="destfile" value="${easymock.jar}"/>
866
    </antcall>
867
862
    <!-- Build Tomcat DBCP bundle -->
868
    <!-- Build Tomcat DBCP bundle -->
863
    <antcall target="downloadgz">
869
    <antcall target="downloadgz">
864
      <param name="sourcefile" value="${commons-pool-src.loc}"/>
870
      <param name="sourcefile" value="${commons-pool-src.loc}"/>
Lines 884-890 Link Here
884
      <param name="basedir" value="${jasper-jdt.home}" />
890
      <param name="basedir" value="${jasper-jdt.home}" />
885
    </antcall>
891
    </antcall>
886
892
887
    <antcall target="downloadzip">
893
   <antcall target="downloadzip">
888
      <param name="sourcefile" value="${nsis.loc}"/>
894
      <param name="sourcefile" value="${nsis.loc}"/>
889
      <param name="destfile" value="${nsis.exe}"/>
895
      <param name="destfile" value="${nsis.exe}"/>
890
  	  <param name="destdir" value="${nsis.home}/.."/>
896
  	  <param name="destdir" value="${nsis.home}/.."/>
(-).classpath (+1 lines)
Lines 7-12 Link Here
7
	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/eclipse/plugins/org.eclipse.jdt.core_3.3.1.v_780_R33x.jar"/>
7
	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/eclipse/plugins/org.eclipse.jdt.core_3.3.1.v_780_R33x.jar"/>
8
	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/json-20080701/json.jar"/>
8
	<classpathentry kind="var" path="TOMCAT_LIBS_BASE/json-20080701/json.jar"/>
9
	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
9
	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
10
        <classpathentry kind="var" path="TOMCAT_LIBS_BASE/easymock/easymock.2.4.jar"/>
10
	<classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/>
11
	<classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/>
11
	<classpathentry kind="lib" path="output/extras/webservices/jaxrpc.jar"/>
12
	<classpathentry kind="lib" path="output/extras/webservices/jaxrpc.jar"/>
12
	<classpathentry kind="lib" path="output/extras/webservices/wsdl4j.jar"/>
13
	<classpathentry kind="lib" path="output/extras/webservices/wsdl4j.jar"/>
(-)build.properties.default (+6 lines)
Lines 50-55 Link Here
50
# Mirror, was used when there were problems with the main SF downloads site
50
# Mirror, was used when there were problems with the main SF downloads site
51
# base-sf.loc=http://sunet.dl.sourceforge.net
51
# base-sf.loc=http://sunet.dl.sourceforge.net
52
52
53
# ----- Easymock ----
54
easymock.version=2.4
55
easymock.loc=http://mirrors.ibiblio.org/pub/mirrors/maven2/org/easymock/easymock/${easymock.version}/easymock_{easymock.version}.jar
56
easymock.dir=${base.path}/easymock/
57
easymock.jar=${easymock.dir}/easymock.${easymock.version}.jar
58
53
# ----- Commons Logging, version 1.1 or later -----
59
# ----- Commons Logging, version 1.1 or later -----
54
commons-logging-version=1.1.1
60
commons-logging-version=1.1.1
55
commons-logging-src.loc=${base-commons.loc}/logging/source/commons-logging-${commons-logging-version}-src.tar.gz
61
commons-logging-src.loc=${base-commons.loc}/logging/source/commons-logging-${commons-logging-version}-src.tar.gz

Return to bug 48358