1 package eu.fbk.knowledgestore; 2 3 import java.util.List; 4 5 import com.google.common.base.Preconditions; 6 import com.google.common.collect.ImmutableList; 7 import com.google.common.collect.Iterables; 8 9 // TODO: make OperationException unchecked? 10 11 /** 12 * Signals the failure of a KnowledgeStore {@code Operation} invocation. 13 * <p> 14 * This exception is thrown every time an invocation of a KnowledgeStore {@link Operation} fails. 15 * The outcome attribute (see {@link #getOutcome()}) provides the error / unknown operation 16 * outcome at the root of this exception. The {@code Throwable}s causing this exception (zero or 17 * more) are also stored: method {@link #getCauses()} returns a list with all the causes, while 18 * standard method {@link #getCause()} returns only the last cause of the list (thus, only this 19 * cause will be included in the stacktrace printed by {@link #printStackTrace()}). 20 * </p> 21 */ 22 public class OperationException extends Exception { 23 24 private static final long serialVersionUID = 1L; 25 26 private final Outcome outcome; 27 28 private final List<Throwable> causes; 29 30 /** 31 * Creates a new instance with the outcome and causes vararg array specified. 32 * 33 * @param outcome 34 * the error/unknown outcome for this exception 35 * @param causes 36 * a vararg array with the causes of this exception, possibly empty 37 */ 38 public OperationException(final Outcome outcome, final Throwable... causes) { 39 this(outcome, ImmutableList.copyOf(causes)); 40 } 41 42 /** 43 * Creates a new instance with the outcome and causes {@code Iterable} specified. 44 * 45 * @param outcome 46 * the error/unknown outcome for this exception 47 * @param causes 48 * an iterable with the causes of this exception, not null, possibly empty 49 */ 50 public OperationException(final Outcome outcome, final Iterable<? extends Throwable> causes) { 51 super(messageFor(Preconditions.checkNotNull(outcome), causes), 52 Iterables.isEmpty(causes) ? null : Iterables.getLast(causes)); 53 this.outcome = outcome; 54 this.causes = ImmutableList.copyOf(causes); 55 } 56 57 /** 58 * Returns the error/unknown outcome associated to this exception. 59 * 60 * @return the outcome 61 */ 62 public Outcome getOutcome() { 63 return this.outcome; 64 } 65 66 /** 67 * Returns all the causes of this exception. Causes are reported whenever available; in 68 * particular, {@code OperationException} on single objects are reported in case of 69 * {@code create}, {@code merge}, {@code update}, {@code delete} bulk operations. 70 * 71 * @return the causes associated to this exception 72 */ 73 public List<Throwable> getCauses() { 74 return this.causes; 75 } 76 77 private static String messageFor(final Outcome outcome, 78 final Iterable<? extends Throwable> causes) { 79 final StringBuilder builder = new StringBuilder(); 80 builder.append(outcome); 81 int index = 0; 82 for (final Throwable cause : causes) { 83 builder.append("\n(").append(++index).append(") ") 84 .append(cause.getClass().getSimpleName()).append(" ") 85 .append(cause.getMessage()); 86 } 87 return builder.toString(); 88 } 89 90 }