Browse Source

#8052 Restore Portlet support

tags/7.0.0.alpha1
Leif Åstrand 12 years ago
parent
commit
5c481e2535

+ 1
- 0
WebContent/VAADIN/vaadinBootstrap.js View File

@@ -176,6 +176,7 @@
var app = apps[appId];
return app;
},
loadTheme: loadTheme,
registerWidgetset: function(widgetset, callback) {
log("Widgetset registered", widgetset)
widgetsets[widgetset].callback = callback;

+ 4
- 4
src/com/vaadin/terminal/CombinedRequest.java View File

@@ -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();
}
}

+ 77
- 0
src/com/vaadin/terminal/DeploymentConfiguration.java View File

@@ -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);
}

+ 52
- 8
src/com/vaadin/terminal/WrappedRequest.java View File

@@ -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;

@@ -186,14 +191,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
@@ -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();

}

+ 1
- 0
src/com/vaadin/terminal/WrappedResponse.java View File

@@ -34,4 +34,5 @@ public interface WrappedResponse extends Serializable {

public void sendError(int errorCode, String message) throws IOException;

public DeploymentConfiguration getDeploymentConfiguration();
}

+ 108
- 467
src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java View File

@@ -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;


+ 66
- 6
src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java View File

@@ -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.

+ 17
- 27
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java View File

@@ -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

+ 300
- 190
src/com/vaadin/terminal/gwt/server/AjaxPageHandler.java View File

@@ -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.

+ 13
- 0
src/com/vaadin/terminal/gwt/server/ApplicationRunnerServlet.java View File

@@ -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());
}
};
}

}

+ 57
- 0
src/com/vaadin/terminal/gwt/server/CommunicationManager.java View File

@@ -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;
}
}

+ 105
- 0
src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java View File

@@ -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;
}

}

+ 48
- 21
src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java View File

@@ -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;
}
}

+ 29
- 4
src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java View File

@@ -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;
}
}

+ 175
- 151
src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java View File

@@ -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);
}

}
/*
@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;
}
}

+ 32
- 2
src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java View File

@@ -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;
}
}

Loading…
Cancel
Save