PushHandler now catches Exception and calls ErrorHandler more.
Change-Id: I7032c00f717b1dae34f4352abc035b1b398c7cfc
import org.atmosphere.cpr.AtmosphereResourceEventListenerAdapter;
import org.json.JSONException;
+import com.vaadin.server.ErrorEvent;
+import com.vaadin.server.ErrorHandler;
import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
import com.vaadin.server.ServiceException;
import com.vaadin.server.ServletPortletHelper;
} else {
callback.run(resource, ui);
}
- } catch (IOException e) {
- getLogger().log(Level.WARNING, "Error writing a push response",
- e);
+ } catch (final IOException e) {
+ callErrorHandler(session, e);
+ } catch (final Exception e) {
+ SystemMessages msg = service.getSystemMessages(
+ ServletPortletHelper.findLocale(null, null,
+ vaadinRequest), vaadinRequest);
+ sendNotificationAndDisconnect(
+ resource,
+ VaadinService.createCriticalNotificationJSON(
+ msg.getInternalErrorCaption(),
+ msg.getInternalErrorMessage(), null,
+ msg.getInternalErrorURL()));
+ callErrorHandler(session, e);
} finally {
- session.unlock();
+ try {
+ session.unlock();
+ } catch (Exception e) {
+ getLogger().log(Level.WARNING,
+ "Error while unlocking session", e);
+ // can't call ErrorHandler, we (hopefully) don't have a lock
+ }
}
} finally {
- service.requestEnd(vaadinRequest, null, session);
+ try {
+ service.requestEnd(vaadinRequest, null, session);
+ } catch (Exception e) {
+ getLogger().log(Level.WARNING, "Error while ending request", e);
+
+ // can't call ErrorHandler, we don't have a lock
+ }
+ }
+ }
+
+ /**
+ * Call the session's {@link ErrorHandler}, if it has one, with the given
+ * exception wrapped in an {@link ErrorEvent}.
+ */
+ private void callErrorHandler(VaadinSession session, Exception e) {
+ try {
+ ErrorHandler errorHandler = ErrorEvent.findErrorHandler(session);
+ if (errorHandler != null) {
+ errorHandler.error(new ErrorEvent(e));
+ }
+ } catch (Exception ex) {
+ // Let's not allow error handling to cause trouble; log fails
+ getLogger().log(Level.WARNING, "ErrorHandler call failed", ex);
}
}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/" />
+<title>PushErrorHandling</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">PushErrorHandling</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/PushErrorHandling?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runPushErrorHandling::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runPushErrorHandling::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VLabel[0]</td>
+ <td>An error! Unable to invoke method click in com.vaadin.shared.ui.button.ButtonServerRpc</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runPushErrorHandling::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>26,7</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runPushErrorHandling::Root/VNotification[0]/HTML[0]/domChild[0]</td>
+ <td>Internal error</td>
+</tr>
+</tbody></table>
+</body>
+</html>
--- /dev/null
+package com.vaadin.tests.push;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.vaadin.data.util.AbstractInMemoryContainer;
+import com.vaadin.data.util.BeanContainer;
+import com.vaadin.event.ItemClickEvent;
+import com.vaadin.event.ItemClickEvent.ItemClickListener;
+import com.vaadin.server.ErrorHandler;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.shared.communication.PushMode;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Table;
+
+public class PushErrorHandling extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ getPushConfiguration().setPushMode(PushMode.AUTOMATIC);
+
+ VaadinSession.getCurrent().setErrorHandler(new ErrorHandler() {
+
+ @Override
+ public void error(com.vaadin.server.ErrorEvent event) {
+ addComponent(new Label("An error! "
+ + event.getThrowable().getMessage()));
+ System.err.println("An error! "
+ + event.getThrowable().getMessage());
+ }
+ });
+
+ final Button button = new Button("Click for NPE!",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ ((String) null).length(); // Null-pointer exception
+ }
+ });
+ addComponent(button);
+
+ final Table view = new Table("testtable");
+ view.setSelectable(true);
+ view.setMultiSelect(false);
+ view.setImmediate(true);
+ view.setSizeFull();
+
+ view.addItemClickListener(new ItemClickListener() {
+
+ @Override
+ public void itemClick(ItemClickEvent event) {
+ BeanContainer<String, AbstractInMemoryContainer> metaContainer = new BeanContainer<String, AbstractInMemoryContainer>(
+ AbstractInMemoryContainer.class) {
+ @Override
+ public Collection<String> getContainerPropertyIds() {
+ List<String> cpropIds = new ArrayList<String>(super
+ .getContainerPropertyIds());
+ cpropIds.add("testid");
+ return cpropIds;
+ }
+
+ @Override
+ public Class<?> getType(Object propertyId) {
+ ((Object) null).hashCode();
+ return super.getType(propertyId);
+ }
+ };
+ view.setContainerDataSource(metaContainer);
+
+ }
+ });
+ view.addContainerProperty("Column", String.class, "Click for NPE");
+ view.addItem(new Object());
+
+ addComponent(view);
+
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Error handling should still work w/ push enabled. (Button can be handled properly, table causes internal error)";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 11882;
+ }
+}