diff options
author | Jonatan Kronqvist <jonatan@vaadin.com> | 2014-02-06 17:30:40 +0200 |
---|---|---|
committer | Jonatan Kronqvist <jonatan@vaadin.com> | 2014-02-06 17:30:41 +0200 |
commit | dc7c1763bb111da6b6964379fbc0ccbe1ab5c8d0 (patch) | |
tree | b4545bfe09c81edf5f3dc77a7fbdbdb96bebb719 | |
parent | 927c497e78e8907c3d62ed4bacbd4b4bcfe1a580 (diff) | |
parent | 1ac492e46b70de9314083492bd8e136e1c8398e3 (diff) | |
download | vaadin-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.java | 39 | ||||
-rw-r--r-- | server/src/com/vaadin/server/VaadinService.java | 15 | ||||
-rw-r--r-- | server/tests/src/com/vaadin/tests/event/EventRouterTest.java | 111 | ||||
-rw-r--r-- | uitest/src/com/vaadin/tests/push/PushFromInit.java | 53 | ||||
-rw-r--r-- | uitest/src/com/vaadin/tests/push/PushFromInitTest.java | 28 |
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 |