View Javadoc
1   /*
2    * Copyright (C) 2009 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.testing;
18  
19  import com.google.common.annotations.GwtCompatible;
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.Collections;
24  
25  /**
26   * An {@link ClusterException} is a data structure that allows for some code to "throw multiple
27   * exceptions", or something close to it. The prototypical code that calls for this class is
28   * presented below:
29   *
30   * <pre>
31   * void runManyThings({@literal List<ThingToRun>} thingsToRun) {
32   *   for (ThingToRun thingToRun : thingsToRun) {
33   *     thingToRun.run(); // say this may throw an exception, but you want to
34   *                       // always run all thingsToRun
35   *   }
36   * }
37   * </pre>
38   *
39   * <p>This is what the code would become:
40   *
41   * <pre>
42   * void runManyThings({@literal List<ThingToRun>} thingsToRun) {
43   *   {@literal List<Exception>} exceptions = Lists.newArrayList();
44   *   for (ThingToRun thingToRun : thingsToRun) {
45   *     try {
46   *       thingToRun.run();
47   *     } catch (Exception e) {
48   *       exceptions.add(e);
49   *     }
50   *   }
51   *   if (exceptions.size() &gt; 0) {
52   *     throw ClusterException.create(exceptions);
53   *   }
54   * }
55   * </pre>
56   *
57   * <p>See semantic details at {@link #create(Collection)}.
58   *
59   * @author Luiz-Otavio Zorzella
60   */
61  @GwtCompatible
62  final class ClusterException extends RuntimeException {
63  
64    public final Collection<? extends Throwable> exceptions;
65  
66    private ClusterException(Collection<? extends Throwable> exceptions) {
67      super(
68          exceptions.size() + " exceptions were thrown. The first exception is listed as a cause.",
69          exceptions.iterator().next());
70      ArrayList<Throwable> temp = new ArrayList<>();
71      temp.addAll(exceptions);
72      this.exceptions = Collections.unmodifiableCollection(temp);
73    }
74  
75    /**
76     * @see #create(Collection)
77     */
78    public static RuntimeException create(Throwable... exceptions) {
79      ArrayList<Throwable> temp = new ArrayList<>(Arrays.asList(exceptions));
80      return create(temp);
81    }
82  
83    /**
84     * Given a collection of exceptions, returns a {@link RuntimeException}, with
85     * the following rules:
86     *
87     * <ul>
88     *  <li>If {@code exceptions} has a single exception and that exception is a
89     *    {@link RuntimeException}, return it
90     *  <li>If {@code exceptions} has a single exceptions and that exceptions is
91     *    <em>not</em> a {@link RuntimeException}, return a simple
92     *    {@code RuntimeException} that wraps it
93     *  <li>Otherwise, return an instance of {@link ClusterException} that wraps
94     *    the first exception in the {@code exceptions} collection.
95     * </ul>
96     *
97     * <p>Though this method takes any {@link Collection}, it often makes most
98     * sense to pass a {@link java.util.List} or some other collection that
99     * preserves the order in which the exceptions got added.
100    *
101    * @throws NullPointerException if {@code exceptions} is null
102    * @throws IllegalArgumentException if {@code exceptions} is empty
103    */
104   public static RuntimeException create(Collection<? extends Throwable> exceptions) {
105     if (exceptions.size() == 0) {
106       throw new IllegalArgumentException(
107           "Can't create an ExceptionCollection with no exceptions");
108     }
109     if (exceptions.size() == 1) {
110       Throwable temp = exceptions.iterator().next();
111       if (temp instanceof RuntimeException) {
112         return (RuntimeException)temp;
113       } else {
114         return new RuntimeException(temp);
115       }
116     }
117     return new ClusterException(exceptions);
118   }
119 }