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> {

Reply via email to