]> source.dussan.org Git - vaadin-framework.git/commitdiff
Pass initial request details through the browser (#8232)
authorLeif Åstrand <leif@vaadin.com>
Wed, 4 Jan 2012 17:07:34 +0000 (19:07 +0200)
committerLeif Åstrand <leif@vaadin.com>
Wed, 4 Jan 2012 17:07:34 +0000 (19:07 +0200)
By passing the details through the browser, we don't need any state
mapped to a rootId that could be sent multiple times by caching in the
browser

Old test updated to test for this

WebContent/VAADIN/vaadinBootstrap.js
src/com/vaadin/Application.java
src/com/vaadin/terminal/CombinedRequest.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
src/com/vaadin/terminal/gwt/server/BootstrapHandler.java
tests/testbench/com/vaadin/tests/application/RefreshStatePreserve.html

index 1de61917b878953912007921e4dbfecd8bbd7670..1f5f3fa9734a318f181df2bba2aac89278ec1771 100644 (file)
                                                url += '/';
                                        }
                                }
-                               // Root id
                                url += ((/\?/).test(url) ? "&" : "?") + "browserDetails";
-                               url += '&rootId=' + getConfig('rootId');
+                               var rootId = getConfig("rootId");
+                               if (rootId !== undefined) {
+                                       url += "&rootId=" + rootId;
+                               }
+
+                               url += '&initialPath=' + encodeURIComponent(getConfig("initialPath"));
+                               url += '&initialParams=' + encodeURIComponent(JSON.stringify(getConfig("initialParams")));
+                               
                                url += '&' + vaadin.getBrowserDetailsParameters(appId); 
                                
                                // Timestamp to avoid caching
                                                                        config[property] = updatedConfig[property];
                                                                }
                                                        }
-                                                       config.initPending = false;
                                                        
                                                        // Try bootstrapping again, this time without fetching missing info
                                                        bootstrapApp(false);
                        apps[appId] = app;
                        
                        if (!window.name) {
-                               var rootId = getConfig('rootId');
-                               window.name =  appId + '-' + rootId;
+                               window.name =  appId + '-' + Math.random();
                        }
                        
                        var bootstrapApp = function(mayDefer) {
                                
                                var widgetsetBase = getConfig('widgetsetBase');
                                var widgetset = getConfig('widgetset');
-                               var initPending = getConfig('initPending');
                                if (widgetset && widgetsetBase) {
                                        loadWidgetset(widgetsetBase, widgetset);
                                }
                                
-                               if (initPending) {
+                               if (getConfig('uidl') === undefined) {
                                        if (mayDefer) {
                                                fetchRootConfig();
                                        } else {
index 8e88a677f6c66e8cffdbf4a426a2e1de94845bb4..e426ea30857b37bba90c9802378c101b4f1ba2ce 100644 (file)
@@ -325,55 +325,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
         }
     }
 
-    /**
-     * Helper class to keep track of the information from an initial request if
-     * another request is required before the <code>Root</code> can be
-     * initialized.
-     * 
-     * The saved information is then used together with information from the
-     * second request to create a {@link CombinedRequest} containing relevant
-     * parts from each request.
-     */
-    private static class PendingRootRequest implements Serializable {
-
-        private final Map<String, String[]> parameterMap;
-        private final String pathInfo;
-
-        /**
-         * Creates a new pending request from an initial request. This is done
-         * by saving the parameterMap and the pathInfo from the provided wrapped
-         * request.
-         * 
-         * @param request
-         *            the initial request from which the required data is
-         *            extracted
-         */
-        public PendingRootRequest(WrappedRequest request) {
-            // Create a defensive copy in case the Map instance is reused
-            parameterMap = new HashMap<String, String[]>(
-                    request.getParameterMap());
-            pathInfo = request.getRequestPathInfo();
-        }
-
-        /**
-         * Creates a new request by combining information from the initial
-         * request with information from the provided second request.
-         * 
-         * @param secondRequest
-         *            the second request, should contain the information
-         *            required for providing {@link BrowserDetails}
-         * @return a request providing a combined view of the information from
-         *         the two original requests
-         * 
-         * @see CombinedRequest#CombinedRequest(WrappedRequest, Map, String)
-         */
-        public CombinedRequest getCombinedRequest(
-                final WrappedRequest secondRequest) {
-            return new CombinedRequest(secondRequest,
-                    Collections.unmodifiableMap(parameterMap), pathInfo);
-        }
-    }
-
     private final static Logger logger = Logger.getLogger(Application.class
             .getName());
 
@@ -452,12 +403,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
 
     private boolean productionMode = true;
 
-    /**
-     * Keeps track of requests for which a root should be created once more
-     * information is available.
-     */
-    private Map<Integer, PendingRootRequest> pendingRoots = new HashMap<Integer, PendingRootRequest>();
-
     private final Map<String, Integer> retainOnRefreshRoots = new HashMap<String, Integer>();
 
     /**
@@ -2128,59 +2073,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
         return productionMode;
     }
 
-    /**
-     * Registers a request that will lead to a root being created in a
-     * subsequent request. When the initial request does not contain all the
-     * information required to initialize a {@link Root}, some information from
-     * the initial request is still needed when processing a subsequent request
-     * containing the rest of the required information. By registering the
-     * initial request, it can be combined with the subsequent request using the
-     * root id returned by this method.
-     * 
-     * @param request
-     *            the initial request from which information is required when
-     *            the subsequent request is processed
-     * @return the root id that should be used to associate the passed request
-     *         with future requests related to the same Root
-     * 
-     * @see #getCombinedRequest(WrappedRequest)
-     * @see #getRoot(WrappedRequest)
-     * 
-     * @since 7.0
-     */
-    public int registerPendingRoot(WrappedRequest request) {
-        int rootId = nextRootId++;
-        pendingRoots.put(Integer.valueOf(rootId), new PendingRootRequest(
-                request));
-        return rootId;
-    }
-
-    /**
-     * Gets a request containing some aspects from the original request and some
-     * aspects from the current request. This is used during the two phase
-     * initialization of Roots with the first request registered using
-     * {@link #registerPendingRoot(WrappedRequest)}
-     * 
-     * @param request
-     *            the second request, should be sent from the bootstrap
-     *            javascript
-     * @return a request containing some aspects of the initial request and some
-     *         aspects from the current request
-     * 
-     * @see #registerPendingRoot(WrappedRequest)
-     * 
-     * @since 7.0
-     */
-    public CombinedRequest getCombinedRequest(WrappedRequest request) {
-        PendingRootRequest pendingRootRequest = pendingRoots
-                .get(getRootId(request));
-        if (pendingRootRequest == null) {
-            return null;
-        } else {
-            return pendingRootRequest.getCombinedRequest(request);
-        }
-    }
-
     /**
      * Finds the {@link Root} to which a particular request belongs. If the
      * request originates from an existing Root, that root is returned. In other
@@ -2220,11 +2112,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
             boolean hasBrowserDetails = browserDetails != null
                     && browserDetails.getUriFragment() != null;
 
-            if (hasBrowserDetails) {
-                // Don't wait for a second request any more
-                pendingRoots.remove(rootId);
-            }
-
             root = roots.get(rootId);
 
             if (root == null && isRootPreserved()) {
@@ -2269,9 +2156,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
                 boolean initRequiresBrowserDetails = isRootPreserved()
                         || !root.getClass()
                                 .isAnnotationPresent(EagerInit.class);
-                if (initRequiresBrowserDetails && !hasBrowserDetails) {
-                    pendingRoots.put(rootId, new PendingRootRequest(request));
-                } else {
+                if (!initRequiresBrowserDetails || hasBrowserDetails) {
                     root.doInit(request);
 
                     // Remember that this root has been initialized
index 88e976120ae928288edb3e0bb4b00122ede0ab39..ccef6d89633853473693d5b0ff85c39196ab753d 100644 (file)
@@ -7,10 +7,15 @@ package com.vaadin.terminal;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
 
 import com.vaadin.Application;
+import com.vaadin.external.json.JSONArray;
+import com.vaadin.external.json.JSONException;
+import com.vaadin.external.json.JSONObject;
 import com.vaadin.terminal.gwt.server.WebApplicationContext;
 import com.vaadin.terminal.gwt.server.WebBrowser;
 
@@ -26,8 +31,7 @@ import com.vaadin.terminal.gwt.server.WebBrowser;
 public class CombinedRequest implements WrappedRequest {
 
     private final WrappedRequest secondRequest;
-    private final Map<String, String[]> parameterMap;
-    private final String pathInfo;
+    private Map<String, String[]> parameterMap;
 
     /**
      * Creates a new combined request based on the second request and some
@@ -36,20 +40,31 @@ public class CombinedRequest implements WrappedRequest {
      * @param secondRequest
      *            the second request which will be used as the foundation of the
      *            combined request
-     * @param parameterMap
-     *            the parameter map from the first request
-     * @param pathInfo
-     *            the path info from string the first request
+     * @throws JSONException
+     *             if the initialParams parameter can not be decoded
      */
-    public CombinedRequest(WrappedRequest secondRequest,
-            Map<String, String[]> parameterMap, String pathInfo) {
+    public CombinedRequest(WrappedRequest secondRequest) throws JSONException {
         this.secondRequest = secondRequest;
-        this.parameterMap = parameterMap;
-        this.pathInfo = pathInfo;
+
+        HashMap<String, String[]> map = new HashMap<String, String[]>();
+        JSONObject initialParams = new JSONObject(
+                secondRequest.getParameter("initialParams"));
+        for (Iterator<?> keys = initialParams.keys(); keys.hasNext();) {
+            String name = (String) keys.next();
+            JSONArray jsonValues = initialParams.getJSONArray(name);
+            String[] values = new String[jsonValues.length()];
+            for (int i = 0; i < values.length; i++) {
+                values[i] = jsonValues.getString(i);
+            }
+            map.put(name, values);
+        }
+
+        parameterMap = Collections.unmodifiableMap(map);
+
     }
 
     public String getParameter(String parameter) {
-        String[] strings = parameterMap.get(parameter);
+        String[] strings = getParameterMap().get(parameter);
         if (strings == null || strings.length == 0) {
             return null;
         } else {
@@ -58,7 +73,7 @@ public class CombinedRequest implements WrappedRequest {
     }
 
     public Map<String, String[]> getParameterMap() {
-        return Collections.unmodifiableMap(parameterMap);
+        return parameterMap;
     }
 
     public int getContentLength() {
@@ -78,7 +93,7 @@ public class CombinedRequest implements WrappedRequest {
     }
 
     public String getRequestPathInfo() {
-        return pathInfo;
+        return secondRequest.getParameter("initialPath");
     }
 
     public int getSessionMaxInactiveInterval() {
index 70d7436e1d47e689885c58ff58bb2b51f802d034..ca79dcfc444db5845337724e43d0406102beebd8 100644 (file)
@@ -1986,11 +1986,9 @@ public abstract class AbstractCommunicationManager implements
         // shortly, and we should send the initial UIDL
         boolean sendUIDL = Root.getCurrentRoot() == null;
 
-        // TODO Handle npe if id has not been registered
-        CombinedRequest combinedRequest = application
-                .getCombinedRequest(request);
-
         try {
+            CombinedRequest combinedRequest = new CombinedRequest(request);
+
             Root root = application.getRootForRequest(combinedRequest);
             response.setContentType("application/json; charset=UTF-8");
 
index 6bdcc0cff57502c7741619f30bf6210cbcde0742..f3cd585b5a7daf356e3d79b3cf86158f6ceeaa72 100644 (file)
@@ -9,6 +9,7 @@ import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.Serializable;
 import java.io.Writer;
+import java.util.Map;
 
 import javax.servlet.http.HttpServletResponse;
 
@@ -31,7 +32,7 @@ public abstract class BootstrapHandler implements RequestHandler {
         private final WrappedResponse response;
         private final WrappedRequest request;
         private final Application application;
-        private final int rootId;
+        private final Integer rootId;
 
         private Writer writer;
         private Root root;
@@ -42,7 +43,7 @@ public abstract class BootstrapHandler implements RequestHandler {
         private boolean rootFetched = false;
 
         public BootstrapContext(WrappedResponse response,
-                WrappedRequest request, Application application, int rootId) {
+                WrappedRequest request, Application application, Integer rootId) {
             this.response = response;
             this.request = request;
             this.application = application;
@@ -70,7 +71,7 @@ public abstract class BootstrapHandler implements RequestHandler {
             return writer;
         }
 
-        public int getRootId() {
+        public Integer getRootId() {
             return rootId;
         }
 
@@ -116,7 +117,7 @@ public abstract class BootstrapHandler implements RequestHandler {
             throws IOException {
 
         // TODO Should all urls be handled here?
-        int rootId;
+        Integer rootId = null;
         try {
             Root root = application.getRootForRequest(request);
             if (root == null) {
@@ -124,9 +125,9 @@ public abstract class BootstrapHandler implements RequestHandler {
                 return true;
             }
 
-            rootId = root.getRootId();
+            rootId = Integer.valueOf(root.getRootId());
         } catch (RootRequiresMoreInformationException e) {
-            rootId = application.registerPendingRoot(request);
+            // Just keep going without rootId
         }
 
         try {
@@ -139,7 +140,7 @@ public abstract class BootstrapHandler implements RequestHandler {
     }
 
     protected final void writeBootstrapPage(WrappedRequest request,
-            WrappedResponse response, Application application, int rootId)
+            WrappedResponse response, Application application, Integer rootId)
             throws IOException, JSONException {
 
         BootstrapContext context = createContext(request, response,
@@ -170,7 +171,7 @@ public abstract class BootstrapHandler implements RequestHandler {
     }
 
     public BootstrapContext createContext(WrappedRequest request,
-            WrappedResponse response, Application application, int rootId) {
+            WrappedResponse response, Application application, Integer rootId) {
         BootstrapContext context = new BootstrapContext(response, request,
                 application, rootId);
         return context;
@@ -350,11 +351,13 @@ public abstract class BootstrapHandler implements RequestHandler {
     protected JSONObject getApplicationParameters(BootstrapContext context)
             throws JSONException, PaintException {
         Application application = context.getApplication();
-        int rootId = context.getRootId();
+        Integer rootId = context.getRootId();
 
         JSONObject appConfig = new JSONObject();
 
-        appConfig.put(ApplicationConnection.ROOT_ID_PARAMETER, rootId);
+        if (rootId != null) {
+            appConfig.put(ApplicationConnection.ROOT_ID_PARAMETER, rootId);
+        }
 
         if (context.getThemeName() != null) {
             appConfig.put("themeUri",
@@ -368,8 +371,13 @@ public abstract class BootstrapHandler implements RequestHandler {
 
         appConfig.put("widgetset", context.getWidgetsetName());
 
-        if (application.isRootInitPending(rootId)) {
-            appConfig.put("initPending", true);
+        if (rootId == null || application.isRootInitPending(rootId.intValue())) {
+            appConfig.put("initialPath", context.getRequest()
+                    .getRequestPathInfo());
+
+            Map<String, String[]> parameterMap = context.getRequest()
+                    .getParameterMap();
+            appConfig.put("initialParams", parameterMap);
         } else {
             // write the initial UIDL into the config
             appConfig.put("uidl",
index b242606e782c20a291c0454175a4feb750070187..d48ab220b51aa8225b5f467d832941a6058a24fd 100644 (file)
        <td>vaadin=runcomvaadintestsapplicationRefreshStatePreserve::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td>
        <td>Root id: 0</td>
 </tr>
+<tr>
+       <td>runScript</td>
+       <td>history.back()</td>
+       <td></td>
+</tr>
+<tr>
+       <td>pause</td>
+       <td></td>
+       <td>1000</td>
+</tr>
+<tr>
+       <td>assertText</td>
+       <td>vaadin=runcomvaadintestsapplicationRefreshStatePreserve::/VVerticalLayout[0]/ChildComponentContainer[1]/VLabel[0]</td>
+       <td>Root id: 0</td>
+</tr>
 
 </tbody></table>
 </body>