You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/07/07 09:18:36 UTC

[02/10] brooklyn-server git commit: Maybe offers more clarity around whether it creates an exception on Absent

Maybe offers more clarity around whether it creates an exception on Absent

and has a toOptional, and tests


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/785342a4
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/785342a4
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/785342a4

Branch: refs/heads/master
Commit: 785342a4aebe0af47fac1e44205f85c28d320f79
Parents: 1f973df
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Jun 24 22:48:10 2016 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Jun 24 22:52:15 2016 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/util/guava/Maybe.java   |  47 ++++-
 .../apache/brooklyn/util/guava/MaybeTest.java   | 178 +++++++++++++++++++
 2 files changed, 217 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/785342a4/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 f64d712..73c9761 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
@@ -45,29 +45,54 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
 
     private static final long serialVersionUID = -6372099069863179019L;
 
+    /** Returns an absent indicator. No message is available and access does not include any reference to this creation.
+     * Therefore it is fast and simple, but hard to work with if someone might {@link #get()} it and want a useful exception.
+     * See also {@link #absentNoTrace(String)} to include a message with very low overhead,
+     * or {@link #absentWithTrace(String)} or {@link #absent(Throwable)} for more control over the exception thrown. 
+     */
     public static <T> Maybe<T> absent() {
-        return new Absent<T>();
+        return new Maybe.Absent<T>();
     }
 
-    /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message.
-     * Both stack traces (the cause and the callers) are provided, which can be quite handy. */
+    /** Convenience for {@link #absentWithTrace(String)}. */
     public static <T> Maybe<T> absent(final String message) {
+        return absent(new IllegalStateException(message));
+    }
+
+    /** Creates an absent whose {@link #get()} throws an {@link IllegalStateException} with the indicated message.
+     * Both stack traces (the cause and the callers) are provided, which can be quite handy,
+     * but comparatively expensive as the cause stack trace has to generated when this method is invoked,
+     * even if it is never accessed. See also {@link #absentNoTrace(String)} and {@link #absent(Throwable)}. */
+    public static <T> Maybe<T> absentWithTrace(final String message) {
+        return absent(new IllegalStateException(message));
+    }
+
+    /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message,
+     * but not a stack trace for the calling location. As stack traces can be comparatively expensive
+     * this is useful for efficiency, but it can make debugging harder as the origin of the absence is not kept,
+     * in contrast to {@link #absentWithTrace(String)} and {@link #absent(Throwable)}. */
+    public static <T> Maybe<T> absentNoTrace(final String message) {
         return absent(new IllegalStateExceptionSupplier(message));
     }
 
-    /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated cause.
-     * Both stack traces (the cause and the callers) are provided, which can be quite handy. */
+    /** As {@link #absentWithTrace(String)} but using the provided exception instead of this location
+     * as the cause, and a string based on this cause as the message on the {@link IllegalStateException}
+     * thrown if a user does a {@link #get()}. 
+     * Useful if an {@link Exception} has already been generated (and no overhead)
+     * or if you want to supply a specific cause as in <code>absent(new MyException(...))</code>
+     * (but there is the Exception creation overhead there). */
     public static <T> Maybe<T> absent(final Throwable cause) {
         return absent(new IllegalStateExceptionSupplier(cause));
     }
     
-    /** Creates an absent whose get throws an {@link IllegalStateException} with the indicated message and underlying cause.
-     * Both stack traces (the cause and the callers) are provided, which can be quite handy. */
+    /** As {@link #absent(Throwable)} but using the given message as the message on the {@link IllegalStateException}
+     * thrown if a user does a {@link #get()}. */
     public static <T> Maybe<T> absent(final String message, final Throwable cause) {
         return absent(new IllegalStateExceptionSupplier(message, cause));
     }
     
-    /** Creates an absent whose get throws an {@link RuntimeException} generated on demand from the given supplier */
+    /** Creates an absent whose {@link #get()} throws a {@link RuntimeException} 
+     * generated on demand from the given supplier */
     public static <T> Maybe<T> absent(final Supplier<? extends RuntimeException> exceptionSupplier) {
         return new Absent<T>(Preconditions.checkNotNull(exceptionSupplier));
     }
@@ -108,6 +133,12 @@ public abstract class Maybe<T> implements Serializable, Supplier<T> {
     public static <T> Maybe<T> of(@Nullable T value) {
         return ofAllowingNull(value);
     }
+    
+    /** Converts the given {@link Maybe} to {@link Optional}, failing if this {@link Maybe} contains null. */
+    public Optional<T> toOptional() {
+        if (isPresent()) return Optional.of(get());
+        return Optional.absent();
+    }
 
     /** Creates a new Maybe object using {@link #ofDisallowingNull(Object)} semantics. 
      * It is recommended to use that method for clarity. 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/785342a4/utils/common/src/test/java/org/apache/brooklyn/util/guava/MaybeTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/guava/MaybeTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/guava/MaybeTest.java
new file mode 100644
index 0000000..5870303
--- /dev/null
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/guava/MaybeTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.test.Asserts;
+import org.apache.brooklyn.util.exceptions.UserFacingException;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Optional;
+
+public class MaybeTest {
+
+    @Test
+    public void testMaybeGet() {
+        Maybe<String> m = Maybe.of("yes");
+        Assert.assertTrue(m.isPresent());
+        Assert.assertEquals(m.get(), "yes");
+    }
+
+    @Test
+    public void testMaybeToOptional() {
+        Maybe<String> m = Maybe.of("yes");
+        Optional<String> o = m.toOptional();
+        Assert.assertTrue(o.isPresent());
+        Assert.assertEquals(o.get(), "yes");
+    }
+    
+    @Test
+    public void testMaybeGetNull() {
+        Maybe<String> m = Maybe.ofAllowingNull(null);
+        Assert.assertTrue(m.isPresent());
+        Assert.assertEquals(m.get(), null);
+    }
+
+    @Test
+    public void testMaybeDefaultAllowsNull() {
+        // but note you have to cast it if you try to do it explicitly
+        // (of course normally it's a variable...)
+        Maybe<Object> m = Maybe.of((Object)null);
+        Assert.assertTrue(m.isPresent());
+        Assert.assertEquals(m.get(), null);
+    }
+
+    @Test
+    public void testMaybeDisallowingNull() {
+        Maybe<Object> m = Maybe.ofDisallowingNull(null);
+        try {
+            m.get();
+            Asserts.shouldHaveFailedPreviously();
+        } catch (Exception e) {
+            Asserts.expectedFailureContainsIgnoreCase(e, "null");
+        }
+    }
+
+    @Test
+    public void testMaybeToOptionalFailsOnNull() {
+        Maybe<String> m = Maybe.ofAllowingNull(null);
+        try {
+            m.toOptional();
+            Asserts.shouldHaveFailedPreviously();
+        } catch (Exception e) {
+            Asserts.expectedFailureOfType(e, NullPointerException.class);
+        }
+    }
+    
+    @Test
+    public void testMaybeAbsent() {
+        Maybe<String> m = Maybe.absent("nope");
+        Assert.assertFalse(m.isPresent());
+        assertGetFailsContaining(m, "nope");
+    }
+
+    protected Exception assertGetFailsContaining(Maybe<?> m, String phrase) {
+        try {
+            getInExplicitMethod(m);
+            throw Asserts.shouldHaveFailedPreviously();
+        } catch (Exception e) {
+            Asserts.expectedFailureContains(e, phrase);
+            return e;
+        }
+    }
+    
+    @Test
+    public void testMaybeAbsentToOptional() {
+        Maybe<String> m = Maybe.absent("nope");
+        Optional<String> o = m.toOptional();
+        Assert.assertFalse(o.isPresent());
+        try {
+            o.get();
+            throw Asserts.shouldHaveFailedPreviously();
+        } catch (Exception e) {
+            Asserts.expectedFailureContains(e, "absent");
+        }
+    }
+
+    // --- now check traces ----
+    
+    /** an explicit method we can search for in the trace */
+    protected <T> T getInExplicitMethod(Maybe<T> m) {
+        return m.get();
+    }
+    
+    protected boolean containsClassAndMethod(StackTraceElement[] stackTrace, String className, String methodName) {
+        boolean methodFound = (methodName==null);
+        boolean classFound = (className==null);
+        for (StackTraceElement element: stackTrace) {
+            if (className!=null && className.equals(element.getClassName())) classFound = true;
+            if (methodName!=null && methodName.equals(element.getMethodName())) methodFound = true;
+        }
+        return methodFound && classFound;
+    }
+    protected boolean containsGetExplicitMethod(Throwable e) {
+        return containsClassAndMethod(e.getStackTrace(), MaybeTest.class.getName(), "getInExplicitMethod");
+    }
+    protected boolean containsMaybeMethod(Throwable e, String methodName) {
+        return containsClassAndMethod(e.getStackTrace(), Maybe.class.getName(), methodName);
+    }
+    
+    @Test
+    public void testMaybeAbsentMessageIncludesSource() {
+        Maybe<Object> m = Maybe.absent("nope");
+        Assert.assertFalse(m.isPresent());
+        Exception e = assertGetFailsContaining(m, "nope");
+        
+        e.printStackTrace();
+        Assert.assertTrue(containsGetExplicitMethod(e), "Outer trace should be in explicit method");
+        Assert.assertFalse(containsMaybeMethod(e, "absent"), "Outer trace should not be from 'absent'");
+        
+        Assert.assertFalse(containsGetExplicitMethod(e.getCause()), "Inner trace should not be in explicit method");
+        Assert.assertTrue(containsMaybeMethod(e.getCause(), "absent"), "Inner trace should be from 'absent'");
+    }
+
+    @Test
+    public void testMaybeAbsentMessageNoTraceDoesNotIncludeSource() {
+        Maybe<Object> m = Maybe.absentNoTrace("nope");
+        Assert.assertFalse(m.isPresent());
+        Exception e = assertGetFailsContaining(m, "nope");
+        Assert.assertTrue(containsGetExplicitMethod(e), "Outer trace should be in explicit method");
+        Assert.assertFalse(containsMaybeMethod(e, "absentNoTrace"), "Outer trace should not be from 'absentNoTrace'");
+        Assert.assertNull(e.getCause());
+    }
+
+    protected Exception newRE(String message) { return new UserFacingException(message); }
+    
+    @Test
+    public void testMaybeAbsentThrowableIncludesGivenSourceOnly() {
+        Maybe<Object> m = Maybe.absent(newRE("nope"));
+        Assert.assertFalse(m.isPresent());
+        Exception e = assertGetFailsContaining(m, "nope");
+        Assert.assertTrue(e instanceof IllegalStateException, "Outer should be ISE, not "+e);
+        Assert.assertTrue(containsGetExplicitMethod(e), "Outer trace should be in explicit method");
+        Assert.assertFalse(containsMaybeMethod(e, "absent"), "Outer trace should not be from 'absent'");
+        Assert.assertFalse(containsMaybeMethod(e, "newRE"), "Outer trace should not be 'newRE'");
+
+        Assert.assertTrue(e.getCause() instanceof UserFacingException, "Inner should be UFE, not "+e.getCause());
+        Assert.assertFalse(containsGetExplicitMethod(e.getCause()), "Inner trace should not be in explicit method");
+        Assert.assertFalse(containsMaybeMethod(e.getCause(), "absent"), "Inner trace should not be from 'absent'");
+        Assert.assertTrue(containsClassAndMethod(e.getCause().getStackTrace(), MaybeTest.class.getName(), "newRE"), "Inner trace SHOULD be from 'newRE'");
+    }
+
+}