summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonatan Kronqvist <jonatan@vaadin.com>2014-02-06 17:30:40 +0200
committerJonatan Kronqvist <jonatan@vaadin.com>2014-02-06 17:30:41 +0200
commitdc7c1763bb111da6b6964379fbc0ccbe1ab5c8d0 (patch)
treeb4545bfe09c81edf5f3dc77a7fbdbdb96bebb719
parent927c497e78e8907c3d62ed4bacbd4b4bcfe1a580 (diff)
parent1ac492e46b70de9314083492bd8e136e1c8398e3 (diff)
downloadvaadin-framework-dc7c1763bb111da6b6964379fbc0ccbe1ab5c8d0.tar.gz
vaadin-framework-dc7c1763bb111da6b6964379fbc0ccbe1ab5c8d0.zip
Merge changes from origin/7.1
5b2ddc1 Make test work reliably by activating @Push 10ca7ed Catch and log exceptions in session lifecycle listeners (#12915) 8abf434 Move working sass tests from sasslangbroken to sasslang. 1ac492e Move a sass test that no longer fails. Change-Id: I960e80fd2120c20bc7b042eccbadb1e748ec0f00
-rw-r--r--server/src/com/vaadin/event/EventRouter.java39
-rw-r--r--server/src/com/vaadin/server/VaadinService.java15
-rw-r--r--server/tests/src/com/vaadin/tests/event/EventRouterTest.java111
-rw-r--r--uitest/src/com/vaadin/tests/push/PushFromInit.java53
-rw-r--r--uitest/src/com/vaadin/tests/push/PushFromInitTest.java28
5 files changed, 212 insertions, 34 deletions
diff --git a/server/src/com/vaadin/event/EventRouter.java b/server/src/com/vaadin/event/EventRouter.java
index 73bfa33881..fdc543143b 100644
--- a/server/src/com/vaadin/event/EventRouter.java
+++ b/server/src/com/vaadin/event/EventRouter.java
@@ -23,6 +23,10 @@ import java.util.EventObject;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.logging.Logger;
+
+import com.vaadin.server.ErrorEvent;
+import com.vaadin.server.ErrorHandler;
/**
* <code>EventRouter</code> class implementing the inheritable event listening
@@ -154,6 +158,25 @@ public class EventRouter implements MethodEventSource {
* the Event to be sent to all listeners.
*/
public void fireEvent(EventObject event) {
+ fireEvent(event, null);
+ }
+
+ /**
+ * Sends an event to all registered listeners. The listeners will decide if
+ * the activation method should be called or not.
+ * <p>
+ * If an error handler is set, the processing of other listeners will
+ * continue after the error handler method call unless the error handler
+ * itself throws an exception.
+ *
+ * @param event
+ * the Event to be sent to all listeners.
+ * @param errorHandler
+ * error handler to use to handle any exceptions thrown by
+ * listeners or null to let the exception propagate to the
+ * caller, preventing further listener calls
+ */
+ public void fireEvent(EventObject event, ErrorHandler errorHandler) {
// It is not necessary to send any events if there are no listeners
if (listenerList != null) {
@@ -164,7 +187,16 @@ public class EventRouter implements MethodEventSource {
// will filter out unwanted events.
final Object[] listeners = listenerList.toArray();
for (int i = 0; i < listeners.length; i++) {
- ((ListenerMethod) listeners[i]).receiveEvent(event);
+ ListenerMethod listenerMethod = (ListenerMethod) listeners[i];
+ if (null != errorHandler) {
+ try {
+ listenerMethod.receiveEvent(event);
+ } catch (Exception e) {
+ errorHandler.error(new ErrorEvent(e));
+ }
+ } else {
+ listenerMethod.receiveEvent(event);
+ }
}
}
@@ -208,4 +240,9 @@ public class EventRouter implements MethodEventSource {
}
return listeners;
}
+
+ private Logger getLogger() {
+ return Logger.getLogger(EventRouter.class.getName());
+ }
+
}
diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java
index aff0124d16..b457436b8f 100644
--- a/server/src/com/vaadin/server/VaadinService.java
+++ b/server/src/com/vaadin/server/VaadinService.java
@@ -420,6 +420,9 @@ public abstract class VaadinService implements Serializable {
/**
* Adds a listener that gets notified when a Vaadin service session that has
* been initialized for this service is destroyed.
+ * <p>
+ * The session being destroyed is locked and its UIs have been removed when
+ * the listeners are called.
*
* @see #addSessionInitListener(SessionInitListener)
*
@@ -461,8 +464,11 @@ public abstract class VaadinService implements Serializable {
}
});
}
+ // for now, use the session error handler; in the future, could
+ // have an API for using some other handler for session init and
+ // destroy listeners
eventRouter.fireEvent(new SessionDestroyEvent(
- VaadinService.this, session));
+ VaadinService.this, session), session.getErrorHandler());
}
});
}
@@ -776,7 +782,12 @@ public abstract class VaadinService implements Serializable {
private void onVaadinSessionStarted(VaadinRequest request,
VaadinSession session) throws ServiceException {
- eventRouter.fireEvent(new SessionInitEvent(this, session, request));
+ // for now, use the session error handler; in the future, could have an
+ // API for using some other handler for session init and destroy
+ // listeners
+
+ eventRouter.fireEvent(new SessionInitEvent(this, session, request),
+ session.getErrorHandler());
ServletPortletHelper.checkUiProviders(session, this);
}
diff --git a/server/tests/src/com/vaadin/tests/event/EventRouterTest.java b/server/tests/src/com/vaadin/tests/event/EventRouterTest.java
new file mode 100644
index 0000000000..dbbeaf778e
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/event/EventRouterTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2000-2013 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.tests.event;
+
+import java.lang.reflect.Method;
+
+import org.easymock.EasyMock;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.event.EventRouter;
+import com.vaadin.server.ErrorEvent;
+import com.vaadin.server.ErrorHandler;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Component.Listener;
+import com.vaadin.util.ReflectTools;
+
+/**
+ * Test EventRouter and related error handling.
+ */
+public class EventRouterTest {
+
+ private static final Method COMPONENT_EVENT_METHOD = ReflectTools
+ .findMethod(Component.Listener.class, "componentEvent",
+ Component.Event.class);
+
+ private EventRouter router;
+ private Component component;
+ private ErrorHandler errorHandler;
+ private Listener listener;
+
+ @Before
+ public void createMocks() {
+ router = new EventRouter();
+ component = EasyMock.createNiceMock(Component.class);
+ errorHandler = EasyMock.createMock(ErrorHandler.class);
+ listener = EasyMock.createMock(Component.Listener.class);
+ router.addListener(Component.Event.class, listener,
+ COMPONENT_EVENT_METHOD);
+ }
+
+ @Test
+ public void fireEvent_noException_eventReceived() {
+ listener.componentEvent(EasyMock.<Component.Event> anyObject());
+
+ EasyMock.replay(component, listener, errorHandler);
+ router.fireEvent(new Component.Event(component), errorHandler);
+ EasyMock.verify(listener, errorHandler);
+ }
+
+ @Test
+ public void fireEvent_exceptionFromListenerAndNoHandler_exceptionPropagated() {
+ listener.componentEvent(EasyMock.<Component.Event> anyObject());
+ EasyMock.expectLastCall().andThrow(
+ new RuntimeException("listener failed"));
+
+ EasyMock.replay(component, listener);
+ try {
+ router.fireEvent(new Component.Event(component));
+ Assert.fail("Did not receive expected exception from listener");
+ } catch (RuntimeException e) {
+ // e is a ListenerMethod@MethodException
+ Assert.assertEquals("listener failed", e.getCause().getMessage());
+ }
+ EasyMock.verify(listener);
+ }
+
+ @Test
+ public void fireEvent_exceptionFromListener_errorHandlerCalled() {
+ listener.componentEvent(EasyMock.<Component.Event> anyObject());
+ EasyMock.expectLastCall().andThrow(
+ new RuntimeException("listener failed"));
+ errorHandler.error(EasyMock.<ErrorEvent> anyObject());
+
+ EasyMock.replay(component, listener, errorHandler);
+ router.fireEvent(new Component.Event(component), errorHandler);
+ EasyMock.verify(listener, errorHandler);
+ }
+
+ @Test
+ public void fireEvent_multipleListenersAndException_errorHandlerCalled() {
+ Listener listener2 = EasyMock.createMock(Component.Listener.class);
+ router.addListener(Component.Event.class, listener2,
+ COMPONENT_EVENT_METHOD);
+
+ listener.componentEvent(EasyMock.<Component.Event> anyObject());
+ EasyMock.expectLastCall().andThrow(
+ new RuntimeException("listener failed"));
+ errorHandler.error(EasyMock.<ErrorEvent> anyObject());
+ // second listener should be called despite an error in the first
+ listener2.componentEvent(EasyMock.<Component.Event> anyObject());
+
+ EasyMock.replay(component, listener, listener2, errorHandler);
+ router.fireEvent(new Component.Event(component), errorHandler);
+ EasyMock.verify(listener, listener2, errorHandler);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/push/PushFromInit.java b/uitest/src/com/vaadin/tests/push/PushFromInit.java
index cb084f1232..0afaa866f7 100644
--- a/uitest/src/com/vaadin/tests/push/PushFromInit.java
+++ b/uitest/src/com/vaadin/tests/push/PushFromInit.java
@@ -15,29 +15,60 @@
*/
package com.vaadin.tests.push;
+import com.vaadin.annotations.Push;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.Button;
+@Push
public class PushFromInit extends AbstractTestUIWithLog {
+ public static final String LOG_DURING_INIT = "Logged from access run before init ends";
+ public static final String LOG_AFTER_INIT = "Logged from background thread run after init has finished";
+
@Override
protected void setup(VaadinRequest request) {
- new Thread() {
- @Override
- public void run() {
- access(new Runnable() {
- @Override
- public void run() {
- log("Logged from background thread started in init");
- }
- });
- }
- }.start();
log("Logged in init");
+ Thread t = new Thread(new RunBeforeInitEnds());
+ t.start();
+ try {
+ t.join();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ new Thread(new RunAfterInit()).start();
addComponent(new Button("Sync"));
}
+ class RunBeforeInitEnds implements Runnable {
+ @Override
+ public void run() {
+ access(new Runnable() {
+ @Override
+ public void run() {
+ log(LOG_DURING_INIT);
+ }
+ });
+ }
+ }
+
+ class RunAfterInit implements Runnable {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ access(new Runnable() {
+ @Override
+ public void run() {
+ log(LOG_AFTER_INIT);
+ }
+ });
+ }
+ }
+
@Override
protected String getTestDescription() {
return "Pusing something to a newly created UI should not cause race conditions";
diff --git a/uitest/src/com/vaadin/tests/push/PushFromInitTest.java b/uitest/src/com/vaadin/tests/push/PushFromInitTest.java
index 3c1bc1b610..4101de29cf 100644
--- a/uitest/src/com/vaadin/tests/push/PushFromInitTest.java
+++ b/uitest/src/com/vaadin/tests/push/PushFromInitTest.java
@@ -15,8 +15,9 @@
*/
package com.vaadin.tests.push;
-import org.junit.Assert;
import org.junit.Test;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.support.ui.ExpectedCondition;
import com.vaadin.tests.tb3.MultiBrowserTest;
@@ -25,26 +26,13 @@ public class PushFromInitTest extends MultiBrowserTest {
public void testPushFromInit() {
openTestURL();
- for (int second = 0;; second++) {
- if (second >= 30) {
- Assert.fail("timeout");
+ waitUntil(new ExpectedCondition<Boolean>() {
+ @Override
+ public Boolean apply(WebDriver input) {
+ return ("3. " + PushFromInit.LOG_AFTER_INIT)
+ .equals(getLogRow(0));
}
- try {
- if ("1. Logged in init".equals(vaadinElementById(
- "Log_row_1").getText())) {
- break;
- }
- } catch (Exception e) {
- }
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- }
- }
-
- Assert.assertEquals(
- "2. Logged from background thread started in init",
- vaadinElementById("Log_row_0").getText());
+ });
}
} \ No newline at end of file