if (!running)
break;
}
// Return value, default is to allow continued processing.
RepeatStatus result = RepeatStatus.CONTINUABLE;
RepeatInternalState state = createInternalState(context);
// This is the list of exceptions thrown by all active callbacks
Collection<Throwable> throwables = state.getThrowables();
// Keep a separate list of exceptions we handled that need to be
// rethrown
Collection<Throwable> deferred = new ArrayList<Throwable>();
try {
while (running) {
/*
* Run the before interceptors here, not in the task executor so
* that they all happen in the same thread - it's easier for
* tracking batch status, amongst other things.
*/
for (int i = 0; i < listeners.length; i++) {
RepeatListener interceptor = listeners[i];
interceptor.before(context);
// Allow before interceptors to veto the batch by setting
// flag.
running = running && !isMarkedComplete(context);
}
// Check that we are still running (should always be true) ...
if (running) {
try {
result = getNextResult(context, callback, state);
executeAfterInterceptors(context, result);
}
catch (Throwable throwable) {
doHandle(throwable, context, deferred);
}
// N.B. the order may be important here:
if (isComplete(context, result) || isMarkedComplete(context) || !deferred.isEmpty()) {
running = false;
}
}
}
result = result.and(waitForResults(state));
for (Throwable throwable : throwables) {
doHandle(throwable, context, deferred);
}
// Explicitly drop any references to internal state...