Skip to content
This repository has been archived by the owner on Sep 20, 2022. It is now read-only.

Commit

Permalink
Execute callables within Gumshoe managed context
Browse files Browse the repository at this point in the history
Addresses issue #26 to give callback interfaces to be executed
within a Gumshoe  managed context.  The context will start,
execute the callable, finish the context (or fail it if exception)
then return result (or propagate exception).

Two interfaces are supported -- the standard lib Callable interface
when you care about a return value and the Gumshoe provided
VoidCallable interface when you don't care about a return value.
  • Loading branch information
Lance Woodson committed Aug 25, 2016
1 parent cac62a6 commit df9f66e
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 0 deletions.
39 changes: 39 additions & 0 deletions java/src/main/java/com/bazaarvoice/gumshoe/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;

/**
* A data context for events. Contexts can be stacked. Data can be stored
Expand Down Expand Up @@ -139,6 +140,44 @@ public Context start() {
return this;
}

/**
* Starts a context and calls the Callable within it and returns the result. The context will
* be finished or failed as appropriate. If an exception bubbles out of the Callable, an
* InContextException runtime exception will be thrown.
*
* @param callable
* @return
*/
public <V> V start(Callable<V> callable) {
try {
start();
V result = callable.call();
finish();
return result;
} catch (Exception exception) {
fail(exception);
throw new InContextException(exception);
}
}

/**
* Starts a context and calls the VoidCallable within it. The context will be finished or
* failed as appropriate. If an exception bubbles out of the Callable, an InContextException
* runtime exception will be thrown.
*
* @param callable
*/
public void start(VoidCallable callable) {
try {
start();
callable.call();
finish();
} catch (Exception exception) {
fail(exception);
throw new InContextException(exception);
}
}

/**
* Emits an event within the current context
*
Expand Down
13 changes: 13 additions & 0 deletions java/src/main/java/com/bazaarvoice/gumshoe/InContextException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.bazaarvoice.gumshoe;

/**
* Exception raised when an exception happens within a context.
*
* @author lance.woodson
*
*/
public class InContextException extends RuntimeException {
public InContextException(Exception cause) {
super(cause);
}
}
11 changes: 11 additions & 0 deletions java/src/main/java/com/bazaarvoice/gumshoe/VoidCallable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.bazaarvoice.gumshoe;

/**
* Interface of objects that can be invoked within a context
*
* @author lance.woodson
*
*/
public interface VoidCallable {
void call() throws Exception;
}
80 changes: 80 additions & 0 deletions java/src/test/java/com/bazaarvoice/gumshoe/ContextTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

public class ContextTest extends Assert {
private EventFactory eventFactory;
Expand Down Expand Up @@ -97,6 +98,85 @@ public void ensureStartLoadsEventFactorysDataStack() {
assertEquals(eventFactory.getDataStack().get("foo"), "bar");
}

@Test
public void ensureStartWithCallableReturnsCallableResult() {
String result = context.start(new Callable<String>() {
@Override
public String call() {
return "test";
}
});
assertEquals(result, "test");
}

@Test
public void ensureStartWithCallableFinishesStatus() {
context.start(new Callable<String>() {
@Override
public String call() {
return "test";
}
});
assertEquals(Context.Status.FINISHED, context.getStatus());
}

@Test(expectedExceptions={InContextException.class})
public void ensureStartWithCallableThrowingExceptionPropagatesException() {
context.start(new Callable<String>() {
@Override
public String call() {
throw new RuntimeException("Ooops, I did it again");
}
});
}

@Test
public void ensureStartWithCallableThrowingExceptionFinishesContext() {
try {
context.start(new Callable<String>() {
@Override
public String call() {
throw new RuntimeException("Ooops, I did it again");
}
});
} catch (Exception e) { }
assertEquals(Context.Status.FINISHED, context.getStatus());
}

@Test
public void ensureStartWithVoidCallableFinishesContext() {
context.start(new VoidCallable() {
@Override
public void call() {
// do something
}
});
assertEquals(Context.Status.FINISHED, context.getStatus());
}

@Test(expectedExceptions={InContextException.class})
public void ensureStartWithVoidCallableThrowingExceptionPropagatesException() {
context.start(new VoidCallable() {
@Override
public void call() {
throw new RuntimeException("Ooops, I did it again");
}
});
}

@Test
public void ensureStartWithVoidCallableThrowingExceptionFinishesContext() {
try {
context.start(new VoidCallable() {
@Override
public void call() {
throw new RuntimeException("Ooops, I did it again");
}
});
} catch (Exception e) { }
assertEquals(Context.Status.FINISHED, context.getStatus());
}

@Test(expectedExceptions={IllegalStateException.class})
public void ensureEmitFailsIfContextNotStarted() {
context.emit("test");
Expand Down

0 comments on commit df9f66e

Please sign in to comment.