/* * JBoss, Home of Professional Open Source * Copyright 2011, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed 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.jboss.solder.exception.control; import java.io.Serializable; import java.sql.SQLException; import java.util.ArrayDeque; import java.util.Collection; import java.util.Collections; import java.util.Deque; import org.apache.deltaspike.core.api.exception.control.ExceptionStackItem; /** * Information about the current exception and exception cause container. This object is not immutable. */ public class ExceptionStack implements Serializable { private static final long serialVersionUID = 5988683320170873619L; private boolean root; private boolean last; private int initialStackSize; private Throwable next; private Collection<ExceptionStackItem> remaining; private Deque<ExceptionStackItem> exceptionStackItems; private Deque<ExceptionStackItem> origExceptionStackItems; private Collection<Throwable> causes; private Throwable current; /** * Basic constructor, needed to make the class a bean, please don't use */ public ExceptionStack() { } // needed to be a bean /** * Builds the stack from the given exception. * * @param exception Caught exception */ public ExceptionStack(final Throwable exception) { if (exception == null) { throw new IllegalArgumentException("exception must not be null"); } Throwable e = exception; this.exceptionStackItems = new ArrayDeque<ExceptionStackItem>(); do { this.exceptionStackItems.addFirst(new ExceptionStackItem(e)); if (e instanceof SQLException) { SQLException sqlException = (SQLException) e; while (sqlException.getNextException() != null) { sqlException = sqlException.getNextException(); this.exceptionStackItems.addFirst(new ExceptionStackItem(sqlException)); } } } while ((e = e.getCause()) != null); this.initialStackSize = this.exceptionStackItems.size(); this.causes = this.createThrowableCollectionFrom(exceptionStackItems); this.origExceptionStackItems = new ArrayDeque<ExceptionStackItem>(exceptionStackItems); this.init(); } /** * Basic constructor. * * @param causeChainElements collection of all causing elements for an exception from top to bottom (not * unwrapped). * @param currentElementIndex index of current element within the causeChainElements. * @throws IllegalArgumentException if causeChainElements is empty or null. * @deprecated There shouldn't be a use for this, please use the other constructor */ @Deprecated protected ExceptionStack(final Collection<Throwable> causeChainElements, final int currentElementIndex) { if (causeChainElements == null || causeChainElements.size() == 0) { throw new IllegalArgumentException("Null or empty collection of causeChainElements is not valid"); } if (currentElementIndex >= causeChainElements.size()) { throw new IllegalArgumentException("currentElementIndex must be less than or equals to causeChainElements.size()"); } this.exceptionStackItems = new ArrayDeque<ExceptionStackItem>(this.createExceptionStackCollectionFrom(causeChainElements)); this.causes = Collections.unmodifiableCollection(causeChainElements); this.origExceptionStackItems = new ArrayDeque<ExceptionStackItem>(exceptionStackItems); this.init(); } private void init() { this.root = this.exceptionStackItems.size() == this.initialStackSize; if (!this.exceptionStackItems.isEmpty()) { this.current = this.exceptionStackItems.removeFirst().getThrowable(); this.remaining = Collections.unmodifiableCollection(this.exceptionStackItems); } else { this.remaining = Collections.emptyList(); this.current = null; } this.last = this.remaining.isEmpty(); this.next = (this.last) ? null : this.exceptionStackItems.peekFirst().getThrowable(); } private Collection<ExceptionStackItem> createExceptionStackCollectionFrom(Collection<Throwable> throwables) { final Deque<ExceptionStackItem> returningCollection = new ArrayDeque<ExceptionStackItem>(throwables.size()); for (Throwable t : throwables) { returningCollection.addFirst(new ExceptionStackItem(t)); } return returningCollection; } private Collection<Throwable> createThrowableCollectionFrom(final Collection<ExceptionStackItem> exceptionStackItems) { final Deque<Throwable> returningCollection = new ArrayDeque<Throwable>(exceptionStackItems.size() + 1); // allow current for (ExceptionStackItem item : exceptionStackItems) { returningCollection.addFirst(item.getThrowable()); } return returningCollection; } public Collection<Throwable> getCauseElements() { return Collections.unmodifiableCollection(this.causes); } /** * Test if iteration is finished * * @return finished with iteration */ public boolean isLast() { return this.last; } public Throwable getNext() { return this.next; } public Collection<Throwable> getRemaining() { return Collections.unmodifiableCollection(this.createThrowableCollectionFrom(this.remaining)); } /** * Tests if the current exception is the root exception * * @return Returns true if iteration is at the root exception (top of the inverted stack) */ public boolean isRoot() { return this.root; } /** * Current exception in the iteration * * @return current exception */ public Throwable getCurrent() { return this.current; } public void setCauseElements(Collection<Throwable> elements) { this.exceptionStackItems = new ArrayDeque<ExceptionStackItem>(this.createExceptionStackCollectionFrom(elements)); this.init(); } /** * The original exception stack if it has been changed. * * @return The original exception stack */ public Deque<ExceptionStackItem> getOrigExceptionStackItems() { return new ArrayDeque<ExceptionStackItem>(this.origExceptionStackItems); } protected void dropCause() { this.init(); } }