summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/src/com/vaadin/server/AbstractClientConnector.java19
-rw-r--r--server/src/com/vaadin/server/BootstrapHandler.java6
-rw-r--r--server/src/com/vaadin/server/ClientConnector.java8
-rw-r--r--server/src/com/vaadin/server/ConnectorResource.java9
-rw-r--r--server/src/com/vaadin/server/ConnectorResourceHandler.java54
-rw-r--r--server/src/com/vaadin/server/DownloadStream.java5
-rw-r--r--server/src/com/vaadin/server/FileDownloader.java23
-rw-r--r--server/src/com/vaadin/server/GlobalResourceHandler.java53
-rw-r--r--server/src/com/vaadin/server/LegacyCommunicationManager.java66
-rw-r--r--server/src/com/vaadin/server/RequestHandler.java11
-rw-r--r--server/src/com/vaadin/server/SynchronizedRequestHandler.java65
-rw-r--r--server/src/com/vaadin/server/UnsupportedBrowserHandler.java6
-rw-r--r--server/src/com/vaadin/server/VaadinPortlet.java4
-rw-r--r--server/src/com/vaadin/server/VaadinServlet.java5
-rw-r--r--server/src/com/vaadin/server/communication/HeartbeatHandler.java19
-rw-r--r--server/src/com/vaadin/server/communication/PortletListenerNotifier.java8
-rw-r--r--server/src/com/vaadin/server/communication/PublishedFileHandler.java6
-rw-r--r--server/src/com/vaadin/server/communication/SessionRequestHandler.java70
-rw-r--r--server/src/com/vaadin/server/communication/UIInitHandler.java10
-rw-r--r--server/src/com/vaadin/server/communication/UidlRequestHandler.java13
-rw-r--r--server/src/com/vaadin/ui/AbstractMedia.java20
-rw-r--r--server/src/com/vaadin/ui/LoginForm.java30
22 files changed, 333 insertions, 177 deletions
diff --git a/server/src/com/vaadin/server/AbstractClientConnector.java b/server/src/com/vaadin/server/AbstractClientConnector.java
index 79ccbd8f0b..e998b8ed55 100644
--- a/server/src/com/vaadin/server/AbstractClientConnector.java
+++ b/server/src/com/vaadin/server/AbstractClientConnector.java
@@ -645,17 +645,22 @@ public abstract class AbstractClientConnector implements ClientConnector,
@Override
public boolean handleConnectorRequest(VaadinRequest request,
VaadinResponse response, String path) throws IOException {
+ DownloadStream stream = null;
String[] parts = path.split("/", 2);
String key = parts[0];
- ConnectorResource resource = (ConnectorResource) getResource(key);
- if (resource != null) {
- DownloadStream stream = resource.getStream();
- stream.writeResponse(request, response);
- return true;
- } else {
- return false;
+ getSession().lock();
+ try {
+ ConnectorResource resource = (ConnectorResource) getResource(key);
+ if (resource == null) {
+ return false;
+ }
+ stream = resource.getStream();
+ } finally {
+ getSession().unlock();
}
+ stream.writeResponse(request, response);
+ return true;
}
/**
diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java
index 03421ce487..9c603ae7ed 100644
--- a/server/src/com/vaadin/server/BootstrapHandler.java
+++ b/server/src/com/vaadin/server/BootstrapHandler.java
@@ -51,7 +51,7 @@ import com.vaadin.ui.UI;
* @deprecated As of 7.0. Will likely change or be removed in a future version
*/
@Deprecated
-public abstract class BootstrapHandler implements RequestHandler {
+public abstract class BootstrapHandler extends SynchronizedRequestHandler {
protected class BootstrapContext implements Serializable {
@@ -113,8 +113,8 @@ public abstract class BootstrapHandler implements RequestHandler {
}
@Override
- public boolean handleRequest(VaadinSession session, VaadinRequest request,
- VaadinResponse response) throws IOException {
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
try {
List<UIProvider> uiProviders = session.getUIProviders();
diff --git a/server/src/com/vaadin/server/ClientConnector.java b/server/src/com/vaadin/server/ClientConnector.java
index 294f94f2be..3b52fbc730 100644
--- a/server/src/com/vaadin/server/ClientConnector.java
+++ b/server/src/com/vaadin/server/ClientConnector.java
@@ -318,8 +318,12 @@ public interface ClientConnector extends Connector {
* routed to this method with the remaining part of the requested path
* available in the path parameter.
* <p>
- * {@link DynamicConnectorResource} can be used to easily make an
- * appropriate URL available to the client-side code.
+ * NOTE that the session is not locked when this method is called. It is the
+ * responsibility of the connector to ensure that the session is locked
+ * while handling state or other session related data. For best performance
+ * the session should be unlocked before writing a large response to the
+ * client.
+ * </p>
*
* @param request
* the request that should be handled
diff --git a/server/src/com/vaadin/server/ConnectorResource.java b/server/src/com/vaadin/server/ConnectorResource.java
index 8f8591e6b1..8682f8ce6f 100644
--- a/server/src/com/vaadin/server/ConnectorResource.java
+++ b/server/src/com/vaadin/server/ConnectorResource.java
@@ -30,6 +30,15 @@ public interface ConnectorResource extends Resource {
/**
* Gets resource as stream.
+ * <p>
+ * Note that this method is called while the session is locked to prevent
+ * race conditions but the methods in the returned {@link DownloadStream}
+ * are assumed to be unrelated to the VaadinSession and are called without
+ * holding session locks (to prevent locking the session during long file
+ * downloads).
+ * </p>
+ *
+ * @return A download stream which produces the resource content
*/
public DownloadStream getStream();
diff --git a/server/src/com/vaadin/server/ConnectorResourceHandler.java b/server/src/com/vaadin/server/ConnectorResourceHandler.java
index 03a2fcc115..61631c3d23 100644
--- a/server/src/com/vaadin/server/ConnectorResourceHandler.java
+++ b/server/src/com/vaadin/server/ConnectorResourceHandler.java
@@ -16,6 +16,8 @@
package com.vaadin.server;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -25,6 +27,7 @@ import javax.servlet.http.HttpServletResponse;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.ui.UI;
+import com.vaadin.util.CurrentInstance;
public class ConnectorResourceHandler implements RequestHandler {
// APP/connector/[uiid]/[cid]/[filename.xyz]
@@ -50,30 +53,41 @@ public class ConnectorResourceHandler implements RequestHandler {
String uiId = matcher.group(1);
String cid = matcher.group(2);
String key = matcher.group(3);
- UI ui = session.getUIById(Integer.parseInt(uiId));
- if (ui == null) {
- return error(request, response,
- "Ignoring connector request for no-existent root "
- + uiId);
- }
- UI.setCurrent(ui);
- VaadinSession.setCurrent(ui.getSession());
+ session.lock();
+ UI ui;
+ ClientConnector connector;
+ try {
+ ui = session.getUIById(Integer.parseInt(uiId));
+ if (ui == null) {
+ return error(request, response,
+ "Ignoring connector request for no-existent root "
+ + uiId);
+ }
+
+ connector = ui.getConnectorTracker().getConnector(cid);
+ if (connector == null) {
+ return error(request, response,
+ "Ignoring connector request for no-existent connector "
+ + cid + " in root " + uiId);
+ }
- ClientConnector connector = ui.getConnectorTracker().getConnector(
- cid);
- if (connector == null) {
- return error(request, response,
- "Ignoring connector request for no-existent connector "
- + cid + " in root " + uiId);
+ } finally {
+ session.unlock();
}
- if (!connector.handleConnectorRequest(request, response, key)) {
- return error(request, response, connector.getClass()
- .getSimpleName()
- + " ("
- + connector.getConnectorId()
- + ") did not handle connector request for " + key);
+ Map<Class<?>, Object> oldThreadLocals = new HashMap<Class<?>, Object>();
+ CurrentInstance.setThreadLocals(ui, oldThreadLocals);
+ try {
+ if (!connector.handleConnectorRequest(request, response, key)) {
+ return error(request, response,
+ connector.getClass().getSimpleName() + " ("
+ + connector.getConnectorId()
+ + ") did not handle connector request for "
+ + key);
+ }
+ } finally {
+ CurrentInstance.setThreadLocals(oldThreadLocals);
}
return true;
diff --git a/server/src/com/vaadin/server/DownloadStream.java b/server/src/com/vaadin/server/DownloadStream.java
index e2f9fc5296..4e66831f1d 100644
--- a/server/src/com/vaadin/server/DownloadStream.java
+++ b/server/src/com/vaadin/server/DownloadStream.java
@@ -28,6 +28,11 @@ import javax.servlet.http.HttpServletResponse;
/**
* Downloadable stream.
+ * <p>
+ * Note that the methods in a DownloadStream are called without locking the
+ * session to prevent locking the session during long file downloads. If your
+ * DownloadStream uses anything from the session, you must handle the locking.
+ * </p>
*
* @author Vaadin Ltd.
* @since 3.0
diff --git a/server/src/com/vaadin/server/FileDownloader.java b/server/src/com/vaadin/server/FileDownloader.java
index 7cc1fd7cc8..9b49ad8edd 100644
--- a/server/src/com/vaadin/server/FileDownloader.java
+++ b/server/src/com/vaadin/server/FileDownloader.java
@@ -129,10 +129,15 @@ public class FileDownloader extends AbstractExtension {
// Ignore if it isn't for us
return false;
}
+ getSession().lock();
+ DownloadStream stream;
- Resource resource = getFileDownloadResource();
- if (resource instanceof ConnectorResource) {
- DownloadStream stream = ((ConnectorResource) resource).getStream();
+ try {
+ Resource resource = getFileDownloadResource();
+ if (!(resource instanceof ConnectorResource)) {
+ return false;
+ }
+ stream = ((ConnectorResource) resource).getStream();
if (stream.getParameter("Content-Disposition") == null) {
// Content-Disposition: attachment generally forces download
@@ -140,15 +145,15 @@ public class FileDownloader extends AbstractExtension {
"attachment; filename=\"" + stream.getFileName() + "\"");
}
- // Content-Type to block eager browser plug-ins from hijacking the
- // file
+ // Content-Type to block eager browser plug-ins from hijacking
+ // the file
if (isOverrideContentType()) {
stream.setContentType("application/octet-stream;charset=UTF-8");
}
- stream.writeResponse(request, response);
- return true;
- } else {
- return false;
+ } finally {
+ getSession().unlock();
}
+ stream.writeResponse(request, response);
+ return true;
}
}
diff --git a/server/src/com/vaadin/server/GlobalResourceHandler.java b/server/src/com/vaadin/server/GlobalResourceHandler.java
index 0fac14e20c..d411b286d0 100644
--- a/server/src/com/vaadin/server/GlobalResourceHandler.java
+++ b/server/src/com/vaadin/server/GlobalResourceHandler.java
@@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletResponse;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.ui.LegacyComponent;
import com.vaadin.ui.UI;
+import com.vaadin.util.CurrentInstance;
/**
* A {@link RequestHandler} that takes care of {@link ConnectorResource}s that
@@ -85,30 +86,38 @@ public class GlobalResourceHandler implements RequestHandler {
return error(request, response, pathInfo
+ " is not a valid global resource path");
}
+ session.lock();
+ Map<Class<?>, CurrentInstance> oldThreadLocals = null;
+ DownloadStream stream = null;
+ try {
+ UI ui = session.getUIById(Integer.parseInt(uiid));
+ if (ui == null) {
+ return error(request, response, "No UI found for id " + uiid);
+ }
+ oldThreadLocals = CurrentInstance.setThreadLocals(ui);
+ ConnectorResource resource;
+ if (LEGACY_TYPE.equals(type)) {
+ resource = legacyResources.get(key);
+ } else {
+ return error(request, response, "Unknown global resource type "
+ + type + " in requested path " + pathInfo);
+ }
- UI ui = session.getUIById(Integer.parseInt(uiid));
- if (ui == null) {
- return error(request, response, "No UI found for id " + uiid);
- }
- UI.setCurrent(ui);
-
- ConnectorResource resource;
- if (LEGACY_TYPE.equals(type)) {
- resource = legacyResources.get(key);
- } else {
- return error(request, response, "Unknown global resource type "
- + type + " in requested path " + pathInfo);
- }
-
- if (resource == null) {
- return error(request, response, "Global resource " + key
- + " not found");
- }
+ if (resource == null) {
+ return error(request, response, "Global resource " + key
+ + " not found");
+ }
- DownloadStream stream = resource.getStream();
- if (stream == null) {
- return error(request, response, "Resource " + resource
- + " didn't produce any stream.");
+ stream = resource.getStream();
+ if (stream == null) {
+ return error(request, response, "Resource " + resource
+ + " didn't produce any stream.");
+ }
+ } finally {
+ session.unlock();
+ if (oldThreadLocals != null) {
+ CurrentInstance.restoreThreadLocals(oldThreadLocals);
+ }
}
stream.writeResponse(request, response);
diff --git a/server/src/com/vaadin/server/LegacyCommunicationManager.java b/server/src/com/vaadin/server/LegacyCommunicationManager.java
index 2b99da7828..b956b806bd 100644
--- a/server/src/com/vaadin/server/LegacyCommunicationManager.java
+++ b/server/src/com/vaadin/server/LegacyCommunicationManager.java
@@ -237,19 +237,17 @@ public class LegacyCommunicationManager implements Serializable {
}
private String registerPublishedFile(String name, Class<?> context) {
- synchronized (publishedFileContexts) {
- // Add to map of names accepted by servePublishedFile
- if (publishedFileContexts.containsKey(name)) {
- Class<?> oldContext = publishedFileContexts.get(name);
- if (oldContext != context) {
- getLogger()
- .log(Level.WARNING,
- "{0} published by both {1} and {2}. File from {2} will be used.",
- new Object[] { name, context, oldContext });
- }
- } else {
- publishedFileContexts.put(name, context);
+ // Add to map of names accepted by servePublishedFile
+ if (publishedFileContexts.containsKey(name)) {
+ Class<?> oldContext = publishedFileContexts.get(name);
+ if (oldContext != context) {
+ getLogger()
+ .log(Level.WARNING,
+ "{0} published by both {1} and {2}. File from {2} will be used.",
+ new Object[] { name, context, oldContext });
}
+ } else {
+ publishedFileContexts.put(name, context);
}
return ApplicationConstants.PUBLISHED_PROTOCOL_PREFIX + "/" + name;
@@ -519,50 +517,6 @@ public class LegacyCommunicationManager implements Serializable {
}
/**
- * Handles a request by passing it to each registered {@link RequestHandler}
- * in turn until one produces a response. This method is used for requests
- * that have not been handled by any specific functionality in the terminal
- * implementation (e.g. {@link VaadinServlet}).
- * <p>
- * The request handlers are invoked in the revere order in which they were
- * added to the session until a response has been produced. This means that
- * the most recently added handler is used first and the first request
- * handler that was added to the session is invoked towards the end unless
- * any previous handler has already produced a response.
- * </p>
- *
- * @param request
- * the Vaadin request to get information from
- * @param response
- * the response to which data can be written
- * @return returns <code>true</code> if a {@link RequestHandler} has
- * produced a response and <code>false</code> if no response has
- * been written.
- * @throws IOException
- * if a handler throws an exception
- *
- * @see VaadinSession#addRequestHandler(RequestHandler)
- * @see RequestHandler
- *
- * @since 7.0
- *
- * @deprecated As of 7.1. Should be moved to VaadinService.
- */
- @Deprecated
- protected boolean handleOtherRequest(VaadinRequest request,
- VaadinResponse response) throws IOException {
- // Use a copy to avoid ConcurrentModificationException
- for (RequestHandler handler : new ArrayList<RequestHandler>(
- session.getRequestHandlers())) {
- if (handler.handleRequest(session, request, response)) {
- return true;
- }
- }
- // If not handled
- return false;
- }
-
- /**
* Handles an exception that occurred when processing RPC calls or a file
* upload.
*
diff --git a/server/src/com/vaadin/server/RequestHandler.java b/server/src/com/vaadin/server/RequestHandler.java
index 24107b744b..9c4f0ae6a4 100644
--- a/server/src/com/vaadin/server/RequestHandler.java
+++ b/server/src/com/vaadin/server/RequestHandler.java
@@ -19,6 +19,8 @@ package com.vaadin.server;
import java.io.IOException;
import java.io.Serializable;
+import com.vaadin.ui.UI;
+
/**
* Handler for producing a response to non-UIDL requests. Handlers can be added
* to service sessions using
@@ -30,6 +32,14 @@ public interface RequestHandler extends Serializable {
* Handles a non-UIDL request. If a response is written, this method should
* return <code>true</code> to indicate that no more request handlers should
* be invoked for the request.
+ * <p>
+ * Note that request handlers by default do not lock the session. If you are
+ * using VaadinSession or anything inside the VaadinSession you must ensure
+ * the session is locked. This can be done by extending
+ * {@link SynchronizedRequestHandler} or by using
+ * {@link VaadinSession#runSafelyInContext(Runnable)} or
+ * {@link UI#runSafelyInContext(Runnable)}.
+ * </p>
*
* @param session
* The session for the request
@@ -40,6 +50,7 @@ public interface RequestHandler extends Serializable {
* @return true if a response has been written and no further request
* handlers should be called, otherwise false
* @throws IOException
+ * If an IO error occurred
*/
boolean handleRequest(VaadinSession session, VaadinRequest request,
VaadinResponse response) throws IOException;
diff --git a/server/src/com/vaadin/server/SynchronizedRequestHandler.java b/server/src/com/vaadin/server/SynchronizedRequestHandler.java
new file mode 100644
index 0000000000..ac730dcecb
--- /dev/null
+++ b/server/src/com/vaadin/server/SynchronizedRequestHandler.java
@@ -0,0 +1,65 @@
+/*
+ * 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.server;
+
+import java.io.IOException;
+
+/**
+ * RequestHandler which takes care of locking and unlocking of the VaadinSession
+ * automatically. The session is locked before
+ * {@link #synchronizedHandleRequest(VaadinSession, VaadinRequest, VaadinResponse)}
+ * is called and unlocked after it has completed.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.1
+ */
+public abstract class SynchronizedRequestHandler implements RequestHandler {
+
+ @Override
+ public boolean handleRequest(VaadinSession session, VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ session.lock();
+ try {
+ return synchronizedHandleRequest(session, request, response);
+ } finally {
+ session.unlock();
+ }
+ }
+
+ /**
+ * Identical to
+ * {@link #handleRequest(VaadinSession, VaadinRequest, VaadinResponse)}
+ * except the {@link VaadinSession} is locked before this is called and
+ * unlocked after this has completed.
+ *
+ * @see #handleRequest(VaadinSession, VaadinRequest, VaadinResponse)
+ * @param session
+ * The session for the request
+ * @param request
+ * The request to handle
+ * @param response
+ * The response object to which a response can be written.
+ * @return true if a response has been written and no further request
+ * handlers should be called, otherwise false
+ *
+ * @throws IOException
+ * If an IO error occurred
+ */
+ public abstract boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException;
+
+}
diff --git a/server/src/com/vaadin/server/UnsupportedBrowserHandler.java b/server/src/com/vaadin/server/UnsupportedBrowserHandler.java
index 65a99ce79c..5fc00408a9 100644
--- a/server/src/com/vaadin/server/UnsupportedBrowserHandler.java
+++ b/server/src/com/vaadin/server/UnsupportedBrowserHandler.java
@@ -28,14 +28,14 @@ import java.io.Writer;
* </p>
*/
@SuppressWarnings("serial")
-public class UnsupportedBrowserHandler implements RequestHandler {
+public class UnsupportedBrowserHandler extends SynchronizedRequestHandler {
/** Cookie used to ignore browser checks */
public static final String FORCE_LOAD_COOKIE = "vaadinforceload=1";
@Override
- public boolean handleRequest(VaadinSession session, VaadinRequest request,
- VaadinResponse response) throws IOException {
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
// Check if the browser is supported
// If Chrome Frame is available we'll assume it's ok
diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java
index 924310e9ed..75d72be03b 100644
--- a/server/src/com/vaadin/server/VaadinPortlet.java
+++ b/server/src/com/vaadin/server/VaadinPortlet.java
@@ -55,6 +55,7 @@ import com.vaadin.server.communication.FileUploadHandler;
import com.vaadin.server.communication.HeartbeatHandler;
import com.vaadin.server.communication.PortletListenerNotifier;
import com.vaadin.server.communication.PublishedFileHandler;
+import com.vaadin.server.communication.SessionRequestHandler;
import com.vaadin.server.communication.UIInitHandler;
import com.vaadin.server.communication.UidlRequestHandler;
import com.vaadin.util.CurrentInstance;
@@ -525,7 +526,8 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
LegacyCommunicationManager communicationManager)
throws PortletException, IOException, MalformedURLException {
if (requestType == RequestType.APP || requestType == RequestType.RENDER) {
- if (!communicationManager.handleOtherRequest(request, response)) {
+ if (!new SessionRequestHandler().handleRequest(vaadinSession,
+ request, response)) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
"Not found");
}
diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java
index c47ce6bcf1..46fe3da5c6 100644
--- a/server/src/com/vaadin/server/VaadinServlet.java
+++ b/server/src/com/vaadin/server/VaadinServlet.java
@@ -43,6 +43,7 @@ import com.vaadin.server.LegacyCommunicationManager.Callback;
import com.vaadin.server.communication.FileUploadHandler;
import com.vaadin.server.communication.HeartbeatHandler;
import com.vaadin.server.communication.PublishedFileHandler;
+import com.vaadin.server.communication.SessionRequestHandler;
import com.vaadin.server.communication.UIInitHandler;
import com.vaadin.server.communication.UidlRequestHandler;
import com.vaadin.util.CurrentInstance;
@@ -286,8 +287,8 @@ public class VaadinServlet extends HttpServlet implements Constants {
new UIInitHandler().handleRequest(vaadinSession, request,
response);
return;
- } else if (vaadinSession.getCommunicationManager()
- .handleOtherRequest(request, response)) {
+ } else if (new SessionRequestHandler().handleRequest(
+ vaadinSession, request, response)) {
return;
}
diff --git a/server/src/com/vaadin/server/communication/HeartbeatHandler.java b/server/src/com/vaadin/server/communication/HeartbeatHandler.java
index 75d4f870c1..a696ad3919 100644
--- a/server/src/com/vaadin/server/communication/HeartbeatHandler.java
+++ b/server/src/com/vaadin/server/communication/HeartbeatHandler.java
@@ -20,11 +20,10 @@ import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
-import com.vaadin.server.RequestHandler;
+import com.vaadin.server.SynchronizedRequestHandler;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinSession;
-import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.ui.UI;
/**
@@ -38,7 +37,7 @@ import com.vaadin.ui.UI;
* @author Vaadin Ltd
* @since 7.1
*/
-public class HeartbeatHandler implements RequestHandler {
+public class HeartbeatHandler extends SynchronizedRequestHandler {
/**
* Handles a heartbeat request for the given session. Reads the GET
@@ -48,17 +47,9 @@ public class HeartbeatHandler implements RequestHandler {
* time. Otherwise, writes a HTTP Not Found error to the response.
*/
@Override
- public boolean handleRequest(VaadinSession session, VaadinRequest request,
- VaadinResponse response) throws IOException {
-
- UI ui = null;
- try {
- int uiId = Integer.parseInt(request
- .getParameter(UIConstants.UI_ID_PARAMETER));
- ui = session.getUIById(uiId);
- } catch (NumberFormatException nfe) {
- // null-check below handles this as well
- }
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
+ UI ui = session.getService().findUI(request);
if (ui != null) {
ui.setLastHeartbeatTimestamp(System.currentTimeMillis());
// Ensure that the browser does not cache heartbeat responses.
diff --git a/server/src/com/vaadin/server/communication/PortletListenerNotifier.java b/server/src/com/vaadin/server/communication/PortletListenerNotifier.java
index aff5c8a80e..c64819ca44 100644
--- a/server/src/com/vaadin/server/communication/PortletListenerNotifier.java
+++ b/server/src/com/vaadin/server/communication/PortletListenerNotifier.java
@@ -29,7 +29,7 @@ import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
-import com.vaadin.server.RequestHandler;
+import com.vaadin.server.SynchronizedRequestHandler;
import com.vaadin.server.ServletPortletHelper;
import com.vaadin.server.VaadinPortletRequest;
import com.vaadin.server.VaadinPortletResponse;
@@ -46,7 +46,7 @@ import com.vaadin.ui.UI;
* @author Vaadin Ltd
* @since 7.1
*/
-public class PortletListenerNotifier implements RequestHandler {
+public class PortletListenerNotifier extends SynchronizedRequestHandler {
/**
* Fires portlet request events to any {@link PortletListener}s registered
@@ -55,8 +55,8 @@ public class PortletListenerNotifier implements RequestHandler {
* PortletListener method corresponding to the request type is invoked.
*/
@Override
- public boolean handleRequest(VaadinSession session, VaadinRequest request,
- VaadinResponse response) throws IOException {
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
VaadinPortletSession sess = (VaadinPortletSession) session;
PortletRequest req = ((VaadinPortletRequest) request)
diff --git a/server/src/com/vaadin/server/communication/PublishedFileHandler.java b/server/src/com/vaadin/server/communication/PublishedFileHandler.java
index 71fd80099a..1cd70bb173 100644
--- a/server/src/com/vaadin/server/communication/PublishedFileHandler.java
+++ b/server/src/com/vaadin/server/communication/PublishedFileHandler.java
@@ -74,11 +74,13 @@ public class PublishedFileHandler implements RequestHandler {
}
// Check that the resource name has been registered
- // TODO PUSH refactor - is the synchronization correct at all?
+ session.lock();
Class<?> context;
- synchronized (session.getCommunicationManager().getDependencies()) {
+ try {
context = session.getCommunicationManager().getDependencies()
.get(fileName);
+ } finally {
+ session.unlock();
}
// Security check: don't serve resource if the name hasn't been
diff --git a/server/src/com/vaadin/server/communication/SessionRequestHandler.java b/server/src/com/vaadin/server/communication/SessionRequestHandler.java
new file mode 100644
index 0000000000..244cb0121d
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/SessionRequestHandler.java
@@ -0,0 +1,70 @@
+/*
+ * 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.server.communication;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import com.vaadin.server.RequestHandler;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinSession;
+
+/**
+ * Handles a request by passing it to each registered {@link RequestHandler} in
+ * the session in turn until one produces a response. This method is used for
+ * requests that have not been handled by any specific functionality in the
+ * servlet/portlet.
+ * <p>
+ * The request handlers are invoked in the reverse order in which they were
+ * added to the session until a response has been produced. This means that the
+ * most recently added handler is used first and the first request handler that
+ * was added to the session is invoked towards the end unless any previous
+ * handler has already produced a response.
+ * </p>
+ * <p>
+ * The session is not locked during execution of the request handlers. The
+ * request handler can itself decide if it needs to lock the session or not.
+ * </p>
+ *
+ * @see VaadinSession#addRequestHandler(RequestHandler)
+ * @see RequestHandler
+ *
+ * @since 7.1
+ */
+public class SessionRequestHandler implements RequestHandler {
+
+ @Override
+ public boolean handleRequest(VaadinSession session, VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ // Use a copy to avoid ConcurrentModificationException
+ session.lock();
+ ArrayList<RequestHandler> requestHandlers;
+ try {
+ requestHandlers = new ArrayList<RequestHandler>(
+ session.getRequestHandlers());
+ } finally {
+ session.unlock();
+ }
+ for (RequestHandler handler : requestHandlers) {
+ if (handler.handleRequest(session, request, response)) {
+ return true;
+ }
+ }
+ // If not handled
+ return false;
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java
index aea8bbd5cd..e4790e95e5 100644
--- a/server/src/com/vaadin/server/communication/UIInitHandler.java
+++ b/server/src/com/vaadin/server/communication/UIInitHandler.java
@@ -32,7 +32,7 @@ import org.json.JSONObject;
import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.server.LegacyApplicationUIProvider;
-import com.vaadin.server.RequestHandler;
+import com.vaadin.server.SynchronizedRequestHandler;
import com.vaadin.server.UIClassSelectionEvent;
import com.vaadin.server.UICreateEvent;
import com.vaadin.server.UIProvider;
@@ -49,11 +49,11 @@ import com.vaadin.ui.UI;
* @author Vaadin Ltd
* @since 7.1
*/
-public class UIInitHandler implements RequestHandler {
+public class UIInitHandler extends SynchronizedRequestHandler {
@Override
- public boolean handleRequest(VaadinSession session, VaadinRequest request,
- VaadinResponse response) throws IOException {
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
// NOTE! GateIn requires, for some weird reason, getOutputStream
// to be used instead of getWriter() (it seems to interpret
@@ -62,7 +62,6 @@ public class UIInitHandler implements RequestHandler {
final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(out, "UTF-8")));
- session.lock();
try {
assert UI.getCurrent() == null;
@@ -88,7 +87,6 @@ public class UIInitHandler implements RequestHandler {
// TODO PUSH handle
e.printStackTrace();
} finally {
- session.unlock();
outWriter.close();
}
diff --git a/server/src/com/vaadin/server/communication/UidlRequestHandler.java b/server/src/com/vaadin/server/communication/UidlRequestHandler.java
index b128a34c7d..e55f39246e 100644
--- a/server/src/com/vaadin/server/communication/UidlRequestHandler.java
+++ b/server/src/com/vaadin/server/communication/UidlRequestHandler.java
@@ -32,7 +32,7 @@ import com.vaadin.server.Constants;
import com.vaadin.server.LegacyCommunicationManager;
import com.vaadin.server.LegacyCommunicationManager.Callback;
import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
-import com.vaadin.server.RequestHandler;
+import com.vaadin.server.SynchronizedRequestHandler;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinSession;
@@ -51,7 +51,7 @@ import com.vaadin.ui.UI;
* @author Vaadin Ltd
* @since 7.1
*/
-public class UidlRequestHandler implements RequestHandler {
+public class UidlRequestHandler extends SynchronizedRequestHandler {
private Callback criticalNotifier;
@@ -62,8 +62,8 @@ public class UidlRequestHandler implements RequestHandler {
}
@Override
- public boolean handleRequest(VaadinSession session, VaadinRequest request,
- VaadinResponse response) throws IOException {
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
UI uI = session.getService().findUI(request);
@@ -99,10 +99,6 @@ public class UidlRequestHandler implements RequestHandler {
final Writer outWriter = new BufferedWriter(new OutputStreamWriter(out,
"UTF-8"));
- // The rest of the process is synchronized with the session
- // in order to guarantee that no parallel variable handling is
- // made
- session.lock();
try {
rpcHandler.handleRpc(uI, request.getReader(), request);
@@ -126,7 +122,6 @@ public class UidlRequestHandler implements RequestHandler {
criticalNotifier.criticalNotification(request, response, null,
null, null, null);
} finally {
- session.unlock();
outWriter.close();
requestThemeName = null;
}
diff --git a/server/src/com/vaadin/ui/AbstractMedia.java b/server/src/com/vaadin/ui/AbstractMedia.java
index 41677467bb..97947b568d 100644
--- a/server/src/com/vaadin/ui/AbstractMedia.java
+++ b/server/src/com/vaadin/ui/AbstractMedia.java
@@ -25,6 +25,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.vaadin.server.ConnectorResource;
+import com.vaadin.server.DownloadStream;
import com.vaadin.server.Resource;
import com.vaadin.server.ResourceReference;
import com.vaadin.server.VaadinRequest;
@@ -83,7 +84,14 @@ public abstract class AbstractMedia extends AbstractComponent {
public boolean handleConnectorRequest(VaadinRequest request,
VaadinResponse response, String path) throws IOException {
Matcher matcher = Pattern.compile("(\\d+)(/.*)?").matcher(path);
- if (matcher.matches()) {
+ if (!matcher.matches()) {
+ return super.handleConnectorRequest(request, response, path);
+ }
+
+ DownloadStream stream;
+
+ getSession().lock();
+ try {
List<URLReference> sources = getState().sources;
int sourceIndex = Integer.parseInt(matcher.group(1));
@@ -98,11 +106,13 @@ public abstract class AbstractMedia extends AbstractComponent {
URLReference reference = sources.get(sourceIndex);
ConnectorResource resource = (ConnectorResource) ResourceReference
.getResource(reference);
- resource.getStream().writeResponse(request, response);
- return true;
- } else {
- return super.handleConnectorRequest(request, response, path);
+ stream = resource.getStream();
+ } finally {
+ getSession().unlock();
}
+
+ stream.writeResponse(request, response);
+ return true;
}
private Logger getLogger() {
diff --git a/server/src/com/vaadin/ui/LoginForm.java b/server/src/com/vaadin/ui/LoginForm.java
index 11ae1b379b..20ad392679 100644
--- a/server/src/com/vaadin/ui/LoginForm.java
+++ b/server/src/com/vaadin/ui/LoginForm.java
@@ -61,24 +61,30 @@ public class LoginForm extends CustomComponent {
private Embedded iframe = new Embedded();
@Override
- public boolean handleConnectorRequest(VaadinRequest request,
- VaadinResponse response, String path) throws IOException {
- String method = VaadinServletService.getCurrentServletRequest()
- .getMethod();
+ public boolean handleConnectorRequest(final VaadinRequest request,
+ final VaadinResponse response, String path) throws IOException {
if (!path.equals("login")) {
return super.handleConnectorRequest(request, response, path);
}
- String responseString = null;
- if (method.equalsIgnoreCase("post")) {
- responseString = handleLogin(request);
- } else {
- responseString = getLoginHTML();
- }
+ final StringBuilder responseBuilder = new StringBuilder();
+
+ getUI().runSafely(new Runnable() {
+ @Override
+ public void run() {
+ String method = VaadinServletService.getCurrentServletRequest()
+ .getMethod();
+ if (method.equalsIgnoreCase("post")) {
+ responseBuilder.append(handleLogin(request));
+ } else {
+ responseBuilder.append(getLoginHTML());
+ }
+ }
+ });
- if (responseString != null) {
+ if (responseBuilder.length() > 0) {
response.setContentType("text/html; charset=utf-8");
response.setCacheTime(-1);
- response.getWriter().write(responseString);
+ response.getWriter().write(responseBuilder.toString());
return true;
} else {
return false;