### Eclipse Workspace Patch 1.0 #P tomcat-8.0.x diff --git java/org/apache/catalina/core/StandardContext.java java/org/apache/catalina/core/StandardContext.java index 91f5699..6fb38d7 100644 --- java/org/apache/catalina/core/StandardContext.java +++ java/org/apache/catalina/core/StandardContext.java @@ -810,6 +810,8 @@ private String containerSciFilter; + private Boolean failDeploymentIfServletLoadedOnStartupFails; + protected static final ThreadBindingListener DEFAULT_NAMING_LISTENER = (new ThreadBindingListener() { @Override public void bind() {} @@ -2618,8 +2620,32 @@ this.renewThreadsWhenStoppingContext); } - // -------------------------------------------------------- Context Methods + public Boolean isFailDeploymentIfServletLoadedOnStartupFails() { + return failDeploymentIfServletLoadedOnStartupFails; + } + public void setFailDeploymentIfServletLoadedOnStartupFails( + Boolean failDeploymentIfServletLoadedOnStartupFails) { + Boolean oldFailDeploymentIfServletLoadedOnStartupFails = this.failDeploymentIfServletLoadedOnStartupFails; + this.failDeploymentIfServletLoadedOnStartupFails = failDeploymentIfServletLoadedOnStartupFails; + support.firePropertyChange("failDeploymentIfServletLoadedOnStartupFails", + oldFailDeploymentIfServletLoadedOnStartupFails, + failDeploymentIfServletLoadedOnStartupFails); + } + + protected boolean getComputedIsFailDeploymentIfServletLoadedOnStartupFails() { + if(failDeploymentIfServletLoadedOnStartupFails != null) { + return failDeploymentIfServletLoadedOnStartupFails.booleanValue(); + } + //else look at Host config + if(getParent() instanceof StandardHost) { + return ((StandardHost)getParent()).isFailDeploymentIfServletLoadedOnStartupFails(); + } + //else + return false; + } + + // -------------------------------------------------------- Context Methods /** * Add a new Listener class name to the set of Listeners @@ -4888,7 +4914,7 @@ * @param children Array of wrappers for all currently defined * servlets (including those not declared load on startup) */ - public void loadOnStartup(Container children[]) { + public boolean loadOnStartup(Container children[]) { // Collect "load on startup" servlets that need to be initialized TreeMap> map = new TreeMap<>(); @@ -4916,10 +4942,14 @@ getName()), StandardWrapper.getRootCause(e)); // NOTE: load errors (including a servlet that throws // UnavailableException from tht init() method) are NOT - // fatal to application startup + // fatal to application startup, excepted if failDeploymentIfServletLoadedOnStartupFails is specified + if(getComputedIsFailDeploymentIfServletLoadedOnStartupFails()) { + return false; + } } } } + return true; } @@ -5192,7 +5222,10 @@ // Load and initialize all "load on startup" servlets if (ok) { - loadOnStartup(findChildren()); + if (!loadOnStartup(findChildren())){ + log.error("Error loadOnStartup"); + ok = false; + } } // Start ContainerBackgroundProcessor thread diff --git java/org/apache/catalina/core/StandardHost.java java/org/apache/catalina/core/StandardHost.java index 5b6b746..5ef14c2 100644 --- java/org/apache/catalina/core/StandardHost.java +++ java/org/apache/catalina/core/StandardHost.java @@ -182,6 +182,8 @@ private boolean undeployOldVersions = false; + private boolean failDeploymentIfServletLoadedOnStartupFails = false; + // ------------------------------------------------------------- Properties @@ -648,6 +650,21 @@ } + public boolean isFailDeploymentIfServletLoadedOnStartupFails() { + return failDeploymentIfServletLoadedOnStartupFails; + } + + + public void setFailDeploymentIfServletLoadedOnStartupFails( + boolean failDeploymentIfServletLoadedOnStartupFails) { + boolean oldFailDeploymentIfServletLoadedOnStartupFails = this.failDeploymentIfServletLoadedOnStartupFails; + this.failDeploymentIfServletLoadedOnStartupFails = failDeploymentIfServletLoadedOnStartupFails; + support.firePropertyChange("failDeploymentIfServletLoadedOnStartupFails", + oldFailDeploymentIfServletLoadedOnStartupFails, + failDeploymentIfServletLoadedOnStartupFails); + } + + // --------------------------------------------------------- Public Methods diff --git test/org/apache/catalina/core/TestStandardContext.java test/org/apache/catalina/core/TestStandardContext.java index 683258e..e2569b7 100644 --- test/org/apache/catalina/core/TestStandardContext.java +++ test/org/apache/catalina/core/TestStandardContext.java @@ -43,6 +43,7 @@ import javax.servlet.http.HttpServletResponse; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -878,6 +879,63 @@ } @Test + public void testFlagFailDeploymentIfServletLoadedOnStartupFails() + throws Exception { + Tomcat tomcat = getTomcatInstance(); + File docBase = new File(System.getProperty("java.io.tmpdir")); + StandardContext context = (StandardContext) tomcat.addContext("", + docBase.getAbsolutePath()); + + // first we test the flag itself, which can be set on the Host and + // Context + assertFalse(context + .getComputedIsFailDeploymentIfServletLoadedOnStartupFails()); + + StandardHost host = (StandardHost) tomcat.getHost(); + host.setFailDeploymentIfServletLoadedOnStartupFails(true); + assertTrue(context + .getComputedIsFailDeploymentIfServletLoadedOnStartupFails()); + context.setFailDeploymentIfServletLoadedOnStartupFails(Boolean.FALSE); + assertFalse( + "flag on Context should override Host config", + context.getComputedIsFailDeploymentIfServletLoadedOnStartupFails()); + + // second, we test the actual effect of the flag on the startup + Wrapper servlet = Tomcat.addServlet(context, "myservlet", + new FailingStartupServlet()); + servlet.setLoadOnStartup(1); + + tomcat.start(); + assertTrue("flag false should not fail deployment", context.getState() + .isAvailable()); + + tomcat.stop(); + assertFalse(context.getState().isAvailable()); + + host.removeChild(context); + context = (StandardContext) tomcat.addContext("", + docBase.getAbsolutePath()); + //context.setFailDeploymentIfServletLoadedOnStartupFails(Boolean.FALSE); + servlet = Tomcat.addServlet(context, "myservlet", + new FailingStartupServlet()); + servlet.setLoadOnStartup(1); + tomcat.start(); + assertFalse("flag true should fail deployment", context.getState() + .isAvailable()); + } + + private class FailingStartupServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void init() throws ServletException { + throw new ServletException("failing on purpose"); + } + + } + + @Test public void testBug56085() throws Exception { // Set up a container Tomcat tomcat = getTomcatInstance(); diff --git webapps/docs/changelog.xml webapps/docs/changelog.xml index 55cf452..7b3c0d4 100644 --- webapps/docs/changelog.xml +++ webapps/docs/changelog.xml @@ -146,6 +146,11 @@ problem is encountered calling a getter or setter on a component attribute from debug to warning. (markt) + + New failDeploymentIfServletLoadedOnStartupFails attribute + on Context and Host configuration to force the context startup to fail + if a load-on-startup servlet fails its startup. (slaurent) + diff --git webapps/docs/config/context.xml webapps/docs/config/context.xml index e8067a5..1f1f08f 100644 --- webapps/docs/config/context.xml +++ webapps/docs/config/context.xml @@ -334,6 +334,14 @@ sufficient.

+ +

Set to true to have the context fail its startup if any + servlet that has load-on-startup >=0 fails its own startup.

+

If not specified, the attribute of the same name in the parent Host + configuration is used if specified. Otherwise the default value of + false is used.

+
+

Set to true to fire any configured ServletRequestListeners when Tomcat forwards a request. This is diff --git webapps/docs/config/host.xml webapps/docs/config/host.xml index 5154f87..fb6f238 100644 --- webapps/docs/config/host.xml +++ webapps/docs/config/host.xml @@ -175,6 +175,15 @@ Deployment for more information.

+ +

Set to true to have each child contexts fail its startup + if any of its servlet that has load-on-startup >=0 fails its own + startup.

+

Each child context may override this attribute.

+

If not specified, the default value of false is + used.

+
+

Usually the network name of this virtual host, as registered in your Domain Name Service server. Regardless of the case used to