Repository: brooklyn-server Updated Branches: refs/heads/master 8929ef320 -> 6a1eafc68
Maybe gives more control over the exceptions it throws You can do `orThrowingUnwrapped()` to suppress the add'l caller trace, and you can change more easily change the type of the exception it will throw. Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/1f973df5 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/1f973df5 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/1f973df5 Branch: refs/heads/master Commit: 1f973df594cd359d1ad04c52c4f003d18191b339 Parents: a941963 Author: Alex Heneveld <[email protected]> Authored: Fri Jun 24 10:58:38 2016 +0100 Committer: Alex Heneveld <[email protected]> Committed: Fri Jun 24 22:51:32 2016 +0100 ---------------------------------------------------------------------- .../brooklyn/util/exceptions/Exceptions.java | 11 ++++ .../util/guava/AnyExceptionSupplier.java | 66 ++++++++++++++++++++ .../guava/IllegalStateExceptionSupplier.java | 20 ++---- .../org/apache/brooklyn/util/guava/Maybe.java | 41 ++++++++++++ 4 files changed, 122 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1f973df5/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java index 13dcafb..2997f49 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/exceptions/Exceptions.java @@ -39,6 +39,7 @@ import org.apache.brooklyn.util.text.Strings; import com.google.common.annotations.Beta; import com.google.common.base.Predicate; import com.google.common.base.Predicates; +import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -367,6 +368,16 @@ public class Exceptions { return result; } + public static class CollapseTextSupplier implements Supplier<String> { + final Throwable cause; + public CollapseTextSupplier(Throwable cause) { this.cause = cause; } + @Override + public String get() { + return Exceptions.collapseText(cause); + } + public Throwable getOriginal() { return cause; } + } + public static RuntimeException propagate(Collection<? extends Throwable> exceptions) { throw propagate(create(exceptions)); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1f973df5/utils/common/src/main/java/org/apache/brooklyn/util/guava/AnyExceptionSupplier.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/AnyExceptionSupplier.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/AnyExceptionSupplier.java new file mode 100644 index 0000000..7111c39 --- /dev/null +++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/AnyExceptionSupplier.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.brooklyn.util.guava; + +import org.apache.brooklyn.util.exceptions.Exceptions.CollapseTextSupplier; +import org.apache.brooklyn.util.javalang.Reflections; + +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; + +public class AnyExceptionSupplier<T extends Throwable> implements Supplier<T> { + + protected final Class<? extends T> type; + protected final Supplier<String> message; + protected final Throwable cause; + + public AnyExceptionSupplier(Class<T> type) { this(type, (Supplier<String>)null, null); } + public AnyExceptionSupplier(Class<T> type, String message) { this(type, message, null); } + public AnyExceptionSupplier(Class<T> type, Throwable cause) { this(type, new CollapseTextSupplier(cause), cause); } + public AnyExceptionSupplier(Class<T> type, String message, Throwable cause) { this(type, Suppliers.ofInstance(message), cause); } + public AnyExceptionSupplier(Class<? extends T> type, Supplier<String> message, Throwable cause) { + this.type = type; + this.message = message; + this.cause = cause; + } + + @Override + public T get() { + String msg = message==null ? null : message.get(); + Maybe<T> result = Maybe.absent(); + if (result.isAbsent() && msg==null && cause==null) result = Reflections.invokeConstructorWithArgs(type); + if (result.isAbsent() && cause==null) result = Reflections.invokeConstructorWithArgs(type, msg); + if (result.isAbsent() && msg==null) result = Reflections.invokeConstructorWithArgs(type, cause); + if (result.isAbsent()) result = Reflections.invokeConstructorWithArgs(type, msg, cause); + if (result.isAbsent()) { + throw new IllegalStateException("Cannot create desired "+type+" (missing constructor)", + new IllegalStateException(message==null ? null : message.get(), cause)); + } + return result.get(); + } + + public Throwable getCause() { + return cause; + } + + public Supplier<String> getMessageSupplier() { + return message; + } + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1f973df5/utils/common/src/main/java/org/apache/brooklyn/util/guava/IllegalStateExceptionSupplier.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/IllegalStateExceptionSupplier.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/IllegalStateExceptionSupplier.java index a79a8c9..9a36930 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/IllegalStateExceptionSupplier.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/IllegalStateExceptionSupplier.java @@ -18,35 +18,23 @@ */ package org.apache.brooklyn.util.guava; -import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.exceptions.Exceptions.CollapseTextSupplier; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; -public class IllegalStateExceptionSupplier implements Supplier<RuntimeException> { +public class IllegalStateExceptionSupplier extends AnyExceptionSupplier<RuntimeException> { public static final IllegalStateExceptionSupplier EMPTY_EXCEPTION = new IllegalStateExceptionSupplier(); - protected final Supplier<String> message; - protected final Throwable cause; - public IllegalStateExceptionSupplier() { this((Supplier<String>)null, null); } public IllegalStateExceptionSupplier(String message) { this(message, null); } public IllegalStateExceptionSupplier(Throwable cause) { this(new CollapseTextSupplier(cause), cause); } public IllegalStateExceptionSupplier(String message, Throwable cause) { this(Suppliers.ofInstance(message), cause); } - public IllegalStateExceptionSupplier(Supplier<String> message, Throwable cause) { - this.message = message; - this.cause = cause; + public IllegalStateExceptionSupplier(Supplier<String> message, Throwable cause) { + super(IllegalStateException.class, message, cause); } - private static class CollapseTextSupplier implements Supplier<String> { - final Throwable cause; - CollapseTextSupplier(Throwable cause) { this.cause = cause; } - @Override - public String get() { - return Exceptions.collapseText(cause); - } - } @Override public RuntimeException get() { return new IllegalStateException(message==null ? null : message.get(), cause); http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/1f973df5/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java index 6b3df49..f64d712 100644 --- a/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java +++ b/utils/common/src/main/java/org/apache/brooklyn/util/guava/Maybe.java @@ -202,6 +202,23 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> { if (isPresent()) return get(); return null; } + + /** As {@link #get()} but if the Maybe wraps an exception + * (and where {@link #get()} throws a {@link RuntimeException} indicating the caller, + * caused by the exception in original processing) + * this throws the original unwrapped exception + * (masking the caller's location) + * <p> + * As this masks the caller's exception, use with care, typically in a location + * near the original execution, otherwise it can get confusing. + * For instance <code>someCallReturningMaybe().orThrowUnwrapped()</code> is a nice idiom, + * but <code>someMaybeVarReturnedEarlier.orThrowUnwrapped()</code> is usually a bad idea. + * <p> + * The benefit of this is simpler stack traces and preservation of original exception type. + */ + public T orThrowUnwrapped() { + return get(); + } public Set<T> asSet() { if (isPresent()) return ImmutableSet.of(get()); @@ -272,9 +289,33 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> { public T get() { throw getException(); } + public T orThrowUnwrapped() { + throw getException(); + } public RuntimeException getException() { return exception.get(); } + public Supplier<? extends RuntimeException> getExceptionSupplier() { + return exception; + } + public static <T> Maybe<T> changeExceptionSupplier(Maybe<T> original, final Class<? extends RuntimeException> type) { + return changeExceptionSupplier(original, new Function<AnyExceptionSupplier<?>,Supplier<? extends RuntimeException>>() { + @SuppressWarnings("unchecked") + @Override + public Supplier<? extends RuntimeException> apply(AnyExceptionSupplier<?> input) { + if (type.isInstance(input)) return (Supplier<? extends RuntimeException>) input; + return new AnyExceptionSupplier<RuntimeException>(type, input.getMessageSupplier(), input.getCause()); + } + }); + } + public static <T> Maybe<T> changeExceptionSupplier(Maybe<T> original, Function<AnyExceptionSupplier<?>,Supplier<? extends RuntimeException>> transform) { + if (original.isPresent()) return original; + + final Supplier<? extends RuntimeException> supplier = ((Maybe.Absent<?>)original).getExceptionSupplier(); + if (!(supplier instanceof AnyExceptionSupplier)) return original; + + return Maybe.absent(transform.apply((AnyExceptionSupplier<?>)supplier)); + } } public static class AbsentNull<T> extends Absent<T> {
