ErrorObserverMiddleware.java
// Copyright (c) ZeroC, Inc.
package com.zeroc.Ice;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
import java.util.function.Consumer;
/**
* Provides a simple middleware that allows applications to observe java.lang.Error thrown by the
* dispatch of an incoming request.
*/
public final class ErrorObserverMiddleware implements Object {
private final Object _next;
private final Consumer<Error> _errorObserver;
/**
* Constructs a ErrorObserverMiddleware.
*
* @param next The next dispatcher in the chain.
* @param errorObserver The error observer. If error observer throws an exception while
* observing an error, this exception replaces the error for the remainder of the dispatch.
*/
public ErrorObserverMiddleware(Object next, Consumer<Error> errorObserver) {
_next = next;
_errorObserver = errorObserver;
}
@Override
public CompletionStage<OutgoingResponse> dispatch(IncomingRequest request)
throws UserException {
try {
return _next.dispatch(request)
.exceptionally(
exception -> {
// _errorObserver can throw an exception that effectively replaces
// exception for dependent completion stages.
if (exception instanceof Error error) {
_errorObserver.accept(error);
throw error;
} else if (exception
instanceof CompletionException completionException
&& completionException.getCause() instanceof Error error) {
// This can occur when the closure of a parent completion stage
// throws an error.
_errorObserver.accept(error);
}
if (exception instanceof RuntimeException runtimeException) {
// Rethrow as-is. Note that Java does not wrap
// CompletionException in CompletionException.
throw runtimeException;
}
// exception is a Throwable that is not an Error or a
// RuntimeException. We can't throw it so we marshal this exception
// into a response.
return request.current.createOutgoingResponse(exception);
});
} catch (Error error) {
// synchronous error
_errorObserver.accept(error);
throw error;
}
}
}