summaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'server/src')
-rw-r--r--server/src/com/vaadin/server/communication/PushHandler.java236
1 files changed, 143 insertions, 93 deletions
diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java
index bfa1067aa8..a9e6c17751 100644
--- a/server/src/com/vaadin/server/communication/PushHandler.java
+++ b/server/src/com/vaadin/server/communication/PushHandler.java
@@ -32,6 +32,7 @@ import org.json.JSONException;
import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
import com.vaadin.server.ServiceException;
import com.vaadin.server.SessionExpiredException;
+import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinServletRequest;
import com.vaadin.server.VaadinServletService;
@@ -47,7 +48,98 @@ import com.vaadin.ui.UI;
*/
public class PushHandler implements AtmosphereHandler {
+ /**
+ * Callback interface used internally to process an event with the
+ * corresponding UI properly locked.
+ */
+ private interface PushEventCallback {
+ public void run(AtmosphereResource resource, UI ui) throws IOException;
+ }
+
+ /**
+ * Callback used when we receive a request to establish a push channel for a
+ * UI. Associate the AtmosphereResource with the UI and leave the connection
+ * open by calling resource.suspend(). If there is a pending push, send it
+ * now.
+ */
+ private static PushEventCallback establishCallback = new PushEventCallback() {
+ @Override
+ public void run(AtmosphereResource resource, UI ui) throws IOException {
+ getLogger().log(Level.FINER,
+ "New push connection with transport {0}",
+ resource.transport());
+ resource.getResponse().setContentType("text/plain; charset=UTF-8");
+ if (resource.transport() == TRANSPORT.STREAMING) {
+ // IE8 requires a longer padding to work properly if the
+ // initial message is small (#11573). Chrome does not work
+ // without the original padding...
+ WebBrowser browser = ui.getSession().getBrowser();
+ if (browser.isIE() && browser.getBrowserMajorVersion() == 8) {
+ resource.padding(LONG_PADDING);
+ }
+ }
+ resource.suspend();
+
+ AtmospherePushConnection connection = new AtmospherePushConnection(
+ ui);
+ connection.connect(resource);
+
+ ui.setPushConnection(connection);
+ }
+ };
+
+ /**
+ * Callback used when we receive a UIDL request through Atmosphere. If the
+ * push channel is bidirectional (websockets), the request was sent via the
+ * same channel. Otherwise, the client used a separate AJAX request. Handle
+ * the request and send changed UI state via the push channel (we do not
+ * respond to the request directly.)
+ */
+ private static PushEventCallback receiveCallback = new PushEventCallback() {
+ @Override
+ public void run(AtmosphereResource resource, UI ui) throws IOException {
+ AtmosphereRequest req = resource.getRequest();
+
+ AtmospherePushConnection connection = getConnectionForUI(ui);
+
+ assert connection != null : "Got push from the client "
+ + "even though the connection does not seem to be "
+ + "valid. This might happen if a HttpSession is "
+ + "serialized and deserialized while the push "
+ + "connection is kept open or if the UI has a "
+ + "connection of unexpected type.";
+
+ // Should be set up by caller
+ VaadinRequest vaadinRequest = VaadinService.getCurrentRequest();
+ assert vaadinRequest != null;
+
+ try {
+ new ServerRpcHandler().handleRpc(ui, req.getReader(),
+ vaadinRequest);
+ connection.push(false);
+ } catch (JSONException e) {
+ getLogger().log(Level.SEVERE, "Error writing JSON to response",
+ e);
+ // Refresh on client side
+ connection
+ .sendMessage(VaadinService
+ .createCriticalNotificationJSON(null, null,
+ null, null));
+ } catch (InvalidUIDLSecurityKeyException e) {
+ getLogger().log(Level.WARNING,
+ "Invalid security key received from {0}",
+ resource.getRequest().getRemoteHost());
+ // Refresh on client side
+ connection
+ .sendMessage(VaadinService
+ .createCriticalNotificationJSON(null, null,
+ null, null));
+ }
+ }
+ };
+
private static final String LONG_PADDING;
+
static {
char[] array = new char[4096];
Arrays.fill(array, '-');
@@ -60,109 +152,67 @@ public class PushHandler implements AtmosphereHandler {
this.service = service;
}
- @Override
- public void onRequest(AtmosphereResource resource) {
-
+ /**
+ * Find the UI for the atmosphere resource, lock it and invoke the callback.
+ *
+ * @param resource
+ * the atmosphere resource for the current request
+ * @param callback
+ * the push callback to call when a UI is found and locked
+ */
+ private void callWithUi(final AtmosphereResource resource,
+ final PushEventCallback callback) {
AtmosphereRequest req = resource.getRequest();
VaadinServletRequest vaadinRequest = new VaadinServletRequest(req,
service);
+ VaadinSession session = null;
- VaadinSession session;
- try {
- session = service.findVaadinSession(vaadinRequest);
- } catch (ServiceException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return;
- } catch (SessionExpiredException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return;
- }
-
- session.lock();
+ service.requestStart(vaadinRequest, null);
try {
- UI ui = service.findUI(vaadinRequest);
- if (ui == null) {
- // This should not happen
- getLogger().warning(
- "Could not find the requested UI in session");
+ try {
+ session = service.findVaadinSession(vaadinRequest);
+ } catch (ServiceException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ return;
+ } catch (SessionExpiredException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
return;
}
- assert ui.getPushMode().isEnabled();
-
- if (req.getMethod().equalsIgnoreCase("GET")) {
- /*
- * We received a request to establish a push channel for a UI.
- * Associate the AtmosphereResource with the UI and leave the
- * connection open by calling resource.suspend(). If there is a
- * pending push, send it now.
- */
- getLogger().log(Level.FINER,
- "New push connection with transport {0}",
- resource.transport());
- resource.getResponse().setContentType(
- "text/plain; charset=UTF-8");
- if (resource.transport() == TRANSPORT.STREAMING) {
- // IE8 requires a longer padding to work properly if the
- // initial message is small (#11573). Chrome does not work
- // without the original padding...
- WebBrowser browser = session.getBrowser();
- if (browser.isIE() && browser.getBrowserMajorVersion() == 8) {
- resource.padding(LONG_PADDING);
- }
- }
- resource.suspend();
-
- AtmospherePushConnection connection = new AtmospherePushConnection(
- ui);
- connection.connect(resource);
-
- ui.setPushConnection(connection);
- } else if (req.getMethod().equalsIgnoreCase("POST")) {
- AtmospherePushConnection connection = getConnectionForUI(ui);
-
- assert connection != null : "Got push from the client "
- + "even though the connection does not seem to be "
- + "valid. This might happen if a HttpSession is "
- + "serialized and deserialized while the push "
- + "connection is kept open or if the UI has a "
- + "connection of unexpected type.";
-
- /*
- * We received a UIDL request through Atmosphere. If the push
- * channel is bidirectional (websockets), the request was sent
- * via the same channel. Otherwise, the client used a separate
- * AJAX request. Handle the request and send changed UI state
- * via the push channel (we do not respond to the request
- * directly.)
- */
- try {
- new ServerRpcHandler().handleRpc(ui, req.getReader(),
- vaadinRequest);
- connection.push(false);
- } catch (JSONException e) {
- getLogger().log(Level.SEVERE,
- "Error writing JSON to response", e);
- // Refresh on client side
- connection.sendMessage(VaadinService
- .createCriticalNotificationJSON(null, null, null,
- null));
- } catch (InvalidUIDLSecurityKeyException e) {
- getLogger().log(Level.WARNING,
- "Invalid security key received from {0}",
- resource.getRequest().getRemoteHost());
- // Refresh on client side
- connection.sendMessage(VaadinService
- .createCriticalNotificationJSON(null, null, null,
- null));
+
+ session.lock();
+ try {
+ VaadinSession.setCurrent(session);
+ // Sets UI.currentInstance
+ final UI ui = service.findUI(vaadinRequest);
+ if (ui == null) {
+ // This should not happen
+ getLogger().warning(
+ "Could not find the requested UI in session");
+ return;
}
+
+ callback.run(resource, ui);
+ } catch (IOException e) {
+ getLogger().log(Level.INFO,
+ "An error occured while writing a push response", e);
+ } finally {
+ session.unlock();
}
- } catch (IOException e) {
- getLogger().log(Level.INFO,
- "An error occured while writing a push response", e);
} finally {
- session.unlock();
+ service.requestEnd(vaadinRequest, null, session);
+ }
+ }
+
+ @Override
+ public void onRequest(AtmosphereResource resource) {
+ AtmosphereRequest req = resource.getRequest();
+
+ if (req.getMethod().equalsIgnoreCase("GET")) {
+ callWithUi(resource, establishCallback);
+ } else if (req.getMethod().equalsIgnoreCase("POST")) {
+ callWithUi(resource, receiveCallback);
}
}