@@ -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) { |
@@ -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()); | |||
@@ -283,6 +299,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. | |||
* | |||
@@ -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; | |||
} | |||
} |
@@ -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 | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} |
@@ -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 | |||
} |
@@ -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/")) { |
@@ -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); | |||
} | |||
}; | |||
@@ -1628,32 +1635,6 @@ public abstract class AbstractCommunicationManager implements | |||
outWriter.print("]"); // Close locales | |||
} | |||
/** | |||
* 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. | |||
* | |||
@@ -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. |
@@ -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; | |||
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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(); | |||
} | |||
@@ -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; | |||
} | |||
} |