@@ -176,6 +176,7 @@ | |||
var app = apps[appId]; | |||
return app; | |||
}, | |||
loadTheme: loadTheme, | |||
registerWidgetset: function(widgetset, callback) { | |||
log("Widgetset registered", widgetset) | |||
widgetsets[widgetset].callback = callback; |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} |
@@ -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(); | |||
} |
@@ -34,4 +34,5 @@ public interface WrappedResponse extends Serializable { | |||
public void sendError(int errorCode, String message) throws IOException; | |||
public DeploymentConfiguration getDeploymentConfiguration(); | |||
} |
@@ -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; | |||
@@ -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. |
@@ -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 |
@@ -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. |
@@ -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()); | |||
} | |||
}; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |