]> source.dussan.org Git - vaadin-framework.git/commitdiff
Replaced ComponentErrorHandler with generic ErrorHandler (#10231) 93/293/7
authorArtur Signell <artur@vaadin.com>
Mon, 19 Nov 2012 11:40:14 +0000 (13:40 +0200)
committerArtur Signell <artur@vaadin.com>
Wed, 21 Nov 2012 13:18:31 +0000 (15:18 +0200)
* Replaced AbstractComponent ErrorHandler with ClientConnector level error handler. Now uses the same ErrorHandler as other parts of the framework.
* Made error handling hierarchical so that the error handler of the connector where the error occured or its ancestors is used. Falls back to VaadinSession ErrorHandler.
* Changed ErrorEvent to be a class as all other events in the framework
* Renamed ErrorListener to ErrorHandler and DefaultErrorListener to DefaultErrorHandler for consistency
* Unified error handling in AbstractCommunicationManager
* Unified error handling in VaadinServlet and VaadinPortlet
* Removed superfluous ErrorEvent implementations (#10232)

Change-Id: Ied518e05209fe54685f4bebab0709b1cd5584fd1

25 files changed:
server/src/com/vaadin/server/AbstractClientConnector.java
server/src/com/vaadin/server/AbstractCommunicationManager.java
server/src/com/vaadin/server/ChangeVariablesErrorEvent.java [deleted file]
server/src/com/vaadin/server/ClientConnector.java
server/src/com/vaadin/server/DefaultErrorHandler.java [new file with mode: 0644]
server/src/com/vaadin/server/DefaultErrorListener.java [deleted file]
server/src/com/vaadin/server/DragAndDropService.java
server/src/com/vaadin/server/ErrorEvent.java
server/src/com/vaadin/server/ErrorHandler.java [new file with mode: 0644]
server/src/com/vaadin/server/ErrorListener.java [deleted file]
server/src/com/vaadin/server/FileResource.java
server/src/com/vaadin/server/LegacyApplication.java
server/src/com/vaadin/server/StreamVariable.java
server/src/com/vaadin/server/VaadinPortlet.java
server/src/com/vaadin/server/VaadinServlet.java
server/src/com/vaadin/server/VaadinSession.java
server/src/com/vaadin/server/VariableOwner.java
server/src/com/vaadin/ui/AbstractComponent.java
server/src/com/vaadin/ui/Component.java
uitest/src/com/vaadin/tests/appengine/GAESyncTest.java
uitest/src/com/vaadin/tests/application/TerminalErrorNotification.java
uitest/src/com/vaadin/tests/components/AbstractComponentTest.java
uitest/src/com/vaadin/tests/components/abstractfield/TextFieldConversions.java
uitest/src/com/vaadin/tests/components/button/ShortCutListenerModification.java
uitest/src/com/vaadin/tests/errorhandler/ErrorHandlers.java [new file with mode: 0644]

index ecdab221603b573e1201b26659d0e6daff94ec45..45c6da7e7744ea9e02766c631fa41cfb213f8e67 100644 (file)
@@ -90,6 +90,8 @@ public abstract class AbstractClientConnector implements ClientConnector,
      */
     private EventRouter eventRouter = null;
 
+    private ErrorHandler errorHandler = null;
+
     /**
      * @deprecated As of 7.0.0, use {@link #markAsDirty()} instead
      */
@@ -951,4 +953,23 @@ public abstract class AbstractClientConnector implements ClientConnector,
 
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.server.ClientConnector#getErrorHandler()
+     */
+    public ErrorHandler getErrorHandler() {
+        return errorHandler;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.server.ClientConnector#setErrorHandler(com.vaadin.server.
+     * ErrorHandler)
+     */
+    public void setErrorHandler(ErrorHandler errorHandler) {
+        this.errorHandler = errorHandler;
+    }
+
 }
index d1180c479b608711133c2b2e4bc868210d1f42d4..86a4f67b4ce366a8689a9487cb5964f39e57cacd 100644 (file)
@@ -63,6 +63,7 @@ import org.json.JSONObject;
 import com.vaadin.annotations.JavaScript;
 import com.vaadin.annotations.PreserveOnRefresh;
 import com.vaadin.annotations.StyleSheet;
+import com.vaadin.server.ClientConnector.ConnectorErrorEvent;
 import com.vaadin.server.ComponentSizeValidator.InvalidLayout;
 import com.vaadin.server.RpcManager.RpcInvocationException;
 import com.vaadin.server.StreamVariable.StreamingEndEvent;
@@ -77,7 +78,6 @@ import com.vaadin.shared.communication.ServerRpc;
 import com.vaadin.shared.communication.SharedState;
 import com.vaadin.shared.communication.UidlValue;
 import com.vaadin.shared.ui.ui.UIConstants;
-import com.vaadin.ui.AbstractField;
 import com.vaadin.ui.Component;
 import com.vaadin.ui.ConnectorTracker;
 import com.vaadin.ui.HasComponents;
@@ -299,8 +299,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
         } catch (Exception e) {
             session.lock();
             try {
-                handleChangeVariablesError(session, (Component) owner, e,
-                        new HashMap<String, Object>());
+                handleConnectorRelatedException(owner, e);
             } finally {
                 session.unlock();
             }
@@ -347,8 +346,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
         } catch (Exception e) {
             session.lock();
             try {
-                handleChangeVariablesError(session, (Component) owner, e,
-                        new HashMap<String, Object>());
+                handleConnectorRelatedException(owner, e);
             } finally {
                 session.unlock();
             }
@@ -1702,13 +1700,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
                         ServerRpcManager.applyInvocation(connector,
                                 (ServerRpcMethodInvocation) invocation);
                     } catch (RpcInvocationException e) {
-                        Throwable realException = e.getCause();
-                        Component errorComponent = null;
-                        if (connector instanceof Component) {
-                            errorComponent = (Component) connector;
-                        }
-                        handleChangeVariablesError(uI.getSession(),
-                                errorComponent, realException, null);
+                        handleConnectorRelatedException(connector, e);
                     }
                 } else {
 
@@ -1730,17 +1722,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
                                             + changes.keySet());
                         }
                     } catch (Exception e) {
-                        Component errorComponent = null;
-                        if (connector instanceof Component) {
-                            errorComponent = (Component) connector;
-                        } else if (connector instanceof DragAndDropService) {
-                            Object dropHandlerOwner = changes.get("dhowner");
-                            if (dropHandlerOwner instanceof Component) {
-                                errorComponent = (Component) dropHandlerOwner;
-                            }
-                        }
-                        handleChangeVariablesError(uI.getSession(),
-                                errorComponent, e, changes);
+                        handleConnectorRelatedException(connector, e);
                     }
                 }
             }
@@ -1755,6 +1737,24 @@ public abstract class AbstractCommunicationManager implements Serializable {
         return success;
     }
 
+    /**
+     * Handles an exception that occurred when processing Rpc calls or a file
+     * upload.
+     * 
+     * @param ui
+     *            The UI where the exception occured
+     * @param throwable
+     *            The exception
+     * @param connector
+     *            The Rpc target
+     */
+    private void handleConnectorRelatedException(ClientConnector connector,
+            Throwable throwable) {
+        ErrorEvent errorEvent = new ConnectorErrorEvent(connector, throwable);
+        ErrorHandler handler = ErrorEvent.findErrorHandler(connector);
+        handler.error(errorEvent);
+    }
+
     /**
      * Parse a message burst from the client into a list of MethodInvocation
      * instances.
@@ -1952,65 +1952,6 @@ public abstract class AbstractCommunicationManager implements Serializable {
         return result;
     }
 
-    public class ErrorHandlerErrorEvent implements ErrorEvent, Serializable {
-        private final Throwable throwable;
-
-        public ErrorHandlerErrorEvent(Throwable throwable) {
-            this.throwable = throwable;
-        }
-
-        @Override
-        public Throwable getThrowable() {
-            return throwable;
-        }
-
-    }
-
-    /**
-     * Handles an error (exception) that occurred when processing variable
-     * changes from the client or a failure of a file upload.
-     * 
-     * For {@link AbstractField} components,
-     * {@link AbstractField#handleError(com.vaadin.ui.AbstractComponent.ComponentErrorEvent)}
-     * is called. In all other cases (or if the field does not handle the
-     * error), {@link ErrorListener#terminalError(ErrorEvent)} for the session
-     * error handler is called.
-     * 
-     * @param session
-     * @param owner
-     *            component that the error concerns
-     * @param e
-     *            exception that occurred
-     * @param m
-     *            map from variable names to values
-     */
-    private void handleChangeVariablesError(VaadinSession session,
-            Component owner, Throwable t, Map<String, Object> m) {
-        boolean handled = false;
-        ChangeVariablesErrorEvent errorEvent = new ChangeVariablesErrorEvent(
-                owner, t, m);
-
-        if (owner instanceof AbstractField) {
-            try {
-                handled = ((AbstractField<?>) owner).handleError(errorEvent);
-            } catch (Exception handlerException) {
-                /*
-                 * If there is an error in the component error handler we pass
-                 * the that error to the session error handler and continue
-                 * processing the actual error
-                 */
-                session.getErrorHandler().terminalError(
-                        new ErrorHandlerErrorEvent(handlerException));
-                handled = false;
-            }
-        }
-
-        if (!handled) {
-            session.getErrorHandler().terminalError(errorEvent);
-        }
-
-    }
-
     /**
      * Unescape encoded burst separator characters in a burst received from the
      * client. This protects from separator injection attacks.
diff --git a/server/src/com/vaadin/server/ChangeVariablesErrorEvent.java b/server/src/com/vaadin/server/ChangeVariablesErrorEvent.java
deleted file mode 100644 (file)
index f208fff..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2011 Vaadin Ltd.
- * 
- * Licensed 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 com.vaadin.server;
-
-import java.util.Map;
-
-import com.vaadin.ui.AbstractComponent.ComponentErrorEvent;
-import com.vaadin.ui.Component;
-
-@SuppressWarnings("serial")
-public class ChangeVariablesErrorEvent implements ComponentErrorEvent {
-
-    private Throwable throwable;
-    private Component component;
-
-    private Map<String, Object> variableChanges;
-
-    public ChangeVariablesErrorEvent(Component component, Throwable throwable,
-            Map<String, Object> variableChanges) {
-        this.component = component;
-        this.throwable = throwable;
-        this.variableChanges = variableChanges;
-    }
-
-    @Override
-    public Throwable getThrowable() {
-        return throwable;
-    }
-
-    public Component getComponent() {
-        return component;
-    }
-
-    public Map<String, Object> getVariableChanges() {
-        return variableChanges;
-    }
-
-}
\ No newline at end of file
index b46ef58fcd7a7daec61e3eca1f4b5813211d59b0..440f2825081d236c4c85e93d6b979c3e077dcb8a 100644 (file)
@@ -37,6 +37,32 @@ import com.vaadin.ui.UI;
  * 
  */
 public interface ClientConnector extends Connector {
+    /**
+     * An error event for connector related errors. Use {@link #getConnector()}
+     * to find the connector where the error occurred or {@link #getComponent()}
+     * to find the nearest parent component.
+     */
+    public static class ConnectorErrorEvent extends
+            com.vaadin.server.ErrorEvent {
+
+        private Connector connector;
+
+        public ConnectorErrorEvent(Connector connector, Throwable t) {
+            super(t);
+            this.connector = connector;
+        }
+
+        /**
+         * Gets the connector for which this error occurred.
+         * 
+         * @return The connector for which the error occurred
+         */
+        public Connector getConnector() {
+            return connector;
+        }
+
+    }
+
     /**
      * Returns the list of pending server to client RPC calls and clears the
      * list.
@@ -249,4 +275,25 @@ public interface ClientConnector extends Connector {
      * @return RpcManager or null if none found for the interface
      */
     public RpcManager getRpcManager(String rpcInterfaceName);
+
+    /**
+     * Gets the error handler for the connector.
+     * 
+     * The error handler is dispatched whenever there is an error processing the
+     * data coming from the client to this connector.
+     * 
+     * @return The error handler or null if not set
+     */
+    public ErrorHandler getErrorHandler();
+
+    /**
+     * Sets the error handler for the connector.
+     * 
+     * The error handler is dispatched whenever there is an error processing the
+     * data coming from the client for this connector.
+     * 
+     * @param errorHandler
+     *            The error handler for this connector
+     */
+    public void setErrorHandler(ErrorHandler errorHandler);
 }
diff --git a/server/src/com/vaadin/server/DefaultErrorHandler.java b/server/src/com/vaadin/server/DefaultErrorHandler.java
new file mode 100644 (file)
index 0000000..de77b48
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ * 
+ * Licensed 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 com.vaadin.server;
+
+import java.net.SocketException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.vaadin.server.ClientConnector.ConnectorErrorEvent;
+import com.vaadin.shared.Connector;
+import com.vaadin.ui.AbstractComponent;
+import com.vaadin.ui.Component;
+
+public class DefaultErrorHandler implements ErrorHandler {
+    @Override
+    public void error(ErrorEvent event) {
+        doDefault(event);
+    }
+
+    public static void doDefault(ErrorEvent event) {
+        final Throwable t = event.getThrowable();
+        if (t instanceof SocketException) {
+            // Most likely client browser closed socket
+            getLogger().info(
+                    "SocketException in CommunicationManager."
+                            + " Most likely client (browser) closed socket.");
+            return;
+        }
+
+        // Finds the original source of the error/exception
+        AbstractComponent component = findAbstractComponent(event);
+        if (component != null) {
+            // Shows the error in AbstractComponent
+            ErrorMessage errorMessage = AbstractErrorMessage
+                    .getErrorMessageForException(t);
+            component.setComponentError(errorMessage);
+        }
+
+        // also print the error on console
+        getLogger().log(Level.SEVERE, "", t);
+    }
+
+    private static Logger getLogger() {
+        return Logger.getLogger(DefaultErrorHandler.class.getName());
+    }
+
+    /**
+     * Returns the AbstractComponent associated with the given error if such can
+     * be found
+     * 
+     * @param event
+     *            The error to investigate
+     * @return The {@link AbstractComponent} to error relates to or null if
+     *         could not be determined or if the error does not relate to any
+     *         AbstractComponent.
+     */
+    public static AbstractComponent findAbstractComponent(
+            com.vaadin.server.ErrorEvent event) {
+        if (event instanceof ConnectorErrorEvent) {
+            Component c = findComponent(((ConnectorErrorEvent) event)
+                    .getConnector());
+            if (c instanceof AbstractComponent) {
+                return (AbstractComponent) c;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Finds the nearest component by traversing upwards in the hierarchy. If
+     * connector is a Component, that Component is returned. Otherwise, looks
+     * upwards in the hierarchy until it finds a {@link Component}.
+     * 
+     * @return A Component or null if no component was found
+     */
+    public static Component findComponent(Connector connector) {
+        if (connector instanceof Component) {
+            return (Component) connector;
+        }
+        if (connector.getParent() != null) {
+            return findComponent(connector.getParent());
+        }
+
+        return null;
+    }
+
+}
\ No newline at end of file
diff --git a/server/src/com/vaadin/server/DefaultErrorListener.java b/server/src/com/vaadin/server/DefaultErrorListener.java
deleted file mode 100644 (file)
index 71fccf8..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2011 Vaadin Ltd.
- * 
- * Licensed 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 com.vaadin.server;
-
-import java.net.SocketException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.vaadin.ui.AbstractComponent;
-
-public class DefaultErrorListener implements ErrorListener {
-    @Override
-    public void terminalError(ErrorEvent event) {
-        doDefault(event);
-    }
-
-    public static void doDefault(ErrorEvent event) {
-        final Throwable t = event.getThrowable();
-        if (t instanceof SocketException) {
-            // Most likely client browser closed socket
-            getLogger().info(
-                    "SocketException in CommunicationManager."
-                            + " Most likely client (browser) closed socket.");
-            return;
-        }
-
-        // Finds the original source of the error/exception
-        Object owner = null;
-        if (event instanceof VariableOwner.ErrorEvent) {
-            owner = ((VariableOwner.ErrorEvent) event).getVariableOwner();
-        } else if (event instanceof ChangeVariablesErrorEvent) {
-            owner = ((ChangeVariablesErrorEvent) event).getComponent();
-        }
-
-        // Shows the error in AbstractComponent
-        if (owner instanceof AbstractComponent) {
-            ((AbstractComponent) owner).setComponentError(AbstractErrorMessage
-                    .getErrorMessageForException(t));
-        }
-
-        // also print the error on console
-        getLogger().log(Level.SEVERE, "Terminal error:", t);
-    }
-
-    private static Logger getLogger() {
-        return Logger.getLogger(DefaultErrorListener.class.getName());
-    }
-}
\ No newline at end of file
index a864f8fb16791f09df9f90001c40622e78e5f063..0fa39fa0e82c29dbb7b3d76d1d43c7353d2f547c 100644 (file)
@@ -53,6 +53,8 @@ public class DragAndDropService implements VariableOwner, ClientConnector {
 
     private AcceptCriterion acceptCriterion;
 
+    private ErrorHandler errorHandler;
+
     public DragAndDropService(AbstractCommunicationManager manager) {
         this.manager = manager;
     }
@@ -346,4 +348,14 @@ public class DragAndDropService implements VariableOwner, ClientConnector {
             VaadinResponse response, String path) throws IOException {
         return false;
     }
+
+    @Override
+    public ErrorHandler getErrorHandler() {
+        return errorHandler;
+    }
+
+    @Override
+    public void setErrorHandler(ErrorHandler errorHandler) {
+        this.errorHandler = errorHandler;
+    }
 }
index b570271cf76b9c606d9b0cb2084554aebe5b9e3f..27754bfae6f93d914d22c426852caa3fa6d2bd34 100644 (file)
@@ -17,14 +17,108 @@ package com.vaadin.server;
 
 import java.io.Serializable;
 
+import com.vaadin.shared.Connector;
+import com.vaadin.ui.UI;
+
 /**
- * An error event implementation for Terminal.
+ * An error thrown by the framework and handled by an {@link ErrorHandler}.
+ * Typically handled by {@link VaadinSession#getErrorHandler()} but can also be
+ * handled by a {@link Connector} specific handler, set using
+ * {@link ClientConnector#setErrorHandler(ErrorHandler)}.
+ * 
  */
-public interface ErrorEvent extends Serializable {
+public class ErrorEvent implements Serializable {
+
+    private Throwable throwable;
+
+    public ErrorEvent(Throwable t) {
+        setThrowable(t);
+    }
 
     /**
      * Gets the contained throwable, the cause of the error.
+     * 
+     * @return
+     */
+    public Throwable getThrowable() {
+        return throwable;
+    }
+
+    public void setThrowable(Throwable throwable) {
+        this.throwable = throwable;
+    }
+
+    /**
+     * Method for finding the error handler for the given connector. Uses
+     * connector hierarchy to find a connector with an error handler. Falls back
+     * to the VaadinSession error handler if no connector has specified an error
+     * handler.
+     * <p>
+     * Returns a {@link DefaultErrorHandler} if no error handler was found
+     * </p>
+     * 
+     * @param connector
+     *            The target connector
+     * @return An ErrorHandler for the connector
+     */
+    public static ErrorHandler findErrorHandler(ClientConnector connector) {
+        if (connector != null) {
+            ErrorHandler errorHandler = connector.getErrorHandler();
+            if (errorHandler != null) {
+                return errorHandler;
+            }
+
+            ClientConnector parent = connector.getParent();
+            if (parent != null) {
+                return findErrorHandler(parent);
+            }
+
+            /*
+             * Reached UI and found no error handler. Try session which
+             * typically has one.
+             */
+            UI ui = connector.getUI();
+            if (ui != null) {
+                errorHandler = findErrorHandler(ui.getSession());
+                if (errorHandler != null) {
+                    return errorHandler;
+                }
+            }
+        }
+
+        /*
+         * No connector known or the connector is not attached to a session. Try
+         * the current session
+         */
+        if (VaadinSession.getCurrent() != null) {
+            ErrorHandler errorHandler = VaadinSession.getCurrent()
+                    .getErrorHandler();
+            if (errorHandler != null) {
+                return errorHandler;
+            }
+        }
+
+        /*
+         * We should never really get here as at least the session should have
+         * an error handler. If for some reason it does not we use the default
+         * error handler.
+         */
+        return new DefaultErrorHandler();
+    }
+
+    /**
+     * Method for finding the error handler for the given session.
+     * 
+     * @param connector
+     *            The target connector
+     * 
+     * @return An ErrorHandler for the session or null if none was found
      */
-    public Throwable getThrowable();
+    public static ErrorHandler findErrorHandler(VaadinSession session) {
+        if (session == null) {
+            return null;
+        }
+        return session.getErrorHandler();
+    }
 
 }
\ No newline at end of file
diff --git a/server/src/com/vaadin/server/ErrorHandler.java b/server/src/com/vaadin/server/ErrorHandler.java
new file mode 100644 (file)
index 0000000..36500a7
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * Licensed 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 com.vaadin.server;
+
+import java.io.Serializable;
+
+/**
+ * Interface for listening to errors in the application.
+ */
+public interface ErrorHandler extends Serializable {
+
+    /**
+     * Invoked when an error occurs.
+     * 
+     * @param event
+     *            the fired event.
+     */
+    public void error(ErrorEvent event);
+}
\ No newline at end of file
diff --git a/server/src/com/vaadin/server/ErrorListener.java b/server/src/com/vaadin/server/ErrorListener.java
deleted file mode 100644 (file)
index 0740085..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2011 Vaadin Ltd.
- *
- * Licensed 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 com.vaadin.server;
-
-import java.io.Serializable;
-
-/**
- * Interface for listening to Terminal errors.
- */
-public interface ErrorListener extends Serializable {
-
-    /**
-     * Invoked when a terminal error occurs.
-     * 
-     * @param event
-     *            the fired event.
-     */
-    public void terminalError(ErrorEvent event);
-}
\ No newline at end of file
index c413bb471dbe5bd544bbed8b9e9b0e2973ec5cc5..42f214c64ae3fe743c9523a1b3a1ea7424936ba8 100644 (file)
@@ -71,18 +71,8 @@ public class FileResource implements ConnectorResource {
             ds.setCacheTime(cacheTime);
             return ds;
         } catch (final FileNotFoundException e) {
-            // Log the exception using the application error handler
-            VaadinSession.getCurrent().getErrorHandler()
-                    .terminalError(new ErrorEvent() {
-
-                        @Override
-                        public Throwable getThrowable() {
-                            return e;
-                        }
-
-                    });
-
-            return null;
+            throw new RuntimeException("File not found: "
+                    + sourceFile.getName(), e);
         }
     }
 
index dc55bca344f3e8a03276644abf1f0511e37be934..598cfbf832826fca620e7e8a89ff308379c643ee 100644 (file)
@@ -38,7 +38,7 @@ import com.vaadin.ui.UI;
  * @since 7.0
  */
 @Deprecated
-public abstract class LegacyApplication implements ErrorListener {
+public abstract class LegacyApplication implements ErrorHandler {
     private LegacyWindow mainWindow;
     private String theme;
 
@@ -208,8 +208,8 @@ public abstract class LegacyApplication implements ErrorListener {
     }
 
     @Override
-    public void terminalError(ErrorEvent event) {
-        DefaultErrorListener.doDefault(event);
+    public void error(ErrorEvent event) {
+        DefaultErrorHandler.doDefault(event);
     }
 
     public VaadinSession getContext() {
index a75cc2f0d714b370ee36518b39693fc9d4adfd55..8a664f22c0f99751e49a9b1a68dd2435046a2b6b 100644 (file)
@@ -151,7 +151,7 @@ public interface StreamVariable extends Serializable {
      * the streaming ended before the end of the input. The streaming may fail
      * due an interruption by {@link } or due an other unknown exception in
      * communication. In the latter case the exception is also passed to
-     * {@link VaadinSession#terminalError(com.vaadin.server.Terminal.ErrorEvent)}
+     * {@link VaadinSession#error(com.vaadin.server.Terminal.ErrorEvent)}
      * .
      */
     public interface StreamingErrorEvent extends StreamingEvent {
index d7d4a65245fa7c6b5ac2f8b10d06cc804bbc4b82..05b6ac360a02831d3aa06e85b289a41b06cd0e6d 100644 (file)
@@ -21,7 +21,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.io.Serializable;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.security.GeneralSecurityException;
@@ -653,6 +652,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
         // portlet
 
         // if this was an UIDL request, response UIDL back to client
+        ErrorHandler errorHandler = ErrorEvent.findErrorHandler(vaadinSession);
         if (getRequestType(request) == RequestType.UIDL) {
             SystemMessages ci = getService().getSystemMessages(
                     ServletPortletHelper.findLocale(null, vaadinSession,
@@ -660,33 +660,17 @@ public class VaadinPortlet extends GenericPortlet implements Constants {
             criticalNotification(request, response,
                     ci.getInternalErrorCaption(), ci.getInternalErrorMessage(),
                     null, ci.getInternalErrorURL());
-            if (vaadinSession != null) {
-                vaadinSession.getErrorHandler().terminalError(
-                        new RequestError(e));
+            if (errorHandler != null) {
+                errorHandler.error(new ErrorEvent(e));
+            }
+        } else {
+            if (errorHandler != null) {
+                errorHandler.error(new ErrorEvent(e));
             } else {
+                // Re-throw other exceptions
                 throw new PortletException(e);
             }
-        } else {
-            // Re-throw other exceptions
-            throw new PortletException(e);
         }
-
-    }
-
-    @SuppressWarnings("serial")
-    public class RequestError implements ErrorEvent, Serializable {
-
-        private final Throwable throwable;
-
-        public RequestError(Throwable throwable) {
-            this.throwable = throwable;
-        }
-
-        @Override
-        public Throwable getThrowable() {
-            return throwable;
-        }
-
     }
 
     /**
index e48153642b2a34b836e67d17af227b00429aca83..3089eccc12aa652c66aeaec19e96dd01fb314121 100644 (file)
@@ -21,7 +21,6 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.io.Serializable;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
@@ -573,6 +572,8 @@ public class VaadinServlet extends HttpServlet implements Constants {
     private void handleServiceException(VaadinServletRequest request,
             VaadinServletResponse response, VaadinSession vaadinSession,
             Throwable e) throws IOException, ServletException {
+        ErrorHandler errorHandler = ErrorEvent.findErrorHandler(vaadinSession);
+
         // if this was an UIDL request, response UIDL back to client
         if (getRequestType(request) == RequestType.UIDL) {
             SystemMessages ci = getService().getSystemMessages(
@@ -581,15 +582,16 @@ public class VaadinServlet extends HttpServlet implements Constants {
             criticalNotification(request, response,
                     ci.getInternalErrorCaption(), ci.getInternalErrorMessage(),
                     null, ci.getInternalErrorURL());
-            if (vaadinSession != null) {
-                vaadinSession.getErrorHandler().terminalError(
-                        new RequestError(e));
+            if (errorHandler != null) {
+                errorHandler.error(new ErrorEvent(e));
+            }
+        } else {
+            if (errorHandler != null) {
+                errorHandler.error(new ErrorEvent(e));
             } else {
+                // Re-throw other exceptions
                 throw new ServletException(e);
             }
-        } else {
-            // Re-throw other exceptions
-            throw new ServletException(e);
         }
 
     }
@@ -1217,21 +1219,6 @@ public class VaadinServlet extends HttpServlet implements Constants {
         return u;
     }
 
-    public class RequestError implements ErrorEvent, Serializable {
-
-        private final Throwable throwable;
-
-        public RequestError(Throwable throwable) {
-            this.throwable = throwable;
-        }
-
-        @Override
-        public Throwable getThrowable() {
-            return throwable;
-        }
-
-    }
-
     /**
      * Escapes characters to html entities. An exception is made for some
      * "safe characters" to keep the text somewhat readable.
index 9bfd03b402c7440c0c93bdae2104f42f9a0a991f..87f5be3e2cc33bfe92a4dac2a597f43af9bb9112 100644 (file)
@@ -90,7 +90,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
      * Session wide error handler which is used by default if an error is left
      * unhandled.
      */
-    private ErrorListener errorHandler = new DefaultErrorListener();
+    private ErrorHandler errorHandler = new DefaultErrorHandler();
 
     /**
      * The converter factory that is used to provide default converters for the
@@ -338,7 +338,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
      * 
      * @return the current error handler
      */
-    public ErrorListener getErrorHandler() {
+    public ErrorHandler getErrorHandler() {
         return errorHandler;
     }
 
@@ -347,7 +347,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
      * 
      * @param errorHandler
      */
-    public void setErrorHandler(ErrorListener errorHandler) {
+    public void setErrorHandler(ErrorHandler errorHandler) {
         this.errorHandler = errorHandler;
     }
 
@@ -388,27 +388,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
         this.converterFactory = converterFactory;
     }
 
-    /**
-     * Application error is an error message defined on the application level.
-     * 
-     * When an error occurs on the application level, this error message4 type
-     * should be used. This indicates that the problem is caused by the
-     * application - not by the user.
-     */
-    public class ApplicationError implements ErrorEvent {
-        private final Throwable throwable;
-
-        public ApplicationError(Throwable throwable) {
-            this.throwable = throwable;
-        }
-
-        @Override
-        public Throwable getThrowable() {
-            return throwable;
-        }
-
-    }
-
     /**
      * Adds a request handler to this session. Request handlers can be added to
      * provide responses to requests that are not handled by the default
index e4319cfaf3ad60121a3c7cfa5b892ef27c5a31e4..825a5804ef65d42b28a2ca0c81bb027a389ea67c 100644 (file)
@@ -81,17 +81,4 @@ public interface VariableOwner extends Serializable {
      */
     public boolean isImmediate();
 
-    /**
-     * VariableOwner error event.
-     */
-    public interface ErrorEvent extends com.vaadin.server.ErrorEvent {
-
-        /**
-         * Gets the source VariableOwner.
-         * 
-         * @return the variable owner.
-         */
-        public VariableOwner getVariableOwner();
-
-    }
 }
index 2ce3e25b2a565b8af338b05719a7b773d0403c23..811a1dc2f65a4e438f0a23ea55bf2d0eab61947a 100644 (file)
@@ -30,6 +30,7 @@ import com.vaadin.event.ShortcutListener;
 import com.vaadin.server.AbstractClientConnector;
 import com.vaadin.server.ClientConnector;
 import com.vaadin.server.ComponentSizeValidator;
+import com.vaadin.server.ErrorHandler;
 import com.vaadin.server.ErrorMessage;
 import com.vaadin.server.Resource;
 import com.vaadin.server.VaadinSession;
@@ -83,7 +84,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
     private static final Pattern sizePattern = Pattern
             .compile("^(-?\\d+(\\.\\d+)?)(%|px|em|ex|in|cm|mm|pt|pc)?$");
 
-    private ComponentErrorHandler errorHandler = null;
+    private ErrorHandler errorHandler = null;
 
     /**
      * Keeps track of the Actions added to this component; the actual
@@ -891,64 +892,6 @@ public abstract class AbstractComponent extends AbstractClientConnector
         }
     }
 
-    public interface ComponentErrorEvent extends com.vaadin.server.ErrorEvent {
-    }
-
-    public interface ComponentErrorHandler extends Serializable {
-        /**
-         * Handle the component error
-         * 
-         * @param event
-         * @return True if the error has been handled False, otherwise
-         */
-        public boolean handleComponentError(ComponentErrorEvent event);
-    }
-
-    /**
-     * Gets the error handler for the component.
-     * 
-     * The error handler is dispatched whenever there is an error processing the
-     * data coming from the client.
-     * 
-     * @return
-     */
-    public ComponentErrorHandler getErrorHandler() {
-        return errorHandler;
-    }
-
-    /**
-     * Sets the error handler for the component.
-     * 
-     * The error handler is dispatched whenever there is an error processing the
-     * data coming from the client.
-     * 
-     * If the error handler is not set, the application error handler is used to
-     * handle the exception.
-     * 
-     * @param errorHandler
-     *            AbstractField specific error handler
-     */
-    public void setErrorHandler(ComponentErrorHandler errorHandler) {
-        this.errorHandler = errorHandler;
-    }
-
-    /**
-     * Handle the component error event.
-     * 
-     * @param error
-     *            Error event to handle
-     * @return True if the error has been handled False, otherwise. If the error
-     *         haven't been handled by this component, it will be handled in the
-     *         application error handler.
-     */
-    public boolean handleError(ComponentErrorEvent error) {
-        if (errorHandler != null) {
-            return errorHandler.handleComponentError(error);
-        }
-        return false;
-
-    }
-
     /*
      * Actions
      */
index 4797bb702c35460d2616061c53b30feda776fba4..85140a83516fb534957fd0bf5bd0d905e7ce84e8 100644 (file)
@@ -953,20 +953,6 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
         }
     }
 
-    /**
-     * Listener interface for receiving <code>Component.Errors</code>s.
-     */
-    public interface ErrorListener extends EventListener, Serializable {
-
-        /**
-         * Notifies the listener of a component error.
-         * 
-         * @param event
-         *            the event that has occured.
-         */
-        public void componentError(Component.ErrorEvent event);
-    }
-
     /**
      * A sub-interface implemented by components that can obtain input focus.
      * This includes all {@link Field} components as well as some other
index f5d90bae79d4af4ca3212e6e0854f472f4d8e471..146e85f5f3206554f9685691c86d2bdd235c7550 100644 (file)
@@ -29,7 +29,7 @@ public class GAESyncTest extends LegacyApplication {
     }
 
     @Override
-    public void terminalError(com.vaadin.server.ErrorEvent event) {
+    public void error(com.vaadin.server.ErrorEvent event) {
         Throwable t = event.getThrowable();
         // Was this caused by a GAE timeout?
         while (t != null) {
@@ -41,7 +41,7 @@ public class GAESyncTest extends LegacyApplication {
             t = t.getCause();
         }
 
-        super.terminalError(event);
+        super.error(event);
 
     }
 
index 9dee2fe0b68d6cfe999831db7403d61061b5a44d..2c8d7e01af4ab61144c574532429cf764a6e0462 100644 (file)
@@ -38,7 +38,7 @@ public class TerminalErrorNotification extends TestBase {
     }
 
     @Override
-    public void terminalError(com.vaadin.server.ErrorEvent event) {
+    public void error(com.vaadin.server.ErrorEvent event) {
         event.getThrowable().printStackTrace();
 
         UI mainWindow = getMainWindow();
index f36437326a79e30445d38cbefeaf14fbfec71fe9..c086e03ae017789aaa7917585d052ac353d8450b 100644 (file)
@@ -715,7 +715,7 @@ public abstract class AbstractComponentTest<T extends AbstractComponent>
     }
 
     @Override
-    public void terminalError(com.vaadin.server.ErrorEvent event) {
+    public void error(com.vaadin.server.ErrorEvent event) {
         String logMsg = "Exception occured, "
                 + event.getThrowable().getClass().getName();
 
index 3a8275bd5141c8c26faffbec359a9aaf59c7e871..888922b69da81f93eb10a526e50cf637d0fd4731 100644 (file)
@@ -5,9 +5,9 @@ import java.util.Date;
 import com.vaadin.data.Property.ValueChangeEvent;
 import com.vaadin.data.Property.ValueChangeListener;
 import com.vaadin.data.util.ObjectProperty;
+import com.vaadin.server.ErrorEvent;
+import com.vaadin.server.ErrorHandler;
 import com.vaadin.server.UserError;
-import com.vaadin.ui.AbstractComponent.ComponentErrorEvent;
-import com.vaadin.ui.AbstractComponent.ComponentErrorHandler;
 import com.vaadin.ui.ComboBox;
 import com.vaadin.ui.TextField;
 
@@ -41,12 +41,11 @@ public class TextFieldConversions extends AbstractComponentDataBindingTest {
 
         tf = new TextField("TextField");
         addComponent(tf);
-        tf.setErrorHandler(new ComponentErrorHandler() {
+        tf.setErrorHandler(new ErrorHandler() {
 
             @Override
-            public boolean handleComponentError(ComponentErrorEvent event) {
+            public void error(ErrorEvent event) {
                 tf.setComponentError(new UserError("Invalid value"));
-                return true;
             }
         });
     }
index 51ca47b4b72ff8024a750c78eb192b94c941799c..9cdd803fe072b044e1448c4d8bc7879e10d07860 100644 (file)
@@ -57,8 +57,8 @@ public class ShortCutListenerModification extends TestBase implements
     }
 
     @Override
-    public void terminalError(com.vaadin.server.ErrorEvent event) {
-        super.terminalError(event);
+    public void error(com.vaadin.server.ErrorEvent event) {
+        super.error(event);
         getMainWindow().showNotification("Failed!",
                 Notification.TYPE_ERROR_MESSAGE);
 
diff --git a/uitest/src/com/vaadin/tests/errorhandler/ErrorHandlers.java b/uitest/src/com/vaadin/tests/errorhandler/ErrorHandlers.java
new file mode 100644 (file)
index 0000000..c5ff1be
--- /dev/null
@@ -0,0 +1,134 @@
+package com.vaadin.tests.errorhandler;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+\r
+import com.vaadin.event.ListenerMethod.MethodException;\r
+import com.vaadin.server.DefaultErrorHandler;\r
+import com.vaadin.server.ErrorHandler;\r
+import com.vaadin.server.RpcManager.RpcInvocationException;\r
+import com.vaadin.server.VaadinRequest;\r
+import com.vaadin.tests.components.AbstractTestUI;\r
+import com.vaadin.ui.Button;\r
+import com.vaadin.ui.Button.ClickEvent;\r
+import com.vaadin.ui.Button.ClickListener;\r
+import com.vaadin.ui.Component;\r
+import com.vaadin.ui.Label;\r
+import com.vaadin.ui.Notification;\r
+import com.vaadin.ui.Notification.Type;\r
+import com.vaadin.ui.VerticalLayout;\r
+\r
+public class ErrorHandlers extends AbstractTestUI {\r
+\r
+    public static class NotificationErrorHandler implements ErrorHandler {\r
+\r
+        @Override\r
+        public void error(com.vaadin.server.ErrorEvent event) {\r
+            Notification.show(getErrorMessage(event), Type.ERROR_MESSAGE);\r
+        }\r
+\r
+    }\r
+\r
+    @Override\r
+    protected void setup(VaadinRequest request) {\r
+        addComponent(runtimeExceptionOnClick(new Button("Standard button")));\r
+        addComponent(npeOnClick(new Button("Standard button with NPE")));\r
+        Button customErrorButton = notificationErrorHandler(new Button(\r
+                "Button with notification error handler"));\r
+        addComponent(runtimeExceptionOnClick(customErrorButton));\r
+\r
+        final VerticalLayout layoutWithErrorHandler = new VerticalLayout(\r
+                runtimeExceptionOnClick(new Button("Error handler on parent")));\r
+        ErrorHandler e = new ErrorHandler() {\r
+\r
+            @Override\r
+            public void error(com.vaadin.server.ErrorEvent event) {\r
+                layoutWithErrorHandler.addComponent(new Label("Layout error: "\r
+                        + getErrorMessage(event)));\r
+            }\r
+\r
+        };\r
+        layoutWithErrorHandler.setErrorHandler(e);\r
+        layoutWithErrorHandler\r
+                .addComponent(notificationErrorHandler(npeOnClick(new Button(\r
+                        "Error handler on button and parent"))));\r
+        addComponent(layoutWithErrorHandler);\r
+    }\r
+\r
+    private Button notificationErrorHandler(Button button) {\r
+        button.setErrorHandler(new NotificationErrorHandler());\r
+        return button;\r
+    }\r
+\r
+    protected static String getErrorMessage(com.vaadin.server.ErrorEvent event) {\r
+        Component c = DefaultErrorHandler.findAbstractComponent(event);\r
+        String errorMsg = "Error: '" + getMessage(event) + "' in ";\r
+        errorMsg += c.getClass().getSimpleName() + " with caption '"\r
+                + c.getCaption() + "'";\r
+        return errorMsg;\r
+    }\r
+\r
+    private static String getMessage(com.vaadin.server.ErrorEvent event) {\r
+        Throwable e = getUserCodeException(event);\r
+        if (e.getMessage() != null) {\r
+            return e.getMessage();\r
+        } else {\r
+            return e.getClass().getSimpleName();\r
+        }\r
+    }\r
+\r
+    private static Throwable getUserCodeException(\r
+            com.vaadin.server.ErrorEvent event) {\r
+        Throwable t = event.getThrowable();\r
+        if (t instanceof RpcInvocationException) {\r
+            t = t.getCause();\r
+        }\r
+        if (t instanceof InvocationTargetException) {\r
+            t = t.getCause();\r
+        }\r
+        if (t instanceof MethodException) {\r
+            t = t.getCause();\r
+        }\r
+\r
+        return t;\r
+\r
+    }\r
+\r
+    private Button runtimeExceptionOnClick(Button customErrorButton) {\r
+        customErrorButton.setCaption("RE: " + customErrorButton.getCaption());\r
+\r
+        customErrorButton.addClickListener(new ClickListener() {\r
+\r
+            @Override\r
+            public void buttonClick(ClickEvent event) {\r
+                throw new RuntimeException("Fail in click event");\r
+            }\r
+        });\r
+        return customErrorButton;\r
+    }\r
+\r
+    private Button npeOnClick(Button customErrorButton) {\r
+        customErrorButton.setCaption("NPE: " + customErrorButton.getCaption());\r
+        customErrorButton.addClickListener(new ClickListener() {\r
+\r
+            @Override\r
+            public void buttonClick(ClickEvent event) {\r
+                Integer i = null;\r
+                i += 2;\r
+            }\r
+        });\r
+        return customErrorButton;\r
+    }\r
+\r
+    @Override\r
+    protected String getTestDescription() {\r
+        // TODO Auto-generated method stub\r
+        return null;\r
+    }\r
+\r
+    @Override\r
+    protected Integer getTicketNumber() {\r
+        // TODO Auto-generated method stub\r
+        return null;\r
+    }\r
+\r
+}\r