| /* |
| * Copyright (c) OSGi Alliance (2016). All Rights Reserved. |
| * |
| * 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.osgi.service.transaction.control; |
| |
| import java.io.Serializable; |
| |
| /** |
| * An Exception that is thrown when a piece of scoped work exits with an |
| * {@link Exception} |
| */ |
| public class ScopedWorkException extends RuntimeException { |
| |
| /** |
| */ |
| private static final long serialVersionUID = 4160254161503114842L; |
| |
| /** |
| * {@link TransactionContext} instances are not required to |
| * be {@link Serializable}, and the ongoing context is very |
| * unlikely to be active post deserialization. As a result |
| * this field is transient. |
| */ |
| private transient final TransactionContext context; |
| |
| /** |
| * Creates a new TransactionException with the supplied message and cause |
| * |
| * @param message |
| * @param cause |
| * @param context |
| */ |
| public ScopedWorkException(String message, Throwable cause, TransactionContext context) { |
| super(message, cause); |
| this.context = context; |
| } |
| |
| /** |
| * @return The ongoing transaction context if the current scope was still |
| * active when this exception was raised or <code>null</code> otherwise. |
| * Note that this property will not be persisted during serialization. |
| */ |
| public TransactionContext ongoingContext() { |
| return context; |
| } |
| |
| /** |
| * @return The cause of this Exception as a {@link RuntimeException} if it |
| * is one, or this otherwise |
| */ |
| public RuntimeException asRuntimeException() { |
| return (RuntimeException) getCause(); |
| } |
| |
| /** |
| * Throws the cause of this Exception as a RuntimeException, or as the supplied |
| * Exception type. |
| * <p> |
| * Usage is of the form: |
| * |
| * <pre> |
| * public void doStuff() throws IOException { |
| * try { |
| * ... |
| * } catch (ScopedWorkException swe) { |
| * throw swe.as(IOException.class); |
| * } |
| * } |
| * </pre> |
| * |
| * @param throwable The exception type to throw |
| * |
| * @return This method will always throw an exception, either: |
| * <ul> |
| * <li>The cause of this exception as the type <T></li> |
| * <li>The cause of this exception as a runtime exception</li> |
| * <li>An IllegalArgumentException with its cause set to <code>this</code></li> |
| * </ul> |
| * |
| * @throws T the type of exception to be thrown |
| * @throws IllegalArgumentException if the cause is not a {@link RuntimeException} or of type T |
| */ |
| public <T extends Throwable> T as(Class<T> throwable) throws T, IllegalArgumentException { |
| Throwable t = getCause(); |
| |
| if (t instanceof RuntimeException) { |
| throw (RuntimeException) t; |
| } |
| |
| possibleThrow(throwable, t); |
| |
| throw new IllegalArgumentException( |
| "The cause of this Exception is not an instance of " |
| + throwable.getName(), |
| this); |
| } |
| |
| /** |
| * Throws the cause of this Exception as a RuntimeException, or as one of the |
| * supplied Exception types. |
| * <p> |
| * Usage is of the form: |
| * |
| * <pre> |
| * public void doStuff() throws IOException, ClassNotFoundException { |
| * try { |
| * ... |
| * } catch (ScopedWorkException swe) { |
| * throw swe.asOneOf(IOException.class, ClassNotFoundException.class); |
| * } |
| * } |
| * </pre> |
| * |
| * @param a The first possible exception type to throw |
| * @param b The second possible exception type to throw |
| * @return This method will always throw an exception, either: |
| * <ul> |
| * <li>The cause of this exception as the type <A></li> |
| * <li>The cause of this exception as the type <B></li> |
| * <li>The cause of this exception as a runtime exception</li> |
| * <li>An IllegalArgumentException with its cause set to <code>this</code></li> |
| * </ul> |
| * @throws A The first possible exception type to throw |
| * @throws B The second possible exception type to throw |
| * @throws IllegalArgumentException if the cause is not a {@link RuntimeException} or of type A or B |
| */ |
| public <A extends Throwable, B extends Throwable> RuntimeException asOneOf( |
| Class<A> a, Class<B> b) throws A, B, IllegalArgumentException { |
| Throwable t = getCause(); |
| |
| if (t instanceof RuntimeException) { |
| throw (RuntimeException) t; |
| } |
| |
| possibleThrow(a, t); |
| possibleThrow(b, t); |
| |
| throw new IllegalArgumentException( |
| "The cause of this Exception is not an instance of " |
| + String.join(", ", a.getName(), b.getName()), |
| this); |
| } |
| |
| /** |
| * Throws the cause of this Exception as a RuntimeException or one of the |
| * supplied Exception types. |
| * |
| * @see #asOneOf(Class, Class) |
| * @param a The first possible exception type to throw |
| * @param b The second possible exception type to throw |
| * @param c The third possible exception type to throw |
| * @return This method will always throw an exception, either: |
| * <ul> |
| * <li>The cause of this exception as the type <A></li> |
| * <li>The cause of this exception as the type <B></li> |
| * <li>The cause of this exception as the type <C></li> |
| * <li>The cause of this exception as a runtime exception</li> |
| * <li>An IllegalArgumentException with its cause set to <code>this</code></li> |
| * </ul> |
| * @throws A The first possible exception type to throw |
| * @throws B The second possible exception type to throw |
| * @throws C The third possible exception type to throw |
| * @throws IllegalArgumentException if the cause is not a {@link RuntimeException} or one of types A, B or C |
| */ |
| public <A extends Throwable, B extends Throwable, C extends Throwable> RuntimeException asOneOf( |
| Class<A> a, Class<B> b, Class<C> c) throws A, B, C, IllegalArgumentException { |
| Throwable t = getCause(); |
| |
| if (t instanceof RuntimeException) { |
| throw (RuntimeException) t; |
| } |
| |
| possibleThrow(a, t); |
| possibleThrow(b, t); |
| possibleThrow(c, t); |
| |
| throw new IllegalArgumentException( |
| "The cause of this Exception is not an instance of " + String |
| .join(", ", a.getName(), b.getName(), c.getName()), |
| this); |
| } |
| |
| /** |
| * Throws the cause of this Exception as a RuntimeException or one of the |
| * supplied Exception types. |
| * |
| * @see #asOneOf(Class, Class) |
| * @param a The first possible exception type to throw |
| * @param b The second possible exception type to throw |
| * @param c The third possible exception type to throw |
| * @param d The fourth possible exception type to throw |
| * @return This method will always throw an exception, either: |
| * <ul> |
| * <li>The cause of this exception as the type <A></li> |
| * <li>The cause of this exception as the type <B></li> |
| * <li>The cause of this exception as the type <C></li> |
| * <li>The cause of this exception as a runtime exception</li> |
| * <li>An IllegalArgumentException with its cause set to <code>this</code></li> |
| * </ul> |
| * @throws A The first possible exception type to throw |
| * @throws B The second possible exception type to throw |
| * @throws C The third possible exception type to throw |
| * @throws D The fourth possible exception type to throw |
| * @throws IllegalArgumentException if the cause is not a {@link RuntimeException} or one of types A, B, C or D |
| */ |
| public <A extends Throwable, B extends Throwable, C extends Throwable, D extends Throwable> RuntimeException asOneOf( |
| Class<A> a, Class<B> b, Class<C> c, Class<D> d) throws A, B, C, D, IllegalArgumentException { |
| Throwable t = getCause(); |
| |
| if (t instanceof RuntimeException) { |
| throw (RuntimeException) t; |
| } |
| |
| possibleThrow(a, t); |
| possibleThrow(b, t); |
| possibleThrow(c, t); |
| possibleThrow(d, t); |
| |
| throw new IllegalArgumentException( |
| "The cause of this Exception is not an instance of " + String |
| .join(", ", a.getName(), b.getName(), c.getName()), |
| this); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <X extends Throwable> void possibleThrow(Class<X> x, Throwable t) |
| throws X { |
| if (x.isInstance(t)) { |
| throw (X) t; |
| } |
| } |
| |
| } |