diff options
3 files changed, 148 insertions, 7 deletions
diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java index 5a7ae5b3e8..93f1434c94 100644 --- a/server/src/com/vaadin/server/communication/PushHandler.java +++ b/server/src/com/vaadin/server/communication/PushHandler.java @@ -18,6 +18,7 @@ package com.vaadin.server.communication; import java.io.IOException; import java.io.Reader; +import java.util.Collection; import java.util.logging.Level; import java.util.logging.Logger; @@ -48,7 +49,7 @@ import com.vaadin.ui.UI; /** * Establishes bidirectional ("push") communication channels - * + * * @author Vaadin Ltd * @since 7.1 */ @@ -194,7 +195,7 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter { /** * Find the UI for the atmosphere resource, lock it and invoke the callback. - * + * * @param resource * the atmosphere resource for the current request * @param callback @@ -357,9 +358,31 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter { // Sets UI.currentInstance ui = service.findUI(vaadinRequest); if (ui == null) { - getLogger().log(Level.SEVERE, - "Could not get UI. This should never happen"); - return; + /* + * UI not found, could be because FF has asynchronously closed + * the websocket connection and Atmosphere has already done + * cleanup of the request attributes. + * + * In that case, we still have a chance of finding the right UI + * by iterating through the UIs in the session looking for one + * using the same AtmosphereResource. + */ + ui = findUiUsingResource(resource, session.getUIs()); + + if (ui == null) { + getLogger() + .log(Level.SEVERE, + "Could not get UI. This should never happen," + + " except when reloading in Firefox -" + + " see http://dev.vaadin.com/ticket/14251."); + return; + } else { + getLogger() + .log(Level.INFO, + "No UI was found based on data in the request," + + " but a slower lookup based on the AtmosphereResource succeeded." + + " See http://dev.vaadin.com/ticket/14251 for more details."); + } } PushMode pushMode = ui.getPushConfiguration().getPushMode(); @@ -411,6 +434,19 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter { } } + private static UI findUiUsingResource(AtmosphereResource resource, + Collection<UI> uIs) { + for (UI ui : uIs) { + PushConnection pushConnection = ui.getPushConnection(); + if (pushConnection instanceof AtmospherePushConnection) { + if (((AtmospherePushConnection) pushConnection).getResource() == resource) { + return ui; + } + } + } + return null; + } + /** * Sends a refresh message to the given atmosphere resource. Uses an * AtmosphereResource instead of an AtmospherePushConnection even though it @@ -419,10 +455,10 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter { * two push connections which try to use the same UI. Using the * AtmosphereResource directly guarantees the message goes to the correct * recipient. - * + * * @param resource * The atmosphere resource to send refresh to - * + * */ private static void sendRefreshAndDisconnect(AtmosphereResource resource) throws IOException { diff --git a/uitest/src/com/vaadin/tests/push/RefreshCloseConnection.java b/uitest/src/com/vaadin/tests/push/RefreshCloseConnection.java new file mode 100644 index 0000000000..4d02c4e62e --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/RefreshCloseConnection.java @@ -0,0 +1,61 @@ +/* + * Copyright 2000-2014 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.push; + +import com.vaadin.annotations.PreserveOnRefresh; +import com.vaadin.annotations.Push; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; + +@Push +@PreserveOnRefresh +public class RefreshCloseConnection extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + log("Init"); + } + + @Override + protected void refresh(VaadinRequest request) { + if (getPushConnection().isConnected()) { + log("Still connected"); + } + log("Refresh"); + new Thread() { + @Override + public void run() { + accessSynchronously(new Runnable() { + @Override + public void run() { + log("Push"); + } + }); + } + }.start(); + } + + @Override + protected String getTestDescription() { + return "A log row should get pushed after reloading the page"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(14251); + } + +} diff --git a/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java b/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java new file mode 100644 index 0000000000..c5c6064555 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/RefreshCloseConnectionTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2014 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.push; + +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.tests.tb3.MultiBrowserTest; +import com.vaadin.tests.tb3.WebsocketTest; + +public class RefreshCloseConnectionTest extends MultiBrowserTest { + @Test + public void testSessionRefresh() { + openTestURL(); + + Assert.assertEquals("1. Init", getLogRow(0)); + + openTestURL(); + + Assert.assertEquals("2. Refresh", getLogRow(1)); + Assert.assertEquals("3. Push", getLogRow(0)); + } + + @Override + public List<DesiredCapabilities> getBrowsersToTest() { + return WebsocketTest.getWebsocketBrowsers(); + } +} |