summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2011-11-25 16:04:20 +0200
committerLeif Åstrand <leif@vaadin.com>2011-11-25 16:04:20 +0200
commit55948aefe8ead5054a83ec84d2e3624ffc1e7427 (patch)
tree7847a0bc9a16048fc5fca60eb6d13dc138afee96
parentd4057da1cd46f78d17a2ed678fe01ad1e04c5306 (diff)
downloadvaadin-framework-55948aefe8ead5054a83ec84d2e3624ffc1e7427.tar.gz
vaadin-framework-55948aefe8ead5054a83ec84d2e3624ffc1e7427.zip
Initial support for lazy root creation
-rw-r--r--WebContent/VAADIN/vaadinBootstrap.js90
-rw-r--r--src/com/vaadin/Application.java120
-rw-r--r--src/com/vaadin/RootRequiresMoreInformation.java17
-rw-r--r--src/com/vaadin/terminal/CombinedRequest.java89
-rw-r--r--src/com/vaadin/terminal/WrappedRequest.java6
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java4
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java16
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java78
-rw-r--r--src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java92
-rw-r--r--src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java5
-rw-r--r--src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java5
-rw-r--r--src/com/vaadin/ui/Root.java12
-rw-r--r--tests/testbench/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java2
-rw-r--r--tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.java47
14 files changed, 457 insertions, 126 deletions
diff --git a/WebContent/VAADIN/vaadinBootstrap.js b/WebContent/VAADIN/vaadinBootstrap.js
index 0aec37efe7..2178e2abe2 100644
--- a/WebContent/VAADIN/vaadinBootstrap.js
+++ b/WebContent/VAADIN/vaadinBootstrap.js
@@ -43,8 +43,6 @@
var url = basePath + widgetset + "/" + widgetset + ".nocache.js?" + new Date().getTime();
- //document.write("<script type='text/javascript' src='"+url+"'></script>");
-
var scriptTag = document.createElement('script');
scriptTag.setAttribute('type', 'text/javascript');
scriptTag.setAttribute('src', url);
@@ -58,7 +56,7 @@
if (defaults) {
throw "Defaults already defined";
}
- log("Got defaults", defaults)
+ log("Got defaults", d)
defaults = d;
},
initApplication: function(appId, config) {
@@ -73,27 +71,45 @@
}
return value;
}
-
- var themeUri = getConfig('themeUri');
- if (themeUri) {
- loadTheme(themeUri);
- }
-
- var widgetsetBase = getConfig('widgetsetBase');
- var widgetset = getConfig('widgetset');
- if (widgetset && widgetsetBase) {
- loadWidgetset(widgetsetBase, widgetset);
- if (widgetsetApps[widgetset]) {
- widgetsetApps[widgetset].push(appId);
- } else {
- widgetsetApps[widgetset] = [appId];
- }
- }
- if (getConfig("debug")) {
- // TODO debug state is now global for the entire page, but should somehow only be set for the current application
- window.vaadin.debug = true;
- }
+ var fetchRootConfig = function() {
+ log('Fetching root config');
+ var url = getConfig('appUri');
+ // Root id
+ url += ((/\?/).test(url) ? "&" : "?") + "browserDetails";
+ url += '&rootId=' + getConfig('rootId');
+ // Uri fragment
+ url += '&f=' + encodeURIComponent(location.hash);
+ // Timestamp to avoid caching
+ url += '&' + (new Date()).getTime();
+
+ var r = new XMLHttpRequest();
+ r.open('POST', url, true);
+ r.onreadystatechange = function (aEvt) {
+ if (r.readyState == 4) {
+ if (r.status == 200){
+ log(r.responseText);
+ // TODO Does this work in all supported browsers?
+ var updatedConfig = JSON.parse(r.responseText);
+
+ // Copy new properties to the config object
+ for (var property in updatedConfig) {
+ if (updatedConfig.hasOwnProperty(property)) {
+ config[property] = updatedConfig[property];
+ }
+ }
+
+ // Try bootstrapping again, this time without fetching missing info
+ bootstrapApp(false);
+ } else {
+ log('Error', r.statusText);
+ }
+ }
+ };
+ r.send(null);
+
+ log('sending request to ', url);
+ };
//Export public data
var app = {
@@ -101,6 +117,34 @@
};
apps[appId] = app;
+ var bootstrapApp = function(mayDefer) {
+ var themeUri = getConfig('themeUri');
+ if (themeUri) {
+ loadTheme(themeUri);
+ }
+
+ var widgetsetBase = getConfig('widgetsetBase');
+ var widgetset = getConfig('widgetset');
+ if (widgetset && widgetsetBase) {
+ loadWidgetset(widgetsetBase, widgetset);
+ if (widgetsetApps[widgetset]) {
+ widgetsetApps[widgetset].push(appId);
+ } else {
+ widgetsetApps[widgetset] = [appId];
+ }
+ } else if (mayDefer) {
+ fetchRootConfig();
+ } else {
+ throw "Widgetset not defined";
+ }
+ }
+ bootstrapApp(true);
+
+ if (getConfig("debug")) {
+ // TODO debug state is now global for the entire page, but should somehow only be set for the current application
+ window.vaadin.debug = true;
+ }
+
return app;
},
getApp: function(appId) {
diff --git a/src/com/vaadin/Application.java b/src/com/vaadin/Application.java
index c4a370b8d9..d284492c1c 100644
--- a/src/com/vaadin/Application.java
+++ b/src/com/vaadin/Application.java
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
import com.vaadin.service.ApplicationContext;
import com.vaadin.terminal.ApplicationResource;
+import com.vaadin.terminal.CombinedRequest;
import com.vaadin.terminal.ErrorMessage;
import com.vaadin.terminal.RequestHandler;
import com.vaadin.terminal.SystemError;
@@ -36,6 +37,7 @@ import com.vaadin.terminal.Terminal;
import com.vaadin.terminal.VariableOwner;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.WrappedResponse;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.server.ChangeVariablesErrorEvent;
import com.vaadin.terminal.gwt.server.WebApplicationContext;
import com.vaadin.ui.AbstractComponent;
@@ -118,8 +120,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
"mainWindow has already been set");
}
this.mainWindow = mainWindow;
- registerRoot(mainWindow);
- mainWindow.init(null);
}
public Root getMainWindow() {
@@ -171,8 +171,6 @@ public class Application implements Terminal.ErrorListener, Serializable {
public void addWindow(Root root, String name) {
legacyRootNames.put(name, root);
- registerRoot(root);
- root.init(null);
}
public void removeWindow(Root root) {
@@ -211,6 +209,24 @@ public class Application implements Terminal.ErrorListener, Serializable {
}
}
+ private static class PendingRootRequest {
+
+ private final Map<String, String[]> parameterMap;
+ private final String pathInfo;
+
+ public PendingRootRequest(WrappedRequest request) {
+ parameterMap = new HashMap<String, String[]>(
+ request.getParameterMap());
+ pathInfo = request.getRequestPathInfo();
+ }
+
+ public CombinedRequest getCombinedRequest(
+ final WrappedRequest secondRequest) {
+ return new CombinedRequest(secondRequest,
+ Collections.unmodifiableMap(parameterMap), pathInfo);
+ }
+ }
+
private final static Logger logger = Logger.getLogger(Application.class
.getName());
@@ -284,6 +300,12 @@ 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>();
+
+ /**
* Gets the user of the application.
*
* <p>
@@ -1570,27 +1592,8 @@ public class Application implements Terminal.ErrorListener, Serializable {
}
- public Root getRoot(WrappedRequest request) {
- // TODO What if getRoot is called again for this request?
-
- // TODO implement support for throwing exception if more
- // information is required to create a root
- Root root = createRoot(request);
-
- registerRoot(root);
-
- // TODO implement lazy init of root if indicated by annotation
- root.init(request);
-
- return root;
- }
-
- protected void registerRoot(Root root) {
- root.registerRoot(this, nextRootId++);
- roots.put(Integer.valueOf(root.getRootId()), root);
- }
-
- protected Root createRoot(WrappedRequest request) {
+ protected Root getRoot(WrappedRequest request)
+ throws RootRequiresMoreInformation {
String rootClassName = getRootClassName(request);
try {
Class<? extends Root> rootClass = Class.forName(rootClassName)
@@ -1666,11 +1669,70 @@ public class Application implements Terminal.ErrorListener, Serializable {
currentApplication.set(application);
}
- public Root getRootById(int rootId) {
- return roots.get(Integer.valueOf(rootId));
- }
-
public boolean isProductionMode() {
return productionMode;
}
+
+ public int registerPendingRoot(WrappedRequest request) {
+ int rootId = nextRootId++;
+ pendingRoots.put(Integer.valueOf(rootId), new PendingRootRequest(
+ request));
+ return rootId;
+ }
+
+ public CombinedRequest getCombinedRequest(WrappedRequest request) {
+ PendingRootRequest pendingRootRequest = pendingRoots
+ .get(getRootId(request));
+ if (pendingRootRequest == null) {
+ return null;
+ } else {
+ return pendingRootRequest.getCombinedRequest(request);
+ }
+ }
+
+ public Root getRootForRequest(WrappedRequest request)
+ throws RootRequiresMoreInformation {
+ Root root = Root.getCurrentRoot();
+ if (root != null) {
+ return root;
+ }
+ Integer rootId = getRootId(request);
+
+ synchronized (this) {
+ PendingRootRequest pendingRootRequest = pendingRoots.remove(rootId);
+ if (pendingRootRequest == null && rootId != null) {
+ root = roots.get(rootId);
+ } else {
+ root = getRoot(request);
+ if (root.getApplication() == null) {
+ root.setApplication(this);
+ }
+ if (root.getRootId() < 0) {
+ int id = (rootId != null ? rootId.intValue() : nextRootId++);
+ root.setRootId(id);
+ roots.put(Integer.valueOf(root.getRootId()), root);
+
+ // TODO implement lazy init of root if indicated by
+ // annotation
+ root.init(request);
+ }
+ }
+ }
+
+ Root.setCurrentRoot(root);
+ return root;
+ }
+
+ private Integer getRootId(WrappedRequest request) {
+ if (request instanceof CombinedRequest) {
+ // Combined requests has the rootid parameter in the second request
+ CombinedRequest combinedRequest = (CombinedRequest) request;
+ request = combinedRequest.getSecondRequest();
+ }
+ String rootIdString = request
+ .getParameter(ApplicationConnection.ROOT_ID_PARAMETER);
+ Integer rootId = rootIdString == null ? null
+ : new Integer(rootIdString);
+ return rootId;
+ }
}
diff --git a/src/com/vaadin/RootRequiresMoreInformation.java b/src/com/vaadin/RootRequiresMoreInformation.java
new file mode 100644
index 0000000000..5fa86fa044
--- /dev/null
+++ b/src/com/vaadin/RootRequiresMoreInformation.java
@@ -0,0 +1,17 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin;
+
+/**
+ * Exception that is thrown to indicate that creating or initializing the root
+ * requires information from the web browser (e.g. screen size or URI fragment)
+ * to be present.
+ *
+ * This exception may not be thrown if that information is already present in
+ * the current WrappedRequest.
+ */
+public class RootRequiresMoreInformation extends Exception {
+ // Nothing of interest here
+}
diff --git a/src/com/vaadin/terminal/CombinedRequest.java b/src/com/vaadin/terminal/CombinedRequest.java
new file mode 100644
index 0000000000..98d0a491aa
--- /dev/null
+++ b/src/com/vaadin/terminal/CombinedRequest.java
@@ -0,0 +1,89 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
+
+public class CombinedRequest implements WrappedRequest {
+
+ private final WrappedRequest secondRequest;
+ private final Map<String, String[]> parameterMap;
+ private final String pathInfo;
+
+ public CombinedRequest(WrappedRequest secondRequest,
+ Map<String, String[]> parameterMap, String pathInfo) {
+ this.secondRequest = secondRequest;
+ this.parameterMap = parameterMap;
+ this.pathInfo = pathInfo;
+ }
+
+ public String getParameter(String parameter) {
+ String[] strings = parameterMap.get(parameter);
+ if (strings == null || strings.length == 0) {
+ return null;
+ } else {
+ return strings[0];
+ }
+ }
+
+ public Map<String, String[]> getParameterMap() {
+ return Collections.unmodifiableMap(parameterMap);
+ }
+
+ public int getContentLength() {
+ return secondRequest.getContentLength();
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return secondRequest.getInputStream();
+ }
+
+ public Object getAttribute(String name) {
+ return secondRequest.getAttribute(name);
+ }
+
+ public void setAttribute(String name, Object value) {
+ secondRequest.setAttribute(name, value);
+ }
+
+ public String getRequestPathInfo() {
+ return pathInfo;
+ }
+
+ public int getSessionMaxInactiveInterval() {
+ return secondRequest.getSessionMaxInactiveInterval();
+ }
+
+ public Object getSessionAttribute(String name) {
+ return secondRequest.getSessionAttribute(name);
+ }
+
+ public void setSessionAttribute(String name, Object attribute) {
+ secondRequest.setSessionAttribute(name, attribute);
+ }
+
+ public String getContentType() {
+ return secondRequest.getContentType();
+ }
+
+ public String getStaticFileLocation() {
+ return secondRequest.getStaticFileLocation();
+ }
+
+ public BrowserDetails getBrowserDetails() {
+ return new BrowserDetails() {
+ public String getUriFragmet() {
+ return secondRequest.getParameter("f");
+ }
+ };
+ }
+
+ public WrappedRequest getSecondRequest() {
+ return secondRequest;
+ }
+}
diff --git a/src/com/vaadin/terminal/WrappedRequest.java b/src/com/vaadin/terminal/WrappedRequest.java
index 5ab11a7374..07a8721ea1 100644
--- a/src/com/vaadin/terminal/WrappedRequest.java
+++ b/src/com/vaadin/terminal/WrappedRequest.java
@@ -10,6 +10,10 @@ import java.io.Serializable;
import java.util.Map;
public interface WrappedRequest extends Serializable {
+ public interface BrowserDetails {
+ public String getUriFragmet();
+ }
+
/**
* Get the named HTTP or portlet request parameter.
*
@@ -65,4 +69,6 @@ public interface WrappedRequest extends Serializable {
public String getStaticFileLocation();
+ public BrowserDetails getBrowserDetails();
+
}
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
index 94c3e3e3e4..da912de753 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
@@ -447,8 +447,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
// root = application.getRoot();
break;
default:
- root = applicationManager.getApplicationRoot(
- wrappedRequest, application);
+ root = application
+ .getRootForRequest(wrappedRequest);
}
// if window not found, not a problem - use null
}
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
index 401f1e2c68..951b9a85bb 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
@@ -452,14 +452,17 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
return;
} else if (requestType == RequestType.UIDL) {
// Handles AJAX UIDL requests
- Root root = applicationManager.getApplicationRoot(
- wrappedRequest, application);
+ Root root = application.getRootForRequest(wrappedRequest);
if (root == null) {
throw new ServletException(ERROR_NO_WINDOW_FOUND);
}
applicationManager.handleUidlRequest(wrappedRequest,
wrappedResponse, servletWrapper, root);
return;
+ } else if (requestType == RequestType.BROWSER_DETAILS) {
+ applicationManager.handleBrowserDetailsRequest(wrappedRequest,
+ wrappedResponse, application);
+ return;
}
// Removes application if it has stopped (mayby by thread or
@@ -1228,12 +1231,14 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
protected enum RequestType {
- FILE_UPLOAD, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE;
+ FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE;
}
protected RequestType getRequestType(HttpServletRequest request) {
if (isFileUploadRequest(request)) {
return RequestType.FILE_UPLOAD;
+ } else if (isBrowserDetailsRequest(request)) {
+ return RequestType.BROWSER_DETAILS;
} else if (isUIDLRequest(request)) {
return RequestType.UIDL;
} else if (isStaticResourceRequest(request)) {
@@ -1247,6 +1252,11 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
+ private static boolean isBrowserDetailsRequest(HttpServletRequest request) {
+ return "POST".equals(request.getMethod())
+ && request.getParameter("browserDetails") != null;
+ }
+
private boolean isApplicationRequest(HttpServletRequest request) {
String path = getRequestPathInfo(request);
if (path != null && path.startsWith("/APP/")) {
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
index d72015dae4..d047ac8170 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
@@ -43,6 +43,10 @@ import java.util.logging.Logger;
import com.vaadin.Application;
import com.vaadin.Application.SystemMessages;
+import com.vaadin.RootRequiresMoreInformation;
+import com.vaadin.external.json.JSONException;
+import com.vaadin.external.json.JSONObject;
+import com.vaadin.terminal.CombinedRequest;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Paintable;
@@ -90,15 +94,18 @@ public abstract class AbstractCommunicationManager implements
.getLogger(AbstractCommunicationManager.class.getName());
private static final RequestHandler APP_RESOURCE_HANDLER = new ApplicationResourceHandler();
- private static final RequestHandler AJAX_PAGE_HANDLER = new AjaxPageHandler() {
+ private static final AjaxPageHandler AJAX_PAGE_HANDLER = new AjaxPageHandler() {
@Override
- protected String getApplicationOrSystemProperty(
- WrappedRequest request, String parameter,
- String defaultValue) {
+ protected String getApplicationOrSystemProperty(WrappedRequest request,
+ String parameter, String defaultValue) {
+ if (request instanceof CombinedRequest) {
+ CombinedRequest combinedRequest = (CombinedRequest) request;
+ request = combinedRequest.getSecondRequest();
+ }
WrappedHttpServletRequest r = (WrappedHttpServletRequest) request;
- return r.getServlet().getApplicationOrSystemProperty(
- parameter, defaultValue);
+ return r.getServlet().getApplicationOrSystemProperty(parameter,
+ defaultValue);
}
};
@@ -1629,32 +1636,6 @@ public abstract class AbstractCommunicationManager implements
}
/**
- * Gets the existing application or creates a new one. Get a window within
- * an application based on the requested URI.
- *
- * @param request
- * the HTTP Request.
- * @param application
- * the Application to query for window.
- * @return Window matching the given URI or null if not found.
- */
- public Root getApplicationRoot(WrappedRequest request,
- Application application) {
- String rootIdString = request
- .getParameter(ApplicationConnection.ROOT_ID_PARAMETER);
- Root root = null;
- synchronized (application) {
- if (rootIdString != null) {
- int rootId = Integer.parseInt(rootIdString);
- root = application.getRootById(rootId);
- }
- }
-
- Root.setCurrentRoot(root);
- return root;
- }
-
- /**
* Ends the Application.
*
* The browser is redirected to the Application logout URL set with
@@ -1951,6 +1932,39 @@ public abstract class AbstractCommunicationManager implements
return application.handleRequest(request, response);
}
+ public void handleBrowserDetailsRequest(WrappedRequest request,
+ WrappedResponse response, Application application)
+ throws IOException {
+
+ // TODO Handle npe if id has not been registered
+ CombinedRequest combinedRequest = application
+ .getCombinedRequest(request);
+
+ try {
+ Root root = application.getRootForRequest(combinedRequest);
+
+ // Use the same logic as for determined roots
+ String widgetset = AJAX_PAGE_HANDLER.getWidgetsetForRoot(
+ combinedRequest, root);
+ String theme = AJAX_PAGE_HANDLER.getThemeForRoot(combinedRequest,
+ root);
+ String themeUri = AJAX_PAGE_HANDLER.getThemeUri(theme,
+ combinedRequest);
+
+ JSONObject params = new JSONObject();
+ params.put("widgetset", widgetset);
+ params.put("themeUri", themeUri);
+ response.getWriter().write(params.toString());
+ } catch (RootRequiresMoreInformation e) {
+ // Requiring more information at this point is not allowed
+ // TODO handle in a better way
+ throw new RuntimeException(e);
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
/**
* Stream that extracts content from another stream until the boundary
* string is encountered.
diff --git a/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java b/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java
index 3979ab4ff2..0ae7d8d884 100644
--- a/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java
+++ b/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java
@@ -7,6 +7,7 @@ import java.io.OutputStreamWriter;
import javax.servlet.http.HttpServletResponse;
import com.vaadin.Application;
+import com.vaadin.RootRequiresMoreInformation;
import com.vaadin.external.json.JSONException;
import com.vaadin.external.json.JSONObject;
import com.vaadin.terminal.RequestHandler;
@@ -22,15 +23,21 @@ public abstract class AjaxPageHandler implements RequestHandler {
throws IOException {
// TODO Should all urls be handled here?
- Root root = application.getRoot(request);
-
- if (root == null) {
- writeError(response, new Throwable("No Root found"));
- return true;
+ int rootId;
+ try {
+ Root root = application.getRootForRequest(request);
+ if (root == null) {
+ writeError(response, new Throwable("No Root found"));
+ return true;
+ }
+
+ rootId = root.getRootId();
+ } catch (RootRequiresMoreInformation e) {
+ rootId = application.registerPendingRoot(request);
}
try {
- writeAjaxPage(request, response, root);
+ writeAjaxPage(request, response, application, rootId);
} catch (JSONException e) {
writeError(response, e);
}
@@ -39,13 +46,14 @@ public abstract class AjaxPageHandler implements RequestHandler {
}
protected final void writeAjaxPage(WrappedRequest request,
- WrappedResponse response, Root root) throws IOException,
- JSONException {
- Application application = root.getApplication();
+ WrappedResponse response, Application application, int rootId)
+ throws IOException, JSONException {
final BufferedWriter page = new BufferedWriter(new OutputStreamWriter(
response.getOutputStream(), "UTF-8"));
- String title = ((root.getCaption() == null) ? "Vaadin "
+ Root root = Root.getCurrentRoot();
+
+ String title = ((root == null || root.getCaption() == null) ? "Vaadin "
+ AbstractApplicationServlet.VERSION_MAJOR : root.getCaption());
/* Fetch relative url to application */
@@ -78,9 +86,11 @@ public abstract class AjaxPageHandler implements RequestHandler {
}
appId = appId + "-" + hashCode;
+ String widgetset = getWidgetsetForRoot(request, root);
+
// TODO include initial UIDL in the scripts?
- writeAjaxPageHtmlVaadinScripts(themeName, page, appUrl, themeUri,
- appId, request, root);
+ writeAjaxPageHtmlVaadinScripts(page, appUrl, themeUri, appId, request,
+ application, rootId, widgetset);
/*- Add classnames;
* .v-app
@@ -109,6 +119,23 @@ public abstract class AjaxPageHandler implements RequestHandler {
page.close();
}
+ public String getWidgetsetForRoot(WrappedRequest request, Root root) {
+ if (root == null) {
+ // Defer widgetset selection
+ return null;
+ }
+
+ String widgetset = root.getApplication().getWidgetsetForRoot(root);
+ if (widgetset == null) {
+ widgetset = getApplicationOrSystemProperty(request,
+ AbstractApplicationServlet.PARAMETER_WIDGETSET,
+ AbstractApplicationServlet.DEFAULT_WIDGETSET);
+ }
+
+ widgetset = AbstractApplicationServlet.stripSpecialChars(widgetset);
+ return widgetset;
+ }
+
/**
* Method to write the div element into which that actual Vaadin application
* is rendered.
@@ -178,22 +205,20 @@ public abstract class AjaxPageHandler implements RequestHandler {
* <p>
* Override this method if you want to add some custom html around scripts.
*
- * @param themeName
* @param page
* @param appUrl
* @param themeUri
* @param appId
* @param request
+ * @param application
* @param rootId
* @throws IOException
* @throws JSONException
*/
- protected void writeAjaxPageHtmlVaadinScripts(String themeName,
- final BufferedWriter page, String appUrl, String themeUri,
- String appId, WrappedRequest request, Root root)
- throws IOException, JSONException {
-
- Application application = root.getApplication();
+ protected void writeAjaxPageHtmlVaadinScripts(final BufferedWriter page,
+ String appUrl, String themeUri, String appId,
+ WrappedRequest request, Application application, int rootId,
+ String widgetset) throws IOException, JSONException {
String staticFileLocation = request.getStaticFileLocation();
@@ -225,8 +250,7 @@ public abstract class AjaxPageHandler implements RequestHandler {
defaults.put("appUri", appUrl);
- appConfig
- .put(ApplicationConnection.ROOT_ID_PARAMETER, root.getRootId());
+ appConfig.put(ApplicationConnection.ROOT_ID_PARAMETER, rootId);
if (isStandalone()) {
defaults.put("standalone", true);
@@ -262,12 +286,6 @@ public abstract class AjaxPageHandler implements RequestHandler {
defaults.put("widgetsetBase", widgetsetBase);
- String widgetset = application.getWidgetsetForRoot(root);
- widgetset = getApplicationOrSystemProperty(request,
- AbstractApplicationServlet.PARAMETER_WIDGETSET,
- AbstractApplicationServlet.DEFAULT_WIDGETSET);
-
- widgetset = AbstractApplicationServlet.stripSpecialChars(widgetset);
appConfig.put("widgetset", widgetset);
page.write("vaadin.setDefaults(");
@@ -327,10 +345,12 @@ public abstract class AjaxPageHandler implements RequestHandler {
+ "html, body {height:100%;margin:0;}</style>");
// Add favicon links
- page.write("<link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\" href=\""
- + themeUri + "/favicon.ico\" />");
- page.write("<link rel=\"icon\" type=\"image/vnd.microsoft.icon\" href=\""
- + themeUri + "/favicon.ico\" />");
+ if (themeUri != null) {
+ page.write("<link rel=\"shortcut icon\" type=\"image/vnd.microsoft.icon\" href=\""
+ + themeUri + "/favicon.ico\" />");
+ page.write("<link rel=\"icon\" type=\"image/vnd.microsoft.icon\" href=\""
+ + themeUri + "/favicon.ico\" />");
+ }
page.write("<title>"
+ AbstractApplicationServlet.safeEscapeForHtml(title)
@@ -387,7 +407,10 @@ public abstract class AjaxPageHandler implements RequestHandler {
* @param request
* @return
*/
- private String getThemeUri(String themeName, WrappedRequest request) {
+ public String getThemeUri(String themeName, WrappedRequest request) {
+ if (themeName == null) {
+ return null;
+ }
final String staticFilePath = request.getStaticFileLocation();
return staticFilePath + "/"
+ AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName;
@@ -400,7 +423,10 @@ public abstract class AjaxPageHandler implements RequestHandler {
* @param root
* @return
*/
- private String getThemeForRoot(WrappedRequest request, Root root) {
+ public String getThemeForRoot(WrappedRequest request, Root root) {
+ if (root == null) {
+ return null;
+ }
// Finds theme name
String themeName;
diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java
index 4d947d20b0..499243a74b 100644
--- a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java
+++ b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java
@@ -95,4 +95,9 @@ public class WrappedHttpServletRequest implements WrappedRequest {
public String getStaticFileLocation() {
return servlet.getStaticFilesLocation(request);
}
+
+ public BrowserDetails getBrowserDetails() {
+ // No browserDetails available for normal requests
+ return null;
+ }
} \ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
index e8e7350d42..7a671520dd 100644
--- a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
+++ b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
@@ -108,4 +108,9 @@ public class WrappedPortletRequest implements WrappedRequest {
throw new UnsupportedOperationException("Please implement me!");
}
+ public BrowserDetails getBrowserDetails() {
+ // No browserDetails available for normal requests
+ return null;
+ }
+
} \ No newline at end of file
diff --git a/src/com/vaadin/ui/Root.java b/src/com/vaadin/ui/Root.java
index d948d0ca9c..cb682609ef 100644
--- a/src/com/vaadin/ui/Root.java
+++ b/src/com/vaadin/ui/Root.java
@@ -85,7 +85,7 @@ public class Root extends AbstractComponentContainer implements
*/
private Component scrollIntoView;
- private int rootId;
+ private int rootId = -1;
/**
* Keeps track of the Actions added to this component, and manages the
@@ -225,17 +225,23 @@ public class Root extends AbstractComponentContainer implements
return Collections.singleton((Component) getContent()).iterator();
}
- public void registerRoot(Application application, int rootId) {
+ public void setApplication(Application application) {
if (application == null) {
throw new NullPointerException("application");
} else if (this.application != null) {
throw new IllegalStateException("Application has already been set");
} else {
this.application = application;
- this.rootId = rootId;
}
}
+ public void setRootId(int rootId) {
+ if (this.rootId != -1) {
+ throw new IllegalStateException("Root id has already been defined");
+ }
+ this.rootId = rootId;
+ }
+
public int getRootId() {
return rootId;
}
diff --git a/tests/testbench/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java b/tests/testbench/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java
index ed6deb420b..ad87549e50 100644
--- a/tests/testbench/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java
+++ b/tests/testbench/com/vaadin/tests/components/loginform/LoginFormWithMultipleWindows.java
@@ -11,7 +11,7 @@ import com.vaadin.ui.Root;
public class LoginFormWithMultipleWindows extends Application {
@Override
- protected Root createRoot(WrappedRequest request) {
+ protected Root getRoot(WrappedRequest request) {
return new LoginFormWindow();
}
diff --git a/tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.java b/tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.java
new file mode 100644
index 0000000000..96d9a465e2
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/root/LazyInitRoots.java
@@ -0,0 +1,47 @@
+package com.vaadin.tests.components.root;
+
+import com.vaadin.Application;
+import com.vaadin.RootRequiresMoreInformation;
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.WrappedRequest.BrowserDetails;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Root;
+import com.vaadin.ui.VerticalLayout;
+
+public class LazyInitRoots extends Application {
+
+ @Override
+ public Root getRoot(WrappedRequest request)
+ throws RootRequiresMoreInformation {
+ if (request.getParameter("lazyCreate") != null) {
+ BrowserDetails browserDetails = request.getBrowserDetails();
+ if (browserDetails == null) {
+ throw new RootRequiresMoreInformation();
+ } else {
+ VerticalLayout content = new VerticalLayout();
+ content.addComponent(new Label(browserDetails.getUriFragmet()));
+ return new Root(content);
+ }
+ } else {
+ VerticalLayout content = new VerticalLayout();
+ Link lazyCreateLink = new Link("Open lazyCreate root",
+ new ExternalResource(getURL() + "?lazyCreate"));
+ lazyCreateLink.setTargetName("_blank");
+ content.addComponent(lazyCreateLink);
+ return new Root(content);
+ }
+ }
+
+ protected String getDescription() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}