diff options
author | Leif Åstrand <leif@vaadin.com> | 2011-11-25 16:04:20 +0200 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2011-11-25 16:04:20 +0200 |
commit | 55948aefe8ead5054a83ec84d2e3624ffc1e7427 (patch) | |
tree | 7847a0bc9a16048fc5fca60eb6d13dc138afee96 | |
parent | d4057da1cd46f78d17a2ed678fe01ad1e04c5306 (diff) | |
download | vaadin-framework-55948aefe8ead5054a83ec84d2e3624ffc1e7427.tar.gz vaadin-framework-55948aefe8ead5054a83ec84d2e3624ffc1e7427.zip |
Initial support for lazy root creation
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; + } + +} |