11d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2009 The Guava Authors 31d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 41d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 51d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * you may not use this file except in compliance with the License. 61d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * You may obtain a copy of the License at 71d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 81d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 91d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Unless required by applicable law or agreed to in writing, software 111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * See the License for the specific language governing permissions and 141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * limitations under the License. 151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertpackage com.google.common.testing; 181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.GwtCompatible; 201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.ArrayList; 221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collection; 231d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport java.util.Collections; 241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert/** 261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * An {@link ClusterException} is a data structure that allows for some code to 271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * "throw multiple exceptions", or something close to it. The prototypical code 281d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * that calls for this class is presented below: 291d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <pre> 311d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * void runManyThings(List<ThingToRun> thingsToRun) { 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * for (ThingToRun thingToRun : thingsToRun) { 331d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * thingToRun.run(); // <-- say this may throw an exception, but you want to 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * // always run all thingsToRun 351d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 361d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 371d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * </pre> 381d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 391d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * This is what the code would become: 401d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <pre> 421d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * void runManyThings(List<ThingToRun> thingsToRun) { 431d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * List<Exception> exceptions = Lists.newArrayList(); 441d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * for (ThingToRun thingToRun : thingsToRun) { 451d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * try { 461d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * thingToRun.run(); 471d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } catch (Exception e) { 481d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * exceptions.add(e); 491d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 501d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 511d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * if (exceptions.size() > 0) { 521d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * throw ClusterException.create(exceptions); 531d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 541d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * } 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * </pre> 561d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 571d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>See semantic details at {@link #create(Collection)}. 581d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 591d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @author Luiz-Otavio Zorzella 601d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 611d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@GwtCompatible 621d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertfinal class ClusterException extends RuntimeException { 631d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 641d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public final Collection<? extends Throwable> exceptions; 651d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 661d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private ClusterException(Collection<? extends Throwable> exceptions) { 671d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert super( 681d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert exceptions.size() + " exceptions were thrown. The first exception is listed as a cause.", 691d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert exceptions.iterator().next()); 701d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ArrayList<Throwable> temp = new ArrayList<Throwable>(); 711d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert temp.addAll(exceptions); 721d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert this.exceptions = Collections.unmodifiableCollection(temp); 731d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 741d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 751d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 761d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @see #create(Collection) 771d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 781d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static RuntimeException create(Throwable... exceptions) { 791d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert ArrayList<Throwable> temp = new ArrayList<Throwable>(); 801d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert for (Throwable exception : exceptions) { 811d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert temp.add(exception); 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return create(temp); 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 851d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 861d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert /** 871d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Given a collection of exceptions, returns a {@link RuntimeException}, with 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the following rules: 891d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <ul> 911d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li>If {@code exceptions} has a single exception and that exception is a 921d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link RuntimeException}, return it 931d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li>If {@code exceptions} has a single exceptions and that exceptions is 941d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <em>not</em> a {@link RuntimeException}, return a simple 951d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@code RuntimeException} that wraps it 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <li>Otherwise, return an instance of {@link ClusterException} that wraps 971d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * the first exception in the {@code exceptions} collection. 981d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * </ul> 991d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1001d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * <p>Though this method takes any {@link Collection}, it often makes most 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * sense to pass a {@link java.util.List} or some other collection that 1021d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * preserves the order in which the exceptions got added. 1031d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * 1041d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws NullPointerException if {@code exceptions} is null 1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @throws IllegalArgumentException if {@code exceptions} is empty 1061d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert */ 1071d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert public static RuntimeException create(Collection<? extends Throwable> exceptions) { 1081d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (exceptions.size() == 0) { 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert throw new IllegalArgumentException( 1101d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert "Can't create an ExceptionCollection with no exceptions"); 1111d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1121d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (exceptions.size() == 1) { 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert Throwable temp = exceptions.iterator().next(); 1141d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert if (temp instanceof RuntimeException) { 1151d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return (RuntimeException)temp; 1161d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } else { 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new RuntimeException(temp); 1181d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return new ClusterException(exceptions); 1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 1221d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert} 123