-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Mark,
On 7/31/18 8:03 AM, ma...@apache.org wrote: > Author: markt Date: Tue Jul 31 12:03:26 2018 New Revision: 1837133 > > URL: http://svn.apache.org/viewvc?rev=1837133&view=rev Log: > Introduce a new class - MultiThrowable - to report exceptions when > multiple actions are taken where each action may throw an exception > but all actions are taken before any errors are reported. Use this > new class when reporting multiple container (e.g. web application) > failures during start. Is it worth adding a mention in the javadoc that this class isn't threadsafe? Typically, no mention of thread-safety == not thread safe, but sometimes it's best to be explicit. - -chris > Added: tomcat/trunk/java/org/apache/tomcat/util/MultiThrowable.java > (with props) Modified: > tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java > tomcat/trunk/test/org/apache/catalina/startup/TestTomcat.java > tomcat/trunk/webapps/docs/changelog.xml > > Modified: > tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java URL: > http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/cor e/ContainerBase.java?rev=1837133&r1=1837132&r2=1837133&view=diff > > ======================================================================== ====== > --- tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java > (original) +++ > tomcat/trunk/java/org/apache/catalina/core/ContainerBase.java Tue > Jul 31 12:03:26 2018 @@ -64,6 +64,7 @@ import > org.apache.catalina.util.Lifecycl import > org.apache.juli.logging.Log; import > org.apache.juli.logging.LogFactory; import > org.apache.tomcat.util.ExceptionUtils; +import > org.apache.tomcat.util.MultiThrowable; import > org.apache.tomcat.util.res.StringManager; import > org.apache.tomcat.util.threads.InlineExecutorService; > > @@ -943,31 +944,32 @@ public abstract class ContainerBase exte > results.add(startStopExecutor.submit(new > StartChild(children[i]))); } > > - boolean fail = false; + MultiThrowable > multiThrowable = new MultiThrowable(); + for (Future<Void> result : > results) { try { result.get(); - } catch (Exception e) > { + } catch (Throwable e) { > log.error(sm.getString("containerBase.threadedStartFailed"), e); - > fail = true; + multiThrowable.add(e); } > > } - if (fail) { - throw new LifecycleException( - > sm.getString("containerBase.threadedStartFailed")); + if > (multiThrowable.size() > 0) { + throw new > LifecycleException(sm.getString("containerBase.threadedStartFailed"), > > + multiThrowable.getThrowable()); > } > > // Start the Valves in our pipeline (including the basic), if any - > if (pipeline instanceof Lifecycle) + if (pipeline instanceof > Lifecycle) { ((Lifecycle) pipeline).start(); + } > > > setState(LifecycleState.STARTING); > > // Start our thread threadStart(); - } > > > > Added: > tomcat/trunk/java/org/apache/tomcat/util/MultiThrowable.java URL: > http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/ MultiThrowable.java?rev=1837133&view=auto > > ======================================================================== ====== > --- tomcat/trunk/java/org/apache/tomcat/util/MultiThrowable.java > (added) +++ > tomcat/trunk/java/org/apache/tomcat/util/MultiThrowable.java Tue > Jul 31 12:03:26 2018 @@ -0,0 +1,97 @@ +/* + * Licensed to the > Apache Software Foundation (ASF) under one or more + * contributor > license agreements. See the NOTICE file distributed with + * this > work for additional information regarding copyright ownership. + * > 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. + * See the License for the specific > language governing permissions and + * limitations under the > License. + */ +package org.apache.tomcat.util; + +import > java.util.ArrayList; +import java.util.Collections; +import > java.util.List; + +/** + * Wraps a list of throwables as a single > throwable. This is intended to be used + * when multiple actions > are taken where each may throw an exception but all + * actions are > taken before any errors are reported. + */ +public class > MultiThrowable extends Throwable { + + private static final long > serialVersionUID = 1L; + + private List<Throwable> throwables = > new ArrayList<>(); + + /** + * Add a throwable to the list > of wrapped throwables. + * + * @param t The throwable to > add + */ + public void add(Throwable t) { + > throwables.add(t); + } + + + /** + * @return A read-only > list of the wrapped throwables. + */ + public > List<Throwable> getThrowables() { + return > Collections.unmodifiableList(throwables); + } + + + /** + > * @return {@code null} if there are no wrapped throwables, the > Throwable if + * there is a single wrapped throwable or > the current instance of + * there are multiple wrapped > throwables + */ + public Throwable getThrowable() { + > if (size() == 0) { + return null; + } else if > (size() == 1) { + return throwables.get(0); + } > else { + return this; + } + } + + + /** + > * @return The number of throwables currently wrapped by this > instance. + */ + public int size() { + return > throwables.size(); + } + + + /** + * Overrides the > default implementation to provide a concatenation of the + * > messages associated with each of the wrapped throwables. Note that > the + * format of the returned String is not guaranteed to be > fixed and may + * change in a future release. + */ + > @Override + public String toString() { + StringBuilder sb > = new StringBuilder(); + sb.append(super.toString()); + > sb.append(": "); + sb.append(size()); + sb.append(" > wrapped Throwables: "); + for (Throwable t : throwables) { + > sb.append("["); + sb.append(t.getMessage()); + > sb.append("]"); + } + + return sb.toString(); + } > +} > > Propchange: > tomcat/trunk/java/org/apache/tomcat/util/MultiThrowable.java > ---------------------------------------------------------------------- - -------- > > svn:eol-style = native > > Modified: > tomcat/trunk/test/org/apache/catalina/startup/TestTomcat.java URL: > http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/sta rtup/TestTomcat.java?rev=1837133&r1=1837132&r2=1837133&view=diff > > ======================================================================== ====== > --- tomcat/trunk/test/org/apache/catalina/startup/TestTomcat.java > (original) +++ > tomcat/trunk/test/org/apache/catalina/startup/TestTomcat.java Tue > Jul 31 12:03:26 2018 @@ -38,10 +38,14 @@ import org.junit.Test; > import org.apache.catalina.Context; import > org.apache.catalina.Host; import > org.apache.catalina.LifecycleEvent; +import > org.apache.catalina.LifecycleException; import > org.apache.catalina.LifecycleListener; +import > org.apache.catalina.authenticator.AuthenticatorBase; +import > org.apache.catalina.connector.Request; import > org.apache.catalina.core.StandardContext; import > org.apache.catalina.core.StandardHost; import > org.apache.catalina.ha.context.ReplicatedContext; +import > org.apache.tomcat.util.MultiThrowable; import > org.apache.tomcat.util.buf.ByteChunk; import > org.apache.tomcat.util.descriptor.web.ContextEnvironment; import > org.apache.tomcat.util.descriptor.web.ContextResourceLink; @@ > -554,4 +558,65 @@ public class TestTomcat extends TomcatBa used = > true; } } + + + @Test + public void testBrokenWarOne() throws > Exception { + Tomcat tomcat = getTomcatInstance(); + + > StandardContext ctx = (StandardContext) tomcat.addContext("/a", > null); + ctx.addValve(new BrokenAuthenticator()); + + > try { + tomcat.start(); + Assert.fail(); + > } catch (Throwable t) { + > Assert.assertTrue(getRootCause(t) instanceof LifecycleException); + > } + } + + + @Test + public void testBrokenWarTwo() throws > Exception { + Tomcat tomcat = getTomcatInstance(); + + > StandardContext ctxA = (StandardContext) tomcat.addContext("/a", > null); + ctxA.addValve(new BrokenAuthenticator()); + > StandardContext ctxB = (StandardContext) tomcat.addContext("/b", > null); + ctxB.addValve(new BrokenAuthenticator()); + + > try { + tomcat.start(); + Assert.fail(); + > } catch (Throwable t) { + > Assert.assertTrue(getRootCause(t) instanceof MultiThrowable); + > } + } + + + private static Throwable getRootCause(Throwable > t) { + while (t.getCause() != null && t.getCause() != t) { + > t = t.getCause(); + } + return t; + } + + + > private static class BrokenAuthenticator extends AuthenticatorBase > { + + @Override + protected boolean > doAuthenticate(Request request, HttpServletResponse response) > throws IOException { + return false; + } + + > @Override + protected String getAuthMethod() { + > return null; + } + + @Override + protected > synchronized void startInternal() throws LifecycleException { + > throw new LifecycleException("Deliberately Broken"); + } + > } } > > Modified: tomcat/trunk/webapps/docs/changelog.xml URL: > http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?r ev=1837133&r1=1837132&r2=1837133&view=diff > > ======================================================================== ====== > --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ > tomcat/trunk/webapps/docs/changelog.xml Tue Jul 31 12:03:26 2018 @@ > -70,6 +70,13 @@ <bug>62527</bug>: Revert restriction of JNDI to the > <code>java:</code> namespace. (remm) </fix> + <add> + > Introduce a new class - <code>MultiThrowable</code> - to report + > exceptions when multiple actions are taken where each action may > throw + an exception but all actions are taken before any > errors are reported. + Use this new class when reporting > multiple container (e.g. web + application) failures during > start. (markt) + </add> </changelog> </subsection> <subsection > name="Coyote"> > > > > --------------------------------------------------------------------- > > To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org > For additional commands, e-mail: dev-h...@tomcat.apache.org > -----BEGIN PGP SIGNATURE----- Comment: GPGTools - http://gpgtools.org Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iQIzBAEBCAAdFiEEMmKgYcQvxMe7tcJcHPApP6U8pFgFAltgbJsACgkQHPApP6U8 pFin2w//e11e+U3K+KUtvoJfOb4x86fxKPyJiOsN6Fbt/WRmmsqDM8xx1rzUMYqK SFoZQIHkgfNha9QgjvGUh1DlddX7LSsd9VSoCNzfeHOJksxX9aMsRkLeqX60NsO6 MBAwS/euhcoyOt4JKEJ8eglpAyILz4/HujoX8YFZWEi+DC9bdFaYJI8rawNFNjX/ n7NklVH17U+/d4YmjDLpQ7EizZJF71uLfI+O43AYWtxPe/Pg+wX9FHBk1YtqJk/n FLHQR3nCcdaI+EwBhhQXFI+tKyxlJdC6p0JrNwfMKaYRlDmnjVx5PxdR6HoAezGl ChluWpA0pQqY0NEP5e7zSm9ex3u5Jcaj0gOPS4j+CEgCU8Eqe5cVGtmHFXr/WJVS TPSH39Eqbyrc8LG0v3Vo7yW2U183ihPLYNmQzPsEha8joFn0KFtUDZZJutTN9uWq RFooLLuO3C5A54xEFZfH0O1OYlb6Tu2XjABtG9LDsCk5MxU78GmTbaRRyOdDb1wr wy3hGOGovMOpb+WBaaICEfgNM66GRqUlxYKyLgJMtS/AHqxJnhpGMBoEbXU6ni2+ G2f6ESJzsUcUyqt030ZEz6BSWgVqs0tMLNHZTm7NKP3Ukq9GcIbuQcBXELcAIXBu XtH6mKBLbdEefQO6ot/xiFxKFHf/EMil0b0TOLevJHjhS0YR6oQ= =JhGH -----END PGP SIGNATURE----- --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org