diff options
16 files changed, 1085 insertions, 880 deletions
diff --git a/WebContent/VAADIN/vaadinBootstrap.js b/WebContent/VAADIN/vaadinBootstrap.js index 9a7a9d3569..47656d9406 100644 --- a/WebContent/VAADIN/vaadinBootstrap.js +++ b/WebContent/VAADIN/vaadinBootstrap.js @@ -176,6 +176,7 @@ var app = apps[appId]; return app; }, + loadTheme: loadTheme, registerWidgetset: function(widgetset, callback) { log("Widgetset registered", widgetset) widgetsets[widgetset].callback = callback; diff --git a/src/com/vaadin/terminal/CombinedRequest.java b/src/com/vaadin/terminal/CombinedRequest.java index 1eeb5aba90..ad1c715051 100644 --- a/src/com/vaadin/terminal/CombinedRequest.java +++ b/src/com/vaadin/terminal/CombinedRequest.java @@ -93,10 +93,6 @@ public class CombinedRequest implements WrappedRequest { return secondRequest.getContentType(); } - public String getStaticFileLocation() { - return secondRequest.getStaticFileLocation(); - } - public BrowserDetails getBrowserDetails() { return new BrowserDetails() { public String getUriFragment() { @@ -140,4 +136,8 @@ public class CombinedRequest implements WrappedRequest { public String getHeader(String name) { return secondRequest.getHeader(name); } + + public DeploymentConfiguration getDeploymentConfiguration() { + return secondRequest.getDeploymentConfiguration(); + } } diff --git a/src/com/vaadin/terminal/DeploymentConfiguration.java b/src/com/vaadin/terminal/DeploymentConfiguration.java new file mode 100644 index 0000000000..403a6d68b7 --- /dev/null +++ b/src/com/vaadin/terminal/DeploymentConfiguration.java @@ -0,0 +1,77 @@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal; + +import java.io.Serializable; + +/** + * Provide deployment specific settings that are required outside terminal + * specific code. + * + * @author Vaadin Ltd. + * + * @since 7.0 + */ +public interface DeploymentConfiguration extends Serializable { + + /** + * Gets the base URL of the location of Vaadin's static files. + * + * @param request + * the request for which the location should be determined + * + * @return a string with the base URL for static files + */ + public String getStaticFileLocation(WrappedRequest request); + + /** + * Gets the widgetset that is configured for this deployment, e.g. from a + * parameter in web.xml. + * + * @param request + * the request for which a widgetset is required + * @return the name of the widgetset + */ + public String getConfiguredWidgetset(WrappedRequest request); + + /** + * Gets the theme that is configured for this deployment, e.g. from a portal + * parameter or just some sensible default value. + * + * @param request + * the request for which a theme is required + * @return the name of the theme + */ + public String getConfiguredTheme(WrappedRequest request); + + /** + * Checks whether the Vaadin application will be rendered on its own in the + * browser or whether it will be included into some other context. A + * standalone application may do things that might interfere with other + * parts of a page, e.g. changing the page title and requesting focus upon + * loading. + * + * @param request + * the request for which the application is loaded + * @return a boolean indicating whether the application should be standalone + */ + public boolean isStandalone(WrappedRequest request); + + /** + * Gets a configured property. The properties are typically read from e.g. + * web.xml or from system properties of the JVM. + * + * @param propertyName + * The simple of the property, in some contexts, lookup might be + * performed using variations of the provided name. + * @param defaultValue + * the default value that should be used if no value has been + * defined + * @return the property value, or the passed default value if no property + * value is found + */ + public String getApplicationOrSystemProperty(String propertyName, + String defaultValue); +} diff --git a/src/com/vaadin/terminal/WrappedRequest.java b/src/com/vaadin/terminal/WrappedRequest.java index eb08453816..d3d5491788 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.Locale; import java.util.Map; +import javax.portlet.PortletRequest; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; + import com.vaadin.Application; import com.vaadin.RootRequiresMoreInformation; import com.vaadin.annotations.RootInitRequiresBrowserDetals; @@ -95,6 +99,7 @@ public interface WrappedRequest extends Serializable { * @return the input stream from which the contents of the request can be * read * @throws IOException + * if the input stream can not be opened */ public InputStream getInputStream() throws IOException; @@ -187,14 +192,6 @@ public interface WrappedRequest extends Serializable { public String getContentType(); /** - * Gets the base URL of the location of Vaadin's static files. - * - * @return a string with the base URL for static files - */ - // TODO Method would be more logical in WrappedResponse - public String getStaticFileLocation(); - - /** * Gets detailed information about the browser from which the request * originated. This consists of information that is not available from * normal HTTP requests, but requires additional information to be extracted @@ -213,12 +210,59 @@ public interface WrappedRequest extends Serializable { */ public BrowserDetails getBrowserDetails(); + /** + * Gets locale information from the query, e.g. using the Accept-Language + * header. + * + * @return the preferred Locale + * + * @see ServletRequest#getLocale() + * @see PortletRequest#getLocale() + */ public Locale getLocale(); + /** + * Returns the IP address from which the request came. This might also be + * the address of a proxy between the server and the original requester. + * + * @return a string containing the IP address, or <code>null</code> if the + * address is not available + * + * @see ServletRequest#getRemoteAddr() + */ public String getRemoteAddr(); + /** + * Checks whether the request was made using a secure channel, e.g. using + * https. + * + * @return a boolean indicating if the request is secure + * + * @see ServletRequest#isSecure() + * @see PortletRequest#isSecure() + */ public boolean isSecure(); + /** + * Gets the value of a request header, e.g. a http header for a + * {@link HttpServletRequest}. + * + * @param headerName + * the name of the header + * @return the header value, or <code>null</code> if the header is not + * present in the request + * + * @see HttpServletRequest#getHeader(String) + */ public String getHeader(String headerName); + /** + * Gets the deployment configuration for the context of this request. + * + * @return the deployment configuration + * + * @see DeploymentConfiguration + */ + public DeploymentConfiguration getDeploymentConfiguration(); + } diff --git a/src/com/vaadin/terminal/WrappedResponse.java b/src/com/vaadin/terminal/WrappedResponse.java index 52c72e716a..bbcc1ff003 100644 --- a/src/com/vaadin/terminal/WrappedResponse.java +++ b/src/com/vaadin/terminal/WrappedResponse.java @@ -34,4 +34,5 @@ public interface WrappedResponse extends Serializable { public void sendError(int errorCode, String message) throws IOException; + public DeploymentConfiguration getDeploymentConfiguration(); } diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java index 7d0b4f9c48..2453590fea 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java @@ -14,14 +14,10 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.security.GeneralSecurityException; -import java.util.Date; import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.Properties; -import java.util.logging.Level; import java.util.logging.Logger; import javax.portlet.ActionRequest; @@ -36,12 +32,10 @@ import javax.portlet.PortletException; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.PortletSession; -import javax.portlet.PortletURL; import javax.portlet.RenderRequest; import javax.portlet.RenderResponse; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; -import javax.portlet.ResourceURL; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; @@ -50,11 +44,10 @@ import com.liferay.portal.kernel.util.PortalClassInvoker; import com.liferay.portal.kernel.util.PropsUtil; import com.vaadin.Application; import com.vaadin.Application.SystemMessages; +import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.Terminal; import com.vaadin.terminal.WrappedRequest; import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConfiguration; -import com.vaadin.terminal.gwt.client.ApplicationConnection; import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback; import com.vaadin.ui.Root; @@ -76,8 +69,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet WrappedPortletRequest { public WrappedHttpAndPortletRequest(PortletRequest request, - HttpServletRequest originalRequest) { - super(request); + HttpServletRequest originalRequest, + DeploymentConfiguration deploymentConfiguration) { + super(request, deploymentConfiguration); this.originalRequest = originalRequest; } @@ -118,8 +112,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet private static class WrappedGateinRequest extends WrappedHttpAndPortletRequest { - public WrappedGateinRequest(PortletRequest request) { - super(request, getOriginalRequest(request)); + public WrappedGateinRequest(PortletRequest request, + DeploymentConfiguration deploymentConfiguration) { + super(request, getOriginalRequest(request), deploymentConfiguration); } private static final HttpServletRequest getOriginalRequest( @@ -140,8 +135,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet private static class WrappedLiferayRequest extends WrappedHttpAndPortletRequest { - public WrappedLiferayRequest(PortletRequest request) { - super(request, getOriginalRequest(request)); + public WrappedLiferayRequest(PortletRequest request, + DeploymentConfiguration deploymentConfiguration) { + super(request, getOriginalRequest(request), deploymentConfiguration); } @Override @@ -183,7 +179,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet public void criticalNotification(WrappedRequest request, WrappedResponse response, String cap, String msg, String details, String outOfSyncURL) throws IOException { - PortletRequest portletRequest = ((WrappedPortletRequest) request) + PortletRequest portletRequest = WrappedPortletRequest.cast(request) .getPortletRequest(); PortletResponse portletResponse = ((WrappedPortletResponse) response) .getPortletResponse(); @@ -207,20 +203,98 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet */ public static final String PORTLET_PARAMETER_STYLE = "style"; - private static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; + /** + * This portal parameter is used to define the name of the Vaadin theme that + * is used for all Vaadin applications in the portal. + */ + public static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; // TODO some parts could be shared with AbstractApplicationServlet // TODO Can we close the application when the portlet is removed? Do we know // when the portlet is removed? - // TODO What happens when the portlet window is resized? Do we know when the - // window is resized? - private Properties applicationProperties; private boolean productionMode = false; + private DeploymentConfiguration deploymentConfiguration = new DeploymentConfiguration() { + public String getConfiguredWidgetset(WrappedRequest request) { + + String widgetset = getApplicationOrSystemProperty( + PARAMETER_WIDGETSET, null); + + if (widgetset == null) { + // If no widgetset defined for the application, check the portal + // property + widgetset = WrappedPortletRequest.cast(request) + .getPortalProperty(PORTAL_PARAMETER_VAADIN_WIDGETSET); + } + + if (widgetset == null) { + // If no widgetset defined for the portal, use the default + widgetset = DEFAULT_WIDGETSET; + } + + return widgetset; + } + + public String getConfiguredTheme(WrappedRequest request) { + + // is the default theme defined by the portal? + String themeName = WrappedPortletRequest.cast(request) + .getPortalProperty(Constants.PORTAL_PARAMETER_VAADIN_THEME); + + if (themeName == null) { + // no, using the default theme defined by Vaadin + themeName = DEFAULT_THEME_NAME; + } + + return themeName; + } + + public String getApplicationOrSystemProperty(String propertyName, + String defaultValue) { + return AbstractApplicationPortlet.this + .getApplicationOrSystemProperty(propertyName, defaultValue); + } + + public boolean isStandalone(WrappedRequest request) { + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.DeploymentConfiguration#getStaticFileLocation + * (com.vaadin.terminal.WrappedRequest) + * + * Return the URL from where static files, e.g. the widgetset and the + * theme, are served. In a standard configuration the VAADIN folder + * inside the returned folder is what is used for widgetsets and themes. + * + * @return The location of static resources (inside which there should + * be a VAADIN directory). Does not end with a slash (/). + */ + public String getStaticFileLocation(WrappedRequest request) { + String staticFileLocation = WrappedPortletRequest.cast(request) + .getPortalProperty( + Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH); + if (staticFileLocation != null) { + // remove trailing slash if any + while (staticFileLocation.endsWith(".")) { + staticFileLocation = staticFileLocation.substring(0, + staticFileLocation.length() - 1); + } + return staticFileLocation; + } else { + // default for Liferay + return "/html"; + } + } + }; + @Override public void init(PortletConfig config) throws PortletException { super.init(config); @@ -433,15 +507,18 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet String portalInfo = request.getPortalContext().getPortalInfo() .toLowerCase(); if (portalInfo.contains("liferay")) { - wrappedRequest = new WrappedLiferayRequest(request); + wrappedRequest = new WrappedLiferayRequest(request, + getDeploymentConfiguration()); } else if (portalInfo.contains("gatein")) { - wrappedRequest = new WrappedGateinRequest(request); + wrappedRequest = new WrappedGateinRequest(request, + getDeploymentConfiguration()); } else { - wrappedRequest = new WrappedPortletRequest(request); + wrappedRequest = new WrappedPortletRequest(request, + getDeploymentConfiguration()); } WrappedPortletResponse wrappedResponse = new WrappedPortletResponse( - response); + response, getDeploymentConfiguration()); RequestType requestType = getRequestType(request); @@ -581,7 +658,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet } handleOtherRequest(wrappedRequest, wrappedResponse, - requestType, application, root, applicationContext, + requestType, application, applicationContext, applicationManager); } } catch (final SessionExpiredException e) { @@ -617,6 +694,10 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet } } + private DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } + private void handleUnknownRequest(PortletRequest request, PortletResponse response) { logger.warning("Unknown request type"); @@ -641,23 +722,15 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet */ private void handleOtherRequest(WrappedPortletRequest request, WrappedResponse response, RequestType requestType, - Application application, Root root, + Application application, PortletApplicationContext2 applicationContext, PortletCommunicationManager applicationManager) throws PortletException, IOException, MalformedURLException { - if (root == null) { - throw new PortletException(ERROR_NO_WINDOW_FOUND); - } - - if (requestType == RequestType.APPLICATION_RESOURCE) { + if (requestType == RequestType.APPLICATION_RESOURCE + || requestType == RequestType.RENDER) { if (!applicationManager.handleApplicationRequest(request, response)) { response.setStatus(404); } - } else if (requestType == RequestType.RENDER) { - PortletResponse portletResponse = ((WrappedPortletResponse) response) - .getPortletResponse(); - writeAjaxPage(request, (RenderResponse) portletResponse, root, - application); } else if (requestType == RequestType.EVENT) { // nothing to do, listeners do all the work } else if (requestType == RequestType.ACTION) { @@ -869,438 +942,6 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet return null; } - /** - * Returns the URL from which the widgetset is served on the portal. - * - * @param widgetset - * @param request - * @return - */ - protected String getWidgetsetURL(String widgetset, - WrappedPortletRequest request) { - return request.getStaticFileLocation() + "/" + WIDGETSET_DIRECTORY_PATH - + widgetset + "/" + widgetset + ".nocache.js?" - + new Date().getTime(); - } - - /** - * Returns the theme URI for the named theme on the portal. - * - * Note that this is not the only location referring to the theme URI - also - * e.g. PortletCommunicationManager uses its own way to access the portlet - * 2.0 theme resources. - * - * @param themeName - * @param request - * @return - */ - protected String getThemeURI(String themeName, WrappedPortletRequest request) { - return request.getStaticFileLocation() + "/" + THEME_DIRECTORY_PATH - + themeName; - } - - /** - * Writes the html host page (aka kickstart page) that starts the actual - * Vaadin application. - * - * If one needs to override parts of the portlet HTML contents creation, it - * is suggested that one overrides one of several submethods including: - * <ul> - * <li> - * {@link #writeAjaxPageHtmlMainDiv(RenderRequest, RenderResponse, BufferedWriter, String)} - * <li> - * {@link #getVaadinConfigurationMap(RenderRequest, RenderResponse, Application, String)} - * <li> - * {@link #writeAjaxPageHtmlVaadinScripts(RenderRequest, RenderResponse, BufferedWriter, Application, String)} - * </ul> - * - * @param request - * the portlet request. - * @param response - * the portlet response to write to. - * @param root - * @param application - * @throws IOException - * if the writing failed due to input/output error. - * @throws MalformedURLException - * if the application is denied access the persistent data store - * represented by the given URL. - * @throws PortletException - */ - protected void writeAjaxPage(WrappedPortletRequest request, - RenderResponse response, Root root, Application application) - throws IOException, MalformedURLException, PortletException { - - response.setContentType("text/html"); - final BufferedWriter page = new BufferedWriter(new OutputStreamWriter( - response.getPortletOutputStream(), "UTF-8")); - - // TODO Currently, we can only load widgetsets and themes from the - // portal - - String themeName = getThemeForRoot(request, root); - - writeAjaxPageHtmlVaadinScripts(request, response, page, application, - themeName); - - /*- Add classnames; - * .v-app - * .v-app-loading - * .v-app-<simpleName for app class> - * .v-theme-<themeName, remove non-alphanum> - */ - String appClass = "v-app-"; - try { - appClass += getApplicationClass().getSimpleName(); - } catch (ClassNotFoundException e) { - appClass += "unknown"; - logger.log(Level.SEVERE, "Could not find application class", e); - } - String themeClass = "v-theme-" - + themeName.replaceAll("[^a-zA-Z0-9]", ""); - - String classNames = "v-app " + themeClass + " " + appClass; - - String style = getApplicationProperty(PORTLET_PARAMETER_STYLE); - String divStyle = ""; - if (style != null) { - divStyle = "style=\"" + style + "\""; - } - - writeAjaxPageHtmlMainDiv(request, response, page, - getApplicationDomId(request.getPortletRequest()), classNames, - divStyle); - - page.close(); - } - - /** - * Creates and returns a unique ID for the DIV where the application is to - * be rendered. We need to generate a unique ID because some portals already - * create a DIV with the portlet's Window ID as the DOM ID. - * - * @param request - * PortletRequest - * @return the id to use in the DOM - */ - private String getApplicationDomId(PortletRequest request) { - return "v-" + request.getWindowID(); - } - - /** - * This method writes the scripts to load the widgetset and the themes as - * well as define Vaadin configuration parameters on the HTML fragment that - * starts the actual Vaadin application. - * - * @param request - * @param response - * @param writer - * @param application - * @param themeName - * @throws IOException - * @throws PortletException - */ - protected void writeAjaxPageHtmlVaadinScripts( - WrappedPortletRequest request, RenderResponse response, - final BufferedWriter writer, Application application, - String themeName) throws IOException, PortletException { - String themeURI = getThemeURI(themeName, request); - - // fixed base theme to use - all portal pages with Vaadin - // applications will load this exactly once - String portalTheme = request - .getPortalProperty(PORTAL_PARAMETER_VAADIN_THEME); - - writer.write("<script type=\"text/javascript\">\n"); - writer.write("if(!vaadin || !vaadin.vaadinConfigurations) {\n " - + "if(!vaadin) { var vaadin = {}} \n" - + "vaadin.vaadinConfigurations = {};\n" - + "if (!vaadin.themesLoaded) { vaadin.themesLoaded = {}; }\n"); - if (!isProductionMode()) { - writer.write("vaadin.debug = true;\n"); - } - - writeAjaxPageScriptWidgetset(request, response, writer); - - Map<String, String> config = getVaadinConfigurationMap(request, - response, application, themeURI); - writeAjaxPageScriptConfigurations(request, response, writer, config); - - writer.write("</script>\n"); - - writeAjaxPageHtmlTheme(request, writer, themeName, themeURI, - portalTheme); - - // TODO Warn if widgetset has not been loaded after 15 seconds - } - - /** - * Writes the script to load the widgetset on the HTML fragment created by - * the portlet. - * - * @param request - * @param response - * @param writer - * @throws IOException - */ - protected void writeAjaxPageScriptWidgetset(WrappedPortletRequest request, - RenderResponse response, final BufferedWriter writer) - throws IOException { - String requestWidgetset = getApplicationOrSystemProperty( - PARAMETER_WIDGETSET, null); - String sharedWidgetset = request - .getPortalProperty(PORTAL_PARAMETER_VAADIN_WIDGETSET); - - String widgetset; - if (requestWidgetset != null) { - widgetset = requestWidgetset; - } else if (sharedWidgetset != null) { - widgetset = sharedWidgetset; - } else { - widgetset = DEFAULT_WIDGETSET; - } - String widgetsetURL = getWidgetsetURL(widgetset, request); - writer.write("document.write('<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" " - + "style=\"position:absolute;width:0;height:0;border:0;overflow:" - + "hidden;opacity:0;top:-100px;left:-100px;\" src=\"javascript:false\"></iframe>');\n"); - writer.write("document.write(\"<script language='javascript' src='" - + widgetsetURL + "'><\\/script>\");\n}\n"); - } - - /** - * Returns the configuration parameters to pass to the client. - * - * To add configuration parameters for the client, override, call the super - * method and then modify the map. Overriding this method may also require - * client side changes in {@link ApplicationConnection} and - * {@link ApplicationConfiguration}. - * - * Note that this method must escape and quote the values when appropriate. - * - * The map returned is typically a {@link LinkedHashMap} to preserve - * insertion order, but it is not guaranteed to be one. - * - * @param request - * @param response - * @param application - * @param themeURI - * @return modifiable Map from parameter name to its full value - * @throws PortletException - */ - protected Map<String, String> getVaadinConfigurationMap( - WrappedPortletRequest request, RenderResponse response, - Application application, String themeURI) throws PortletException { - Map<String, String> config = new LinkedHashMap<String, String>(); - - /* - * We need this in order to get uploads to work. TODO this is not needed - * for uploads anymore, check if this is needed for some other things - */ - PortletURL appUri = response.createActionURL(); - config.put("appUri", "'" + appUri.toString() + "'"); - config.put("usePortletURLs", "true"); - ResourceURL uidlUrlBase = response.createResourceURL(); - uidlUrlBase.setResourceID("UIDL"); - config.put("portletUidlURLBase", "'" + uidlUrlBase.toString() + "'"); - config.put("pathInfo", "''"); - config.put("themeUri", "'" + themeURI + "'"); - - String versionInfo = "{vaadinVersion:\"" - + AbstractApplicationServlet.VERSION - + "\",applicationVersion:\"" + application.getVersion() + "\"}"; - config.put("versionInfo", versionInfo); - - // Get system messages - Application.SystemMessages systemMessages = null; - try { - systemMessages = getSystemMessages(); - } catch (SystemMessageException e) { - // failing to get the system messages is always a problem - throw new PortletException("Failed to obtain system messages!", e); - } - if (systemMessages != null) { - // Write the CommunicationError -message to client - String caption = systemMessages.getCommunicationErrorCaption(); - if (caption != null) { - caption = "\"" + caption + "\""; - } - String message = systemMessages.getCommunicationErrorMessage(); - if (message != null) { - message = "\"" + message + "\""; - } - String url = systemMessages.getCommunicationErrorURL(); - if (url != null) { - url = "\"" + url + "\""; - } - - config.put("\"comErrMsg\"", "{" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}"); - - // Write the AuthenticationError -message to client - caption = systemMessages.getAuthenticationErrorCaption(); - if (caption != null) { - caption = "\"" + caption + "\""; - } - message = systemMessages.getAuthenticationErrorMessage(); - if (message != null) { - message = "\"" + message + "\""; - } - url = systemMessages.getAuthenticationErrorURL(); - if (url != null) { - url = "\"" + url + "\""; - } - - config.put("\"authErrMsg\"", "{" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}"); - } - - return config; - } - - /** - * Constructs the Vaadin configuration section for - * {@link ApplicationConnection} and {@link ApplicationConfiguration}. - * - * Typically this method should not be overridden. Instead, modify - * {@link #getVaadinConfigurationMap(RenderRequest, RenderResponse, Application, String)} - * . - * - * @param request - * @param response - * @param writer - * @param config - * @throws IOException - * @throws PortletException - */ - protected void writeAjaxPageScriptConfigurations( - WrappedPortletRequest request, RenderResponse response, - final BufferedWriter writer, Map<String, String> config) - throws IOException, PortletException { - - writer.write("vaadin.vaadinConfigurations[\"" - + getApplicationDomId(request.getPortletRequest()) + "\"] = {"); - - Iterator<String> keyIt = config.keySet().iterator(); - while (keyIt.hasNext()) { - String key = keyIt.next(); - writer.write(key + ": " + config.get(key)); - if (keyIt.hasNext()) { - writer.write(", "); - } - } - - writer.write("};\n"); - } - - /** - * Writes the Vaadin theme loading section of the portlet HTML. Loads both - * the portal theme and the portlet theme in this order, skipping loading of - * themes that are already loaded (matched by name). - * - * @param request - * @param writer - * @param themeName - * @param themeURI - * @param portalTheme - * @throws IOException - */ - protected void writeAjaxPageHtmlTheme(WrappedPortletRequest request, - final BufferedWriter writer, String themeName, String themeURI, - String portalTheme) throws IOException { - writer.write("<script type=\"text/javascript\">\n"); - - if (portalTheme == null) { - portalTheme = DEFAULT_THEME_NAME; - } - - writer.write("if(!vaadin.themesLoaded['" + portalTheme + "']) {\n"); - writer.write("var defaultStylesheet = document.createElement('link');\n"); - writer.write("defaultStylesheet.setAttribute('rel', 'stylesheet');\n"); - writer.write("defaultStylesheet.setAttribute('type', 'text/css');\n"); - writer.write("defaultStylesheet.setAttribute('href', '" - + getThemeURI(portalTheme, request) + "/styles.css');\n"); - writer.write("document.getElementsByTagName('head')[0].appendChild(defaultStylesheet);\n"); - writer.write("vaadin.themesLoaded['" + portalTheme + "'] = true;\n}\n"); - - if (!portalTheme.equals(themeName)) { - writer.write("if(!vaadin.themesLoaded['" + themeName + "']) {\n"); - writer.write("var stylesheet = document.createElement('link');\n"); - writer.write("stylesheet.setAttribute('rel', 'stylesheet');\n"); - writer.write("stylesheet.setAttribute('type', 'text/css');\n"); - writer.write("stylesheet.setAttribute('href', '" + themeURI - + "/styles.css');\n"); - writer.write("document.getElementsByTagName('head')[0].appendChild(stylesheet);\n"); - writer.write("vaadin.themesLoaded['" + themeName - + "'] = true;\n}\n"); - } - - writer.write("</script>\n"); - } - - /** - * Method to write the div element into which that actual Vaadin application - * is rendered. - * <p> - * Override this method if you want to add some custom html around around - * the div element into which the actual Vaadin application will be - * rendered. - * - * @param request - * @param response - * @param writer - * @param id - * @param classNames - * @param divStyle - * @throws IOException - */ - protected void writeAjaxPageHtmlMainDiv(WrappedPortletRequest request, - RenderResponse response, final BufferedWriter writer, String id, - String classNames, String divStyle) throws IOException { - writer.write("<div id=\"" + id + "\" class=\"" + classNames + "\" " - + divStyle + ">"); - writer.write("<div class=\"v-app-loading\"></div>"); - writer.write("</div>\n"); - writer.write("<noscript>" + getNoScriptMessage() + "</noscript>"); - } - - /** - * Returns a message printed for browsers without scripting support or if - * browsers scripting support is disabled. - */ - protected String getNoScriptMessage() { - return "You have to enable javascript in your browser to use an application built with Vaadin."; - } - - /** - * Returns the theme for given request/window - * - * @param request - * @param window - * @return - */ - protected String getThemeForRoot(WrappedPortletRequest request, Root root) { - // Finds theme name - String themeName; - - // theme defined for the window? - themeName = null;// window.getTheme(); - - if (themeName == null) { - // no, is the default theme defined by the portal? - themeName = request - .getPortalProperty(Constants.PORTAL_PARAMETER_VAADIN_THEME); - } - - if (themeName == null) { - // no, using the default theme defined by Vaadin - themeName = DEFAULT_THEME_NAME; - } - - return themeName; - } - protected abstract Class<? extends Application> getApplicationClass() throws ClassNotFoundException; diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java index 90ab443d70..213d2e862d 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java @@ -36,6 +36,7 @@ import javax.servlet.http.HttpSession; import com.vaadin.Application; import com.vaadin.Application.SystemMessages; +import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.Terminal; import com.vaadin.terminal.ThemeResource; import com.vaadin.terminal.WrappedRequest; @@ -74,8 +75,8 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements public void criticalNotification(WrappedRequest request, WrappedResponse response, String cap, String msg, String details, String outOfSyncURL) throws IOException { - servlet.criticalNotification(((WrappedHttpServletRequest) request) - .getHttpServletRequest(), + servlet.criticalNotification(WrappedHttpServletRequest + .cast(request).getHttpServletRequest(), ((WrappedHttpServletResponse) response) .getHttpServletResponse(), cap, msg, details, outOfSyncURL); @@ -148,6 +149,37 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements private final String resourcePath = null; private int resourceCacheTime = 3600; + + private DeploymentConfiguration deploymentConfiguration = new DeploymentConfiguration() { + public String getStaticFileLocation(WrappedRequest request) { + HttpServletRequest servletRequest = WrappedHttpServletRequest.cast( + request).getHttpServletRequest(); + return AbstractApplicationServlet.this + .getStaticFilesLocation(servletRequest); + } + + public String getConfiguredWidgetset(WrappedRequest request) { + return getApplicationOrSystemProperty( + AbstractApplicationServlet.PARAMETER_WIDGETSET, + AbstractApplicationServlet.DEFAULT_WIDGETSET); + } + + public String getConfiguredTheme(WrappedRequest request) { + // Use the default + return AbstractApplicationServlet.getDefaultTheme(); + } + + public String getApplicationOrSystemProperty(String propertyName, + String defaultValue) { + return AbstractApplicationServlet.this + .getApplicationOrSystemProperty(propertyName, defaultValue); + } + + public boolean isStandalone(WrappedRequest request) { + return true; + } + }; + static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/"; /** @@ -363,10 +395,8 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements HttpServletResponse response) throws ServletException, IOException { AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper( this); - WrappedHttpServletRequest wrappedRequest = new WrappedHttpServletRequest( - request, this); - WrappedHttpServletResponse wrappedResponse = new WrappedHttpServletResponse( - response); + WrappedHttpServletRequest wrappedRequest = createWrappedRequest(request); + WrappedHttpServletResponse wrappedResponse = createWrappedResponse(response); RequestType requestType = getRequestType(request); if (!ensureCookiesEnabled(requestType, request, response)) { @@ -511,6 +541,36 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements } } + private WrappedHttpServletResponse createWrappedResponse( + HttpServletResponse response) { + WrappedHttpServletResponse wrappedResponse = new WrappedHttpServletResponse( + response, getDeploymentConfiguration()); + return wrappedResponse; + } + + /** + * Create a wrapped request for a http servlet request. This method can be + * overridden if the wrapped request should have special properties. + * + * @param request + * the original http servlet request + * @return a wrapped request for the original request + */ + protected WrappedHttpServletRequest createWrappedRequest( + HttpServletRequest request) { + return new WrappedHttpServletRequest(request, + getDeploymentConfiguration()); + } + + /** + * Gets a the deployment configuration for this servlet. + * + * @return the deployment configuration + */ + protected DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } + /** * Check that cookie support is enabled in the browser. Only checks UIDL * requests. diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 361f16048b..ec7d8eeb53 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -62,6 +62,7 @@ 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.AjaxPageHandler.AjaxPageContext; import com.vaadin.terminal.gwt.server.ComponentSizeValidator.InvalidLayout; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.AbstractField; @@ -95,26 +96,6 @@ public abstract class AbstractCommunicationManager implements .getLogger(AbstractCommunicationManager.class.getName()); private static final RequestHandler APP_RESOURCE_HANDLER = new ApplicationResourceHandler(); - private final AjaxPageHandler ajaxPageHandler = new AjaxPageHandler() { - - @Override - 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); - } - - @Override - protected AbstractCommunicationManager getCommunicationManager() { - return AbstractCommunicationManager.this; - } - - }; /** * TODO Document me! @@ -209,7 +190,7 @@ public abstract class AbstractCommunicationManager implements */ public AbstractCommunicationManager(Application application) { this.application = application; - application.addRequestHandler(ajaxPageHandler); + application.addRequestHandler(getAjaxPageHandler()); application.addRequestHandler(APP_RESOURCE_HANDLER); requireLocale(application.getLocale().toString()); } @@ -1968,6 +1949,14 @@ public abstract class AbstractCommunicationManager implements abstract protected void cleanStreamVariable(VariableOwner owner, String name); + /** + * Gets the ajax page handler that should be used for generating ajax pages + * for this communication manager. + * + * @return the ajax page handler to use + */ + protected abstract AjaxPageHandler getAjaxPageHandler(); + protected boolean handleApplicationRequest(WrappedRequest request, WrappedResponse response) throws IOException { return application.handleRequest(request, response); @@ -1989,12 +1978,13 @@ public abstract class AbstractCommunicationManager implements Root root = application.getRootForRequest(combinedRequest); // Use the same logic as for determined roots - String widgetset = ajaxPageHandler.getWidgetsetForRoot( - combinedRequest, root); - String theme = ajaxPageHandler.getThemeForRoot(combinedRequest, - root); - String themeUri = ajaxPageHandler.getThemeUri(theme, - combinedRequest); + AjaxPageHandler ajaxPageHandler = getAjaxPageHandler(); + AjaxPageContext context = ajaxPageHandler.createContext( + combinedRequest, response, application, root.getRootId()); + + String widgetset = context.getWidgetsetName(); + String theme = context.getThemeName(); + String themeUri = ajaxPageHandler.getThemeUri(context, theme); // TODO These are not required if it was only the init of the root // that was delayed diff --git a/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java b/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java index 6a9a35255e..b301a0c801 100644 --- a/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java +++ b/src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; +import java.io.Writer; import javax.servlet.http.HttpServletResponse; @@ -16,6 +17,8 @@ import com.vaadin.Application; import com.vaadin.RootRequiresMoreInformation; import com.vaadin.external.json.JSONException; import com.vaadin.external.json.JSONObject; +import com.vaadin.terminal.DeploymentConfiguration; +import com.vaadin.terminal.PaintException; import com.vaadin.terminal.RequestHandler; import com.vaadin.terminal.WrappedRequest; import com.vaadin.terminal.WrappedResponse; @@ -32,6 +35,90 @@ public abstract class AjaxPageHandler implements RequestHandler { */ protected abstract AbstractCommunicationManager getCommunicationManager(); + protected class AjaxPageContext { + private final WrappedResponse response; + private final WrappedRequest request; + private final Application application; + private final int rootId; + + private Writer writer; + private Root root; + private String widgetsetName; + private String themeName; + private String appId; + + private boolean rootFetched = false; + + public AjaxPageContext(WrappedResponse response, + WrappedRequest request, Application application, int rootId) { + this.response = response; + this.request = request; + this.application = application; + this.rootId = rootId; + } + + public WrappedResponse getResponse() { + return response; + } + + public WrappedRequest getRequest() { + return request; + } + + public Application getApplication() { + return application; + } + + public Writer getWriter() throws IOException { + if (writer == null) { + response.setContentType("text/html"); + writer = new BufferedWriter(new OutputStreamWriter( + response.getOutputStream(), "UTF-8")); + } + return writer; + } + + public int getRootId() { + return rootId; + } + + public Root getRoot() { + if (!rootFetched) { + root = Root.getCurrentRoot(); + rootFetched = true; + } + return root; + } + + public String getWidgetsetName() { + if (widgetsetName == null) { + Root root = getRoot(); + if (root != null) { + widgetsetName = getWidgetsetForRoot(this); + } + } + return widgetsetName; + } + + public String getThemeName() { + if (themeName == null) { + Root root = getRoot(); + if (root != null) { + themeName = findAndEscapeThemeName(this); + } + } + return themeName; + } + + public String getAppId() { + if (appId == null) { + appId = getApplicationId(this); + } + return appId; + } + + } + public boolean handleRequest(Application application, WrappedRequest request, WrappedResponse response) throws IOException { @@ -62,88 +149,63 @@ public abstract class AjaxPageHandler implements RequestHandler { protected final void writeAjaxPage(WrappedRequest request, WrappedResponse response, Application application, int rootId) throws IOException, JSONException { - final BufferedWriter page = new BufferedWriter(new OutputStreamWriter( - response.getOutputStream(), "UTF-8")); - Root root = Root.getCurrentRoot(); + AjaxPageContext context = createContext(request, response, application, + rootId); - String title = ((root == null || root.getCaption() == null) ? "Vaadin " - + AbstractApplicationServlet.VERSION_MAJOR : root.getCaption()); + DeploymentConfiguration deploymentConfiguration = request + .getDeploymentConfiguration(); - /* Fetch relative url to application */ - // don't use server and port in uri. It may cause problems with some - // virtual server configurations which lose the server name - String appUrl = application.getURL().getPath(); - if (appUrl.endsWith("/")) { - appUrl = appUrl.substring(0, appUrl.length() - 1); + boolean standalone = deploymentConfiguration.isStandalone(request); + if (standalone) { + setAjaxPageHeaders(context); + writeAjaxPageHtmlHeadStart(context); + writeAjaxPageHtmlHeader(context); + writeAjaxPageHtmlBodyStart(context); } - String themeName = getThemeForRoot(request, root); - - String themeUri = getThemeUri(themeName, request); - - setAjaxPageHeaders(response); - writeAjaxPageHtmlHeadStart(page, request); - writeAjaxPageHtmlHeader(page, title, themeUri, request); - writeAjaxPageHtmlBodyStart(page, request); - - String appId = appUrl; - if ("".equals(appUrl)) { - appId = "ROOT"; - } - appId = appId.replaceAll("[^a-zA-Z0-9]", ""); - // Add hashCode to the end, so that it is still (sort of) predictable, - // but indicates that it should not be used in CSS and such: - int hashCode = appId.hashCode(); - if (hashCode < 0) { - hashCode = -hashCode; - } - appId = appId + "-" + hashCode; - - String widgetset = getWidgetsetForRoot(request, root); - // TODO include initial UIDL in the scripts? - writeAjaxPageHtmlVaadinScripts(page, appUrl, themeUri, appId, request, - application, rootId, widgetset); + writeAjaxPageHtmlVaadinScripts(context); - /*- Add classnames; - * .v-app - * .v-app-loading - * .v-app-<simpleName for app class> - * .v-theme-<themeName, remove non-alphanum> - */ - - String appClass = "v-app-" + getApplicationCSSClassName(application); + writeAjaxPageHtmlMainDiv(context); - String themeClass = ""; - if (themeName != null) { - themeClass = "v-theme-" + themeName.replaceAll("[^a-zA-Z0-9]", ""); - } else { - themeClass = "v-theme-" - + AbstractApplicationServlet.getDefaultTheme().replaceAll( - "[^a-zA-Z0-9]", ""); + Writer page = context.getWriter(); + if (standalone) { + page.write("</body>\n</html>\n"); } - String classNames = "v-app " + themeClass + " " + appClass; - - writeAjaxPageHtmlMainDiv(page, appId, classNames, request); + page.close(); + } - page.write("</body>\n</html>\n"); + public AjaxPageContext createContext(WrappedRequest request, + WrappedResponse response, Application application, int rootId) { + AjaxPageContext context = new AjaxPageContext(response, request, + application, rootId); + return context; + } - page.close(); + protected String getMainDivStyle(AjaxPageContext context) { + return null; } - public String getWidgetsetForRoot(WrappedRequest request, Root root) { - if (root == null) { - // Defer widgetset selection - return null; - } + /** + * Creates and returns a unique ID for the DIV where the application is to + * be rendered. + * + * @param context + * + * @return the id to use in the DOM + */ + protected abstract String getApplicationId(AjaxPageContext context); + + public String getWidgetsetForRoot(AjaxPageContext context) { + Root root = context.getRoot(); + WrappedRequest request = context.getRequest(); String widgetset = root.getApplication().getWidgetsetForRoot(root); if (widgetset == null) { - widgetset = getApplicationOrSystemProperty(request, - AbstractApplicationServlet.PARAMETER_WIDGETSET, - AbstractApplicationServlet.DEFAULT_WIDGETSET); + widgetset = request.getDeploymentConfiguration() + .getConfiguredWidgetset(request); } widgetset = AbstractApplicationServlet.stripSpecialChars(widgetset); @@ -158,16 +220,42 @@ public abstract class AjaxPageHandler implements RequestHandler { * the div element into which the actual Vaadin application will be * rendered. * - * @param page - * @param appId - * @param classNames - * @param request + * @param context + * * @throws IOException */ - protected void writeAjaxPageHtmlMainDiv(final BufferedWriter page, - String appId, String classNames, WrappedRequest request) + protected void writeAjaxPageHtmlMainDiv(AjaxPageContext context) throws IOException { - page.write("<div id=\"" + appId + "\" class=\"" + classNames + "\">"); + Writer page = context.getWriter(); + String style = getMainDivStyle(context); + String themeName = context.getThemeName(); + + /*- Add classnames; + * .v-app + * .v-app-loading + * .v-app-<simpleName for app class> + * .v-theme-<themeName, remove non-alphanum> + */ + + String appClass = "v-app-" + + getApplicationCSSClassName(context.getApplication()); + + String themeClass = ""; + if (themeName != null) { + themeClass = "v-theme-" + themeName.replaceAll("[^a-zA-Z0-9]", ""); + } else { + themeClass = "v-theme-" + + AbstractApplicationServlet.getDefaultTheme().replaceAll( + "[^a-zA-Z0-9]", ""); + } + + String classNames = "v-app " + themeClass + " " + appClass; + + if (style != null && style.length() != 0) { + style = " style=\"" + style + "\""; + } + page.write("<div id=\"" + context.getAppId() + "\" class=\"" + + classNames + "\"" + style + ">"); page.write("<div class=\"v-app-loading\"></div>"); page.write("</div>\n"); page.write("<noscript>" + getNoScriptMessage() + "</noscript>"); @@ -203,12 +291,11 @@ public abstract class AjaxPageHandler implements RequestHandler { * <p> * Override this method if you want to add some custom html to the page. * - * @param page - * @param request * @throws IOException */ - protected void writeAjaxPageHtmlBodyStart(final BufferedWriter page, - final WrappedRequest request) throws IOException { + protected void writeAjaxPageHtmlBodyStart(AjaxPageContext context) + throws IOException { + Writer page = context.getWriter(); page.write("\n</head>\n<body scroll=\"auto\" class=\"" + ApplicationConnection.GENERATED_BODY_CLASSNAME + "\">\n"); } @@ -219,29 +306,24 @@ public abstract class AjaxPageHandler implements RequestHandler { * <p> * Override this method if you want to add some custom html around scripts. * - * @param page - * @param appUrl - * @param themeUri - * @param appId - * @param request - * @param application - * @param rootId + * @param context + * * @throws IOException * @throws JSONException */ - 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(); + protected void writeAjaxPageHtmlVaadinScripts(AjaxPageContext context) + throws IOException, JSONException { + WrappedRequest request = context.getRequest(); + Writer page = context.getWriter(); - String widgetsetBase = staticFileLocation + "/" - + AbstractApplicationServlet.WIDGETSET_DIRECTORY_PATH; + DeploymentConfiguration deploymentConfiguration = request + .getDeploymentConfiguration(); + String staticFileLocation = deploymentConfiguration + .getStaticFileLocation(request); - // Get system messages - Application.SystemMessages systemMessages = AbstractApplicationServlet - .getSystemMessages(application.getClass()); + page.write("<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" " + + "style=\"position:absolute;width:0;height:0;border:0;overflow:" + + "hidden;\" src=\"javascript:false\"></iframe>"); page.write("<script type=\"text/javascript\" src=\""); page.write(staticFileLocation); @@ -250,33 +332,90 @@ public abstract class AjaxPageHandler implements RequestHandler { page.write("<script type=\"text/javascript\">\n"); page.write("//<![CDATA[\n"); - JSONObject defaults = new JSONObject(); - JSONObject appConfig = new JSONObject(); + writeMainScriptTagContents(context); + page.write("//]]>\n</script>\n"); + } + + protected void writeMainScriptTagContents(AjaxPageContext context) + throws JSONException, IOException { + JSONObject defaults = getDefaultParameters(context); + JSONObject appConfig = getApplicationParameters(context); - boolean isDebug = !application.isProductionMode(); + boolean isDebug = !context.getApplication().isProductionMode(); + Writer page = context.getWriter(); + + page.write("vaadin.setDefaults("); + printJsonObject(page, defaults, isDebug); + page.write(");\n"); + + page.write("vaadin.initApplication(\""); + page.write(context.getAppId()); + page.write("\","); + printJsonObject(page, appConfig, isDebug); + page.write(");\n"); + } + + private static void printJsonObject(Writer page, JSONObject jsonObject, + boolean isDebug) throws IOException, JSONException { if (isDebug) { - defaults.put("debug", true); + page.write(jsonObject.toString(4)); + } else { + page.write(jsonObject.toString()); } + } - page.write("document.write('<iframe tabIndex=\"-1\" id=\"__gwt_historyFrame\" " - + "style=\"position:absolute;width:0;height:0;border:0;overflow:" - + "hidden;\" src=\"javascript:false\"></iframe>');\n"); + protected JSONObject getApplicationParameters(AjaxPageContext context) + throws JSONException, PaintException { + Application application = context.getApplication(); + int rootId = context.getRootId(); - defaults.put("appUri", appUrl); + JSONObject appConfig = new JSONObject(); appConfig.put(ApplicationConnection.ROOT_ID_PARAMETER, rootId); - if (isStandalone()) { - defaults.put("standalone", true); + if (context.getThemeName() != null) { + appConfig.put("themeUri", + getThemeUri(context, context.getThemeName())); } - appConfig.put("themeUri", themeUri); - JSONObject versionInfo = new JSONObject(); versionInfo.put("vaadinVersion", AbstractApplicationServlet.VERSION); versionInfo.put("applicationVersion", application.getVersion()); appConfig.put("versionInfo", versionInfo); + appConfig.put("widgetset", context.getWidgetsetName()); + + if (application.isRootInitPending(rootId)) { + appConfig.put("initPending", true); + } else { + // write the initial UIDL into the config + AbstractCommunicationManager manager = getCommunicationManager(); + Root root = Root.getCurrentRoot(); + manager.makeAllPaintablesDirty(root); + StringWriter sWriter = new StringWriter(); + PrintWriter pWriter = new PrintWriter(sWriter); + pWriter.print("{"); + if (manager.isXSRFEnabled(application)) { + pWriter.print(manager.getSecurityKeyUIDL(context.getRequest())); + } + manager.writeUidlResponce(null, true, pWriter, root, false); + pWriter.print("}"); + appConfig.put("uidl", sWriter.toString()); + } + + return appConfig; + } + + protected JSONObject getDefaultParameters(AjaxPageContext context) + throws JSONException { + JSONObject defaults = new JSONObject(); + + WrappedRequest request = context.getRequest(); + Application application = context.getApplication(); + + // Get system messages + Application.SystemMessages systemMessages = AbstractApplicationServlet + .getSystemMessages(application.getClass()); if (systemMessages != null) { // Write the CommunicationError -message to client JSONObject comErrMsg = new JSONObject(); @@ -298,75 +437,42 @@ public abstract class AjaxPageHandler implements RequestHandler { defaults.put("authErrMsg", authErrMsg); } + DeploymentConfiguration deploymentConfiguration = request + .getDeploymentConfiguration(); + String staticFileLocation = deploymentConfiguration + .getStaticFileLocation(request); + String widgetsetBase = staticFileLocation + "/" + + AbstractApplicationServlet.WIDGETSET_DIRECTORY_PATH; defaults.put("widgetsetBase", widgetsetBase); - appConfig.put("widgetset", widgetset); - - if (application.isRootInitPending(rootId)) { - appConfig.put("initPending", true); - } else { - // write the initial UIDL into the config - AbstractCommunicationManager manager = getCommunicationManager(); - Root root = Root.getCurrentRoot(); - manager.makeAllPaintablesDirty(root); - StringWriter sWriter = new StringWriter(); - PrintWriter pWriter = new PrintWriter(sWriter); - pWriter.print("{"); - if (manager.isXSRFEnabled(application)) { - pWriter.print(manager.getSecurityKeyUIDL(request)); - } - manager.writeUidlResponce(null, true, pWriter, root, false); - pWriter.print("}"); - appConfig.put("uidl", sWriter.toString()); - } - - page.write("vaadin.setDefaults("); - if (isDebug) { - page.write(defaults.toString(4)); - } else { - page.write(defaults.toString()); + if (!application.isProductionMode()) { + defaults.put("debug", true); } - page.write(");\n"); - page.write("vaadin.initApplication(\""); - page.write(appId); - page.write("\","); - if (isDebug) { - page.write(appConfig.toString(4)); - } else { - page.write(appConfig.toString()); + if (deploymentConfiguration.isStandalone(request)) { + defaults.put("standalone", true); } - page.write(");\n"); - page.write("//]]>\n</script>\n"); - } - protected abstract String getApplicationOrSystemProperty( - WrappedRequest request, String parameter, String defaultValue); + defaults.put("appUri", getAppUri(context)); - /** - * @return true if the served application is considered to be the only or - * main content of the host page. E.g. various embedding solutions - * should override this to false. - */ - protected boolean isStandalone() { - return true; + return defaults; } + protected abstract String getAppUri(AjaxPageContext context); + /** * Method to write the contents of head element in html kickstart page. * <p> * Override this method if you want to add some custom html to the header of * the page. * - * @param page - * @param title - * @param themeUri - * @param request * @throws IOException */ - protected void writeAjaxPageHtmlHeader(final BufferedWriter page, - String title, String themeUri, final WrappedRequest request) + protected void writeAjaxPageHtmlHeader(AjaxPageContext context) throws IOException { + Writer page = context.getWriter(); + String themeName = context.getThemeName(); + page.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"); // Chrome frame in all versions of IE (only if Chrome frame is @@ -377,13 +483,18 @@ public abstract class AjaxPageHandler implements RequestHandler { + "html, body {height:100%;margin:0;}</style>"); // Add favicon links - if (themeUri != null) { + if (themeName != null) { + String themeUri = getThemeUri(context, themeName); 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\" />"); } + Root root = context.getRoot(); + String title = ((root == null || root.getCaption() == null) ? "Vaadin " + + AbstractApplicationServlet.VERSION_MAJOR : root.getCaption()); + page.write("<title>" + AbstractApplicationServlet.safeEscapeForHtml(title) + "</title>"); @@ -394,9 +505,11 @@ public abstract class AjaxPageHandler implements RequestHandler { * <p> * Override this method if you need to customize http headers of the page. * - * @param response + * @param context */ - protected void setAjaxPageHeaders(WrappedResponse response) { + protected void setAjaxPageHeaders(AjaxPageContext context) { + WrappedResponse response = context.getResponse(); + // Window renders are not cacheable response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); @@ -413,12 +526,13 @@ public abstract class AjaxPageHandler implements RequestHandler { * Override this method if you want to add some custom html to the very * beginning of the page. * - * @param page - * @param request + * @param context * @throws IOException */ - protected void writeAjaxPageHtmlHeadStart(final BufferedWriter page, - final WrappedRequest request) throws IOException { + protected void writeAjaxPageHtmlHeadStart(AjaxPageContext context) + throws IOException { + Writer page = context.getWriter(); + // write html header page.write("<!DOCTYPE html PUBLIC \"-//W3C//DTD " + "XHTML 1.0 Transitional//EN\" " @@ -435,45 +549,41 @@ public abstract class AjaxPageHandler implements RequestHandler { * A portal-wide default theme is fetched from the portal shared resource * directory (if any), other themes from the portlet. * + * @param context * @param themeName - * @param request + * * @return */ - public String getThemeUri(String themeName, WrappedRequest request) { - if (themeName == null) { - return null; - } - final String staticFilePath = request.getStaticFileLocation(); + public String getThemeUri(AjaxPageContext context, String themeName) { + WrappedRequest request = context.getRequest(); + final String staticFilePath = request.getDeploymentConfiguration() + .getStaticFileLocation(request); return staticFilePath + "/" + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName; } /** - * Returns the theme for given request/root + * Override if required * - * @param request - * @param root + * @param context * @return */ - public String getThemeForRoot(WrappedRequest request, Root root) { - if (root == null) { - return null; - } - // Finds theme name - String themeName; - - if (request - .getParameter(AbstractApplicationServlet.URL_PARAMETER_THEME) != null) { - themeName = request - .getParameter(AbstractApplicationServlet.URL_PARAMETER_THEME); - } else { - themeName = root.getApplication().getThemeForRoot(root); - } + public String getThemeName(AjaxPageContext context) { + return context.getApplication().getThemeForRoot(context.getRoot()); + } + /** + * Don not override. + * + * @param context + * @return + */ + public String findAndEscapeThemeName(AjaxPageContext context) { + String themeName = getThemeName(context); if (themeName == null) { - // no explicit theme for root defined - // using the default theme defined by Vaadin - themeName = AbstractApplicationServlet.getDefaultTheme(); + WrappedRequest request = context.getRequest(); + themeName = request.getDeploymentConfiguration() + .getConfiguredTheme(request); } // XSS preventation, theme names shouldn't contain special chars anyway. diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java b/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java index 8809346f57..e41ea2a980 100644 --- a/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java +++ b/src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java @@ -250,4 +250,17 @@ public class ApplicationRunnerServlet extends AbstractApplicationServlet { return staticFilesPath; } + @Override + protected WrappedHttpServletRequest createWrappedRequest( + HttpServletRequest request) { + return new WrappedHttpServletRequest(request, + getDeploymentConfiguration()) { + @Override + public String getRequestPathInfo() { + return ApplicationRunnerServlet.this + .getRequestPathInfo(getHttpServletRequest()); + } + }; + } + } diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java index bd31e0aa56..e352d606c1 100644 --- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java @@ -5,6 +5,7 @@ package com.vaadin.terminal.gwt.server; import java.io.IOException; +import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -33,6 +34,57 @@ import com.vaadin.ui.Component; @SuppressWarnings("serial") public class CommunicationManager extends AbstractCommunicationManager { + private final AjaxPageHandler ajaxPageHandler = new AjaxPageHandler() { + @Override + protected String getApplicationId(AjaxPageContext context) { + String appUrl = getAppUri(context); + + String appId = appUrl; + if ("".equals(appUrl)) { + appId = "ROOT"; + } + appId = appId.replaceAll("[^a-zA-Z0-9]", ""); + // Add hashCode to the end, so that it is still (sort of) + // predictable, but indicates that it should not be used in CSS and + // such: + int hashCode = appId.hashCode(); + if (hashCode < 0) { + hashCode = -hashCode; + } + appId = appId + "-" + hashCode; + return appId; + } + + @Override + protected String getAppUri(AjaxPageContext context) { + /* Fetch relative url to application */ + // don't use server and port in uri. It may cause problems with some + // virtual server configurations which lose the server name + Application application = context.getApplication(); + URL url = application.getURL(); + String appUrl = url.getPath(); + if (appUrl.endsWith("/")) { + appUrl = appUrl.substring(0, appUrl.length() - 1); + } + return appUrl; + } + + @Override + public String getThemeName(AjaxPageContext context) { + String themeName = context.getRequest().getParameter( + AbstractApplicationServlet.URL_PARAMETER_THEME); + if (themeName == null) { + themeName = super.getThemeName(context); + } + return themeName; + } + + @Override + protected AbstractCommunicationManager getCommunicationManager() { + return CommunicationManager.this; + } + }; + /** * @deprecated use {@link #CommunicationManager(Application)} instead * @param application @@ -178,4 +230,9 @@ public class CommunicationManager extends AbstractCommunicationManager { pidToNameToStreamVariable.remove(getPaintableId((Paintable) owner)); } } + + @Override + protected AjaxPageHandler getAjaxPageHandler() { + return ajaxPageHandler; + } } diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java index 1762e0f1cf..d1398c14e1 100644 --- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java @@ -7,10 +7,17 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; +import javax.portlet.PortletRequest; +import javax.portlet.PortletResponse; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; import javax.portlet.ResourceResponse; import javax.portlet.ResourceURL; import com.vaadin.Application; +import com.vaadin.external.json.JSONException; +import com.vaadin.external.json.JSONObject; +import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.Paintable; import com.vaadin.terminal.StreamVariable; import com.vaadin.terminal.VariableOwner; @@ -28,6 +35,99 @@ import com.vaadin.ui.Root; @SuppressWarnings("serial") public class PortletCommunicationManager extends AbstractCommunicationManager { + private final AjaxPageHandler ajaxPageHandler = new AjaxPageHandler() { + + @Override + public boolean handleRequest(Application application, + WrappedRequest request, WrappedResponse response) + throws IOException { + PortletRequest portletRequest = WrappedPortletRequest.cast(request) + .getPortletRequest(); + if (portletRequest instanceof RenderRequest) { + return super.handleRequest(application, request, response); + } else { + return false; + } + } + + @Override + protected String getApplicationId(AjaxPageContext context) { + PortletRequest portletRequest = WrappedPortletRequest.cast( + context.getRequest()).getPortletRequest(); + /* + * We need to generate a unique ID because some portals already + * create a DIV with the portlet's Window ID as the DOM ID. + */ + return "v-" + portletRequest.getWindowID(); + } + + @Override + protected String getAppUri(AjaxPageContext context) { + return getRenderResponse(context).createActionURL().toString(); + } + + private RenderResponse getRenderResponse(AjaxPageContext context) { + PortletResponse response = ((WrappedPortletResponse) context + .getResponse()).getPortletResponse(); + + RenderResponse renderResponse = (RenderResponse) response; + return renderResponse; + } + + @Override + protected JSONObject getDefaultParameters(AjaxPageContext context) + throws JSONException { + /* + * We need this in order to get uploads to work. TODO this is not + * needed for uploads anymore, check if this is needed for some + * other things + */ + JSONObject defaults = super.getDefaultParameters(context); + defaults.put("usePortletURLs", true); + + ResourceURL uidlUrlBase = getRenderResponse(context) + .createResourceURL(); + uidlUrlBase.setResourceID("UIDL"); + defaults.put("portletUidlURLBase", uidlUrlBase.toString()); + defaults.put("pathInfo", ""); + + return defaults; + } + + @Override + protected void writeMainScriptTagContents(AjaxPageContext context) + throws JSONException, IOException { + // fixed base theme to use - all portal pages with Vaadin + // applications will load this exactly once + String portalTheme = WrappedPortletRequest.cast( + context.getRequest()).getPortalProperty( + AbstractApplicationPortlet.PORTAL_PARAMETER_VAADIN_THEME); + if (portalTheme != null + && !portalTheme.equals(context.getThemeName())) { + String portalThemeUri = getThemeUri(context, portalTheme); + // XSS safe - originates from portal properties + context.getWriter().write( + "vaadin.loadTheme('" + portalThemeUri + "')"); + } + + super.writeMainScriptTagContents(context); + } + + @Override + protected String getMainDivStyle(AjaxPageContext context) { + DeploymentConfiguration deploymentConfiguration = context + .getRequest().getDeploymentConfiguration(); + return deploymentConfiguration.getApplicationOrSystemProperty( + AbstractApplicationPortlet.PORTLET_PARAMETER_STYLE, null); + } + + @Override + protected AbstractCommunicationManager getCommunicationManager() { + return PortletCommunicationManager.this; + } + + }; + private transient ResourceResponse currentUidlResponse; public PortletCommunicationManager(Application application) { @@ -106,4 +206,9 @@ public class PortletCommunicationManager extends AbstractCommunicationManager { } } + @Override + protected AjaxPageHandler getAjaxPageHandler() { + return ajaxPageHandler; + } + } diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java index c6d3b06dd8..88ba0499a1 100644 --- a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java +++ b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java @@ -11,22 +11,37 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; +import com.vaadin.terminal.CombinedRequest; +import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.WrappedRequest; /** - * Concrete wrapper class for {@link HttpServletRequest}. + * Wrapper for {@link HttpServletRequest}. * - * @see Request + * @author Vaadin Ltd. + * @since 7.0 + * + * @see WrappedRequest + * @see WrappedHttpServletResponse */ public class WrappedHttpServletRequest implements WrappedRequest { private final HttpServletRequest request; - private final AbstractApplicationServlet servlet; - + private final DeploymentConfiguration deploymentConfiguration; + + /** + * Wraps a http servlet request and associates with a deployment + * configuration + * + * @param request + * the http servlet request to wrap + * @param deploymentConfiguration + * the associated deployment configuration + */ public WrappedHttpServletRequest(HttpServletRequest request, - AbstractApplicationServlet servlet) { + DeploymentConfiguration deploymentConfiguration) { this.request = request; - this.servlet = servlet; + this.deploymentConfiguration = deploymentConfiguration; } public Object getAttribute(String name) { @@ -49,20 +64,12 @@ public class WrappedHttpServletRequest implements WrappedRequest { return request.getParameterMap(); } - public String getRequestID() { - return "RequestURL:" + request.getRequestURI(); - } - - public Object getWrappedRequest() { - return request; - } - public void setAttribute(String name, Object o) { request.setAttribute(name, o); } public String getRequestPathInfo() { - return servlet.getRequestPathInfo(request); + return request.getPathInfo(); } public int getSessionMaxInactiveInterval() { @@ -77,6 +84,11 @@ public class WrappedHttpServletRequest implements WrappedRequest { request.getSession().setAttribute(name, attribute); } + /** + * Gets the original, unwrapped HTTP servlet request. + * + * @return the servlet request + */ public HttpServletRequest getHttpServletRequest() { return request; } @@ -85,12 +97,8 @@ public class WrappedHttpServletRequest implements WrappedRequest { return request.getContentType(); } - public AbstractApplicationServlet getServlet() { - return servlet; - } - - public String getStaticFileLocation() { - return servlet.getStaticFilesLocation(request); + public DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; } public BrowserDetails getBrowserDetails() { @@ -113,4 +121,23 @@ public class WrappedHttpServletRequest implements WrappedRequest { public String getHeader(String headerName) { return request.getHeader(headerName); } + + /** + * Helper method to get a <code>WrappedHttpServletRequest</code> from a + * <code>WrappedRequest</code>. Aside from casting, this method also takes + * care of situations where there's another level of wrapping. + * + * @param request + * a wrapped request + * @return a wrapped http servlet request + * @throws ClassCastException + * if the wrapped request doesn't wrap a http servlet request + */ + public static WrappedHttpServletRequest cast(WrappedRequest request) { + if (request instanceof CombinedRequest) { + CombinedRequest combinedRequest = (CombinedRequest) request; + request = combinedRequest.getSecondRequest(); + } + return (WrappedHttpServletRequest) request; + } }
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java index 8986221603..03a2eb1c8d 100644 --- a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java +++ b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java @@ -10,25 +10,46 @@ import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; +import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.WrappedResponse; /** - * Concrete wrapper class for {@link HttpServletResponse}. + * Wrapper for {@link HttpServletResponse}. * - * @see Response + * @author Vaadin Ltd. + * @since 7.0 + * + * @see WrappedResponse + * @see WrappedHttpServletRequest */ public class WrappedHttpServletResponse implements WrappedResponse { private final HttpServletResponse response; - - public WrappedHttpServletResponse(HttpServletResponse response) { + private DeploymentConfiguration deploymentConfiguration; + + /** + * Wraps a http servlet response and an associated deployment configuration + * + * @param response + * the http servlet response to wrap + * @param deploymentConfiguration + * the associated deployment configuration + */ + public WrappedHttpServletResponse(HttpServletResponse response, + DeploymentConfiguration deploymentConfiguration) { this.response = response; + this.deploymentConfiguration = deploymentConfiguration; } public OutputStream getOutputStream() throws IOException { return response.getOutputStream(); } + /** + * Gets the original unwrapped <code>HttpServletResponse</code> + * + * @return the unwrapped response + */ public HttpServletResponse getHttpServletResponse() { return response; } @@ -76,4 +97,8 @@ public class WrappedHttpServletResponse implements WrappedResponse { public void sendError(int errorCode, String message) throws IOException { response.sendError(errorCode, message); } + + public DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } }
\ 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 adf41b73c7..93627c1ff1 100644 --- a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java +++ b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java @@ -1,151 +1,175 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Locale; -import java.util.Map; - -import javax.portlet.ClientDataRequest; -import javax.portlet.PortletRequest; -import javax.portlet.ResourceRequest; - -import com.vaadin.terminal.WrappedRequest; - -public class WrappedPortletRequest implements WrappedRequest { - - private final PortletRequest request; - - public WrappedPortletRequest(PortletRequest request) { - this.request = request; - } - - public Object getAttribute(String name) { - return request.getAttribute(name); - } - - public int getContentLength() { - try { - return ((ClientDataRequest) request).getContentLength(); - } catch (ClassCastException e) { - throw new IllegalStateException( - "Content lenght only available for ClientDataRequests"); - } - } - - public InputStream getInputStream() throws IOException { - try { - return ((ClientDataRequest) request).getPortletInputStream(); - } catch (ClassCastException e) { - throw new IllegalStateException( - "Input data only available for ClientDataRequests"); - } - } - - public String getParameter(String name) { - return request.getParameter(name); - } - - public Map<String, String[]> getParameterMap() { - return request.getParameterMap(); - } - - public String getRequestID() { - return "WindowID:" + request.getWindowID(); - } - - public Object getWrappedRequest() { - return request; - } - - public void setAttribute(String name, Object o) { - request.setAttribute(name, o); - } - - public String getRequestPathInfo() { - if (request instanceof ResourceRequest) { - return ((ResourceRequest) request).getResourceID(); - } else { - // We do not use paths in portlet mode - throw new IllegalStateException( - "PathInfo only available when using ResourceRequests"); - } - } - - public int getSessionMaxInactiveInterval() { - return request.getPortletSession().getMaxInactiveInterval(); - } - - public Object getSessionAttribute(String name) { - return request.getPortletSession().getAttribute(name); - } - - public void setSessionAttribute(String name, Object attribute) { - request.getPortletSession().setAttribute(name, attribute); - } - - public PortletRequest getPortletRequest() { - return request; - } - - public String getContentType() { - try { - return ((ResourceRequest) request).getContentType(); - } catch (ClassCastException e) { - throw new IllegalStateException( - "Content type only available for ResourceRequests"); - } - } - - /* - * Return the URL from where static files, e.g. the widgetset and the theme, - * are served. In a standard configuration the VAADIN folder inside the - * returned folder is what is used for widgetsets and themes. - * - * @return The location of static resources (inside which there should be a - * VAADIN directory). Does not end with a slash (/). - */ - public String getStaticFileLocation() { - String staticFileLocation = getPortalProperty(Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH); - if (staticFileLocation != null) { - // remove trailing slash if any - while (staticFileLocation.endsWith(".")) { - staticFileLocation = staticFileLocation.substring(0, - staticFileLocation.length() - 1); - } - return staticFileLocation; - } else { - // default for Liferay - return "/html"; - } - } - - public BrowserDetails getBrowserDetails() { - // No browserDetails available for normal requests - return null; - } - - public Locale getLocale() { - return request.getLocale(); - } - - public String getRemoteAddr() { - return null; - } - - public boolean isSecure() { - return request.isSecure(); - } - - public String getHeader(String string) { - return null; - } - - public String getPortalProperty(String name) { - return request.getPortalContext().getProperty(name); - } - -}
\ No newline at end of file +/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.portlet.ClientDataRequest;
+import javax.portlet.PortletRequest;
+import javax.portlet.ResourceRequest;
+
+import com.vaadin.terminal.CombinedRequest;
+import com.vaadin.terminal.DeploymentConfiguration;
+import com.vaadin.terminal.WrappedRequest;
+
+/**
+ * Wrapper for {@link PortletRequest} and its subclasses.
+ *
+ * @author Vaadin Ltd.
+ * @since 7.0
+ *
+ * @see WrappedRequest
+ * @see WrappedPortletResponse
+ */
+public class WrappedPortletRequest implements WrappedRequest {
+
+ private final PortletRequest request;
+ private final DeploymentConfiguration deploymentConfiguration;
+
+ /**
+ * Wraps a portlet request and an associated deployment configuration
+ *
+ * @param request
+ * the portlet request to wrap
+ * @param deploymentConfiguration
+ * the associated deployment configuration
+ */
+ public WrappedPortletRequest(PortletRequest request,
+ DeploymentConfiguration deploymentConfiguration) {
+ this.request = request;
+ this.deploymentConfiguration = deploymentConfiguration;
+ }
+
+ public Object getAttribute(String name) {
+ return request.getAttribute(name);
+ }
+
+ public int getContentLength() {
+ try {
+ return ((ClientDataRequest) request).getContentLength();
+ } catch (ClassCastException e) {
+ throw new IllegalStateException(
+ "Content lenght only available for ClientDataRequests");
+ }
+ }
+
+ public InputStream getInputStream() throws IOException {
+ try {
+ return ((ClientDataRequest) request).getPortletInputStream();
+ } catch (ClassCastException e) {
+ throw new IllegalStateException(
+ "Input data only available for ClientDataRequests");
+ }
+ }
+
+ public String getParameter(String name) {
+ return request.getParameter(name);
+ }
+
+ public Map<String, String[]> getParameterMap() {
+ return request.getParameterMap();
+ }
+
+ public void setAttribute(String name, Object o) {
+ request.setAttribute(name, o);
+ }
+
+ public String getRequestPathInfo() {
+ if (request instanceof ResourceRequest) {
+ return ((ResourceRequest) request).getResourceID();
+ } else {
+ return null;
+ }
+ }
+
+ public int getSessionMaxInactiveInterval() {
+ return request.getPortletSession().getMaxInactiveInterval();
+ }
+
+ public Object getSessionAttribute(String name) {
+ return request.getPortletSession().getAttribute(name);
+ }
+
+ public void setSessionAttribute(String name, Object attribute) {
+ request.getPortletSession().setAttribute(name, attribute);
+ }
+
+ /**
+ * Gets the original, unwrapped portlet request.
+ *
+ * @return the unwrapped portlet request
+ */
+ public PortletRequest getPortletRequest() {
+ return request;
+ }
+
+ public String getContentType() {
+ try {
+ return ((ResourceRequest) request).getContentType();
+ } catch (ClassCastException e) {
+ throw new IllegalStateException(
+ "Content type only available for ResourceRequests");
+ }
+ }
+
+ public BrowserDetails getBrowserDetails() {
+ // No browserDetails available for normal requests
+ return null;
+ }
+
+ public Locale getLocale() {
+ return request.getLocale();
+ }
+
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ public boolean isSecure() {
+ return request.isSecure();
+ }
+
+ public String getHeader(String string) {
+ return null;
+ }
+
+ /**
+ * Reads a portal property from the portal context of the wrapped request.
+ *
+ * @param name
+ * a string with the name of the portal property to get
+ * @return a string with the value of the property, or <code>null</code> if
+ * the property is not defined
+ */
+ public String getPortalProperty(String name) {
+ return request.getPortalContext().getProperty(name);
+ }
+
+ public DeploymentConfiguration getDeploymentConfiguration() {
+ return deploymentConfiguration;
+ }
+
+ /**
+ * Helper method to get a <code>WrappedPortlettRequest</code> from a
+ * <code>WrappedRequest</code>. Aside from casting, this method also takes
+ * care of situations where there's another level of wrapping.
+ *
+ * @param request
+ * a wrapped request
+ * @return a wrapped portlet request
+ * @throws ClassCastException
+ * if the wrapped request doesn't wrap a portlet request
+ */
+ public static WrappedPortletRequest cast(WrappedRequest request) {
+ if (request instanceof CombinedRequest) {
+ CombinedRequest combinedRequest = (CombinedRequest) request;
+ request = combinedRequest.getSecondRequest();
+ }
+ return (WrappedPortletRequest) request;
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java index af8e726612..8824396352 100644 --- a/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java +++ b/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java @@ -17,8 +17,18 @@ import javax.portlet.MimeResponse; import javax.portlet.PortletResponse; import javax.portlet.ResourceResponse; +import com.vaadin.terminal.DeploymentConfiguration; import com.vaadin.terminal.WrappedResponse; +/** + * Wrapper for {@link PortletResponse} and its subclasses. + * + * @author Vaadin Ltd. + * @since 7.0 + * + * @see WrappedResponse + * @see WrappedPortletRequest + */ public class WrappedPortletResponse implements WrappedResponse { private static final DateFormat HTTP_DATE_FORMAT = new SimpleDateFormat( "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH); @@ -27,15 +37,31 @@ public class WrappedPortletResponse implements WrappedResponse { } private final PortletResponse response; - - public WrappedPortletResponse(PortletResponse response) { + private DeploymentConfiguration deploymentConfiguration; + + /** + * Wraps a portlet response and an associated deployment configuration + * + * @param response + * the portlet response to wrap + * @param deploymentConfiguration + * the associated deployment configuration + */ + public WrappedPortletResponse(PortletResponse response, + DeploymentConfiguration deploymentConfiguration) { this.response = response; + this.deploymentConfiguration = deploymentConfiguration; } public OutputStream getOutputStream() throws IOException { return ((MimeResponse) response).getPortletOutputStream(); } + /** + * Gets the original, unwrapped portlet response. + * + * @return the unwrapped portlet response + */ public PortletResponse getPortletResponse() { return response; } @@ -69,4 +95,8 @@ public class WrappedPortletResponse implements WrappedResponse { setStatus(errorCode); getWriter().write(message); } + + public DeploymentConfiguration getDeploymentConfiguration() { + return deploymentConfiguration; + } }
\ No newline at end of file |