diff options
author | Leif Åstrand <legioth@gmail.com> | 2018-10-02 14:21:41 +0300 |
---|---|---|
committer | Sun Zhe <31067185+ZheSun88@users.noreply.github.com> | 2018-10-02 14:21:41 +0300 |
commit | 199bff6db17913501c049a7a456a1469af4fbfd2 (patch) | |
tree | 7f4b9c954dc68d9b02343df1e1db7596550c13dd /server | |
parent | 2c14aa2260495ec354bc1a5909318fd8b2edffc7 (diff) | |
download | vaadin-framework-199bff6db17913501c049a7a456a1469af4fbfd2.tar.gz vaadin-framework-199bff6db17913501c049a7a456a1469af4fbfd2.zip |
Suppress unavoidable UIDetachedException (#11146)
* Suppress unavoidable UIDetachedException
Fixes #11144
Diffstat (limited to 'server')
4 files changed, 83 insertions, 13 deletions
diff --git a/server/src/main/java/com/vaadin/server/ErrorHandlingRunnable.java b/server/src/main/java/com/vaadin/server/ErrorHandlingRunnable.java index 2066bfc9f1..a74c31c389 100644 --- a/server/src/main/java/com/vaadin/server/ErrorHandlingRunnable.java +++ b/server/src/main/java/com/vaadin/server/ErrorHandlingRunnable.java @@ -16,6 +16,7 @@ package com.vaadin.server; import java.io.Serializable; +import java.util.Objects; /** * Defines the interface to handle exceptions thrown during the execution of a @@ -28,6 +29,8 @@ public interface ErrorHandlingRunnable extends Runnable, Serializable { /** * Handles exceptions thrown during the execution of a FutureAccess. + * Exceptions thrown by this method are handled by the default error + * handler. * * @since 7.1.8 * @param exception @@ -35,4 +38,38 @@ public interface ErrorHandlingRunnable extends Runnable, Serializable { */ public void handleError(Exception exception); + /** + * Process the given exception in the context of the given runnable. If the + * runnable extends {@link ErrorHandlingRunnable}, then the exception is + * passed to {@link #handleError(Exception)} and null is returned. If + * {@link #handleError(Exception)} throws an exception, that exception is + * returned. If the runnable does not extend {@link ErrorHandlingRunnable}, + * then the original exception is returned. + * + * @since + * @param runnable + * the runnable for which the exception should be processed, not + * <code>null</code> + * @param exception + * the exception to process, not <code>null</code> + * @return the resulting exception, or <code>null</code> if the exception is + * fully processed + */ + public static Exception processException(Runnable runnable, + Exception exception) { + Objects.requireNonNull(runnable, "The runnable cannot be null."); + if (runnable instanceof ErrorHandlingRunnable) { + ErrorHandlingRunnable errorHandlingRunnable = (ErrorHandlingRunnable) runnable; + + try { + errorHandlingRunnable.handleError(exception); + return null; + } catch (Exception exceptionFromHandler) { + return exceptionFromHandler; + } + } + + return exception; + } + } diff --git a/server/src/main/java/com/vaadin/server/VaadinService.java b/server/src/main/java/com/vaadin/server/VaadinService.java index a968a89ac6..1e67db708b 100644 --- a/server/src/main/java/com/vaadin/server/VaadinService.java +++ b/server/src/main/java/com/vaadin/server/VaadinService.java @@ -40,6 +40,7 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; @@ -2047,8 +2048,13 @@ public abstract class VaadinService implements Serializable { try { pendingAccess.get(); - } catch (Exception exception) { + if (exception instanceof ExecutionException) { + Throwable cause = exception.getCause(); + if (cause instanceof Exception) { + exception = (Exception) cause; + } + } pendingAccess.handleError(exception); } } diff --git a/server/src/main/java/com/vaadin/server/VaadinSession.java b/server/src/main/java/com/vaadin/server/VaadinSession.java index 8d246b5696..dd64de4fa5 100644 --- a/server/src/main/java/com/vaadin/server/VaadinSession.java +++ b/server/src/main/java/com/vaadin/server/VaadinSession.java @@ -123,11 +123,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { */ public void handleError(Exception exception) { try { - if (runnable instanceof ErrorHandlingRunnable) { - ErrorHandlingRunnable errorHandlingRunnable = (ErrorHandlingRunnable) runnable; + exception = ErrorHandlingRunnable.processException(runnable, + exception); - errorHandlingRunnable.handleError(exception); - } else { + if (exception != null) { ErrorEvent errorEvent = new ErrorEvent(exception); ErrorHandler errorHandler = ErrorEvent diff --git a/server/src/main/java/com/vaadin/ui/UI.java b/server/src/main/java/com/vaadin/ui/UI.java index 30c01d8cb8..181382603d 100644 --- a/server/src/main/java/com/vaadin/ui/UI.java +++ b/server/src/main/java/com/vaadin/ui/UI.java @@ -230,8 +230,8 @@ public abstract class UI extends AbstractSingleComponentContainer } json.append("]}"); getRpcProxy(DebugWindowClientRpc.class) - .reportLayoutProblems(json.toString()); - } + .reportLayoutProblems(json.toString()); +} @Override public void showServerDesign(Connector connector) { @@ -1567,17 +1567,45 @@ public abstract class UI extends AbstractSingleComponentContainer @Override public void handleError(Exception exception) { try { - if (runnable instanceof ErrorHandlingRunnable) { - ErrorHandlingRunnable errorHandlingRunnable = (ErrorHandlingRunnable) runnable; - - errorHandlingRunnable.handleError(exception); - } else { + exception = ErrorHandlingRunnable.processException(runnable, + exception); + + if (exception instanceof UIDetachedException) { + assert session != null; + /* + * UI was detached after access was run, but before + * accessSynchronously. Furthermore, there wasn't an + * ErrorHandlingRunnable that handled the exception. + */ + getLogger().log(Level.WARNING, + "access() task ignored because UI got detached after the task was enqueued." + + " To suppress this message, change the task to implement {} and make it handle {}." + + " Affected task: {}", + new Object[] { + ErrorHandlingRunnable.class.getName(), + UIDetachedException.class.getName(), + runnable }); + } else if (exception != null) { + /* + * If no ErrorHandlingRunnable, or if it threw an + * exception of its own. + */ ConnectorErrorEvent errorEvent = new ConnectorErrorEvent( UI.this, exception); ErrorHandler errorHandler = com.vaadin.server.ErrorEvent .findErrorHandler(UI.this); + if (errorHandler == null && getSession() == null) { + /* + * Special case where findErrorHandler(UI) cannot + * find the session handler because the UI has + * recently been detached. + */ + errorHandler = com.vaadin.server.ErrorEvent + .findErrorHandler(session); + } + if (errorHandler == null) { errorHandler = new DefaultErrorHandler(); } @@ -1699,7 +1727,7 @@ public abstract class UI extends AbstractSingleComponentContainer // If pushMode is disabled then there should never be a pushConnection; // if enabled there should always be assert (pushConnection == null) - ^ getPushConfiguration().getPushMode().isEnabled(); + ^ getPushConfiguration().getPushMode().isEnabled(); if (pushConnection == this.pushConnection) { return; |