-----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

Reply via email to