diff options
Diffstat (limited to 'server/src')
21 files changed, 430 insertions, 411 deletions
diff --git a/server/src/com/vaadin/Application.java b/server/src/com/vaadin/Application.java index 1d716d60c5..b120c8455a 100644 --- a/server/src/com/vaadin/Application.java +++ b/server/src/com/vaadin/Application.java @@ -361,31 +361,24 @@ public class Application implements Terminal.ErrorListener, Serializable { public static class ApplicationStartEvent implements Serializable { private final URL applicationUrl; - private final Properties applicationProperties; + private final DeploymentConfiguration configuration; private final ApplicationContext context; - private final boolean productionMode; - /** * @param applicationUrl * the URL the application should respond to. - * @param applicationProperties - * the Application properties as specified by the deployment - * configuration. + * @param configuration + * the deployment configuration for the application. * @param context * the context application will be running in. - * @param productionMode - * flag indicating whether the application is running in - * production mode. */ public ApplicationStartEvent(URL applicationUrl, - Properties applicationProperties, ApplicationContext context, - boolean productionMode) { + DeploymentConfiguration configuration, + ApplicationContext context) { this.applicationUrl = applicationUrl; - this.applicationProperties = applicationProperties; + this.configuration = configuration; this.context = context; - this.productionMode = productionMode; } /** @@ -401,15 +394,12 @@ public class Application implements Terminal.ErrorListener, Serializable { } /** - * Gets the Application properties as specified by the deployment - * configuration. - * - * @return the properties configured for the applciation. + * Returns the deployment configuration used by this application. * - * @see Application#getProperty(String) + * @return the deployment configuration. */ - public Properties getApplicationProperties() { - return applicationProperties; + public DeploymentConfiguration getConfiguration() { + return configuration; } /** @@ -422,18 +412,6 @@ public class Application implements Terminal.ErrorListener, Serializable { public ApplicationContext getContext() { return context; } - - /** - * Checks whether the application is running in production mode. - * - * @return <code>true</code> if in production mode, else - * <code>false</code> - * - * @see Application#isProductionMode() - */ - public boolean isProductionMode() { - return productionMode; - } } private final static Logger logger = Logger.getLogger(Application.class @@ -445,6 +423,11 @@ public class Application implements Terminal.ErrorListener, Serializable { private ApplicationContext context; /** + * Deployment configuration for the application. + */ + private DeploymentConfiguration configuration; + + /** * The current user or <code>null</code> if no user has logged in. */ private Object user; @@ -460,11 +443,6 @@ public class Application implements Terminal.ErrorListener, Serializable { private volatile boolean applicationIsRunning = false; /** - * Application properties. - */ - private Properties properties; - - /** * Default locale of the application. */ private Locale locale; @@ -512,8 +490,6 @@ public class Application implements Terminal.ErrorListener, Serializable { private int nextRootId = 0; private Map<Integer, Root> roots = new HashMap<Integer, Root>(); - private boolean productionMode = true; - private final Map<String, Integer> retainOnRefreshRoots = new HashMap<String, Integer>(); private final EventRouter eventRouter = new EventRouter(); @@ -638,8 +614,7 @@ public class Application implements Terminal.ErrorListener, Serializable { */ public void start(ApplicationStartEvent event) { applicationUrl = event.getApplicationUrl(); - productionMode = event.isProductionMode(); - properties = event.getApplicationProperties(); + configuration = event.getConfiguration(); context = event.getContext(); init(); applicationIsRunning = true; @@ -673,6 +648,16 @@ public class Application implements Terminal.ErrorListener, Serializable { } /** + * Returns the properties of this application as specified in the deployment + * configuration. + * + * @return Application properties + */ + protected Properties getProperties() { + return configuration.getInitParameters(); + } + + /** * Returns an enumeration of all the names in this application. * * <p> @@ -685,7 +670,7 @@ public class Application implements Terminal.ErrorListener, Serializable { * */ public Enumeration<?> getPropertyNames() { - return properties.propertyNames(); + return getProperties().propertyNames(); } /** @@ -700,7 +685,7 @@ public class Application implements Terminal.ErrorListener, Serializable { * @return the value in this property list with the specified key value. */ public String getProperty(String name) { - return properties.getProperty(name); + return getProperties().getProperty(name); } /** @@ -1930,7 +1915,7 @@ public class Application implements Terminal.ErrorListener, Serializable { * @since 7.0 */ protected String getRootClassName(WrappedRequest request) { - Object rootClassNameObj = properties.get(ROOT_PARAMETER); + Object rootClassNameObj = getProperties().get(ROOT_PARAMETER); if (rootClassNameObj instanceof String) { return (String) rootClassNameObj; } else { @@ -2181,7 +2166,7 @@ public class Application implements Terminal.ErrorListener, Serializable { * @since 7.0 */ public boolean isProductionMode() { - return productionMode; + return configuration.isProductionMode(); } /** diff --git a/server/src/com/vaadin/terminal/AbstractClientConnector.java b/server/src/com/vaadin/terminal/AbstractClientConnector.java index 0eb38a3d13..bc1cd2af1a 100644 --- a/server/src/com/vaadin/terminal/AbstractClientConnector.java +++ b/server/src/com/vaadin/terminal/AbstractClientConnector.java @@ -518,4 +518,9 @@ public abstract class AbstractClientConnector implements ClientConnector { return getParent().isConnectorEnabled(); } } + + @Override + public void beforeClientResponse(boolean initial) { + // Do nothing by default + } } diff --git a/server/src/com/vaadin/terminal/DeploymentConfiguration.java b/server/src/com/vaadin/terminal/DeploymentConfiguration.java index 74d0320ff8..14a5a3724f 100644 --- a/server/src/com/vaadin/terminal/DeploymentConfiguration.java +++ b/server/src/com/vaadin/terminal/DeploymentConfiguration.java @@ -132,4 +132,25 @@ public interface DeploymentConfiguration extends Serializable { public AddonContext getAddonContext(); public void setAddonContext(AddonContext vaadinContext); + + /** + * Returns whether Vaadin is in production mode. + * + * @return true if in production mode, false otherwise. + */ + public boolean isProductionMode(); + + /** + * Returns whether cross-site request forgery protection is enabled. + * + * @return true if XSRF protection is enabled, false otherwise. + */ + public boolean isXsrfProtectionEnabled(); + + /** + * Returns the time resources can be cached in the browsers, in seconds. + * + * @return The resource cache time. + */ + public int getResourceCacheTime(); } diff --git a/server/src/com/vaadin/terminal/Page.java b/server/src/com/vaadin/terminal/Page.java index d5d474e2e3..933f9b39e6 100644 --- a/server/src/com/vaadin/terminal/Page.java +++ b/server/src/com/vaadin/terminal/Page.java @@ -376,23 +376,17 @@ public class Page implements Serializable { .getBrowser(); } - public void setBrowserWindowSize(Integer width, Integer height) { + public void setBrowserWindowSize(int width, int height) { boolean fireEvent = false; - if (width != null) { - int newWidth = width.intValue(); - if (newWidth != browserWindowWidth) { - browserWindowWidth = newWidth; - fireEvent = true; - } + if (width != browserWindowWidth) { + browserWindowWidth = width; + fireEvent = true; } - if (height != null) { - int newHeight = height.intValue(); - if (newHeight != browserWindowHeight) { - browserWindowHeight = newHeight; - fireEvent = true; - } + if (height != browserWindowHeight) { + browserWindowHeight = height; + fireEvent = true; } if (fireEvent) { diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java index 7892018218..bd39504237 100644 --- a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java +++ b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java @@ -217,99 +217,13 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet // TODO Can we close the application when the portlet is removed? Do we know // when the portlet is removed? - private boolean productionMode = false; - - private DeploymentConfiguration deploymentConfiguration = new AbstractDeploymentConfiguration( - getClass()) { - @Override - 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; - } - - @Override - 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; - } - - @Override - 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 (/). - */ - - @Override - 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 String getMimeType(String resourceName) { - return getPortletContext().getMimeType(resourceName); - } - }; - - private final AddonContext addonContext = new AddonContext( - getDeploymentConfiguration()); + private DeploymentConfiguration deploymentConfiguration; + private AddonContext addonContext; @Override public void init(PortletConfig config) throws PortletException { super.init(config); - Properties applicationProperties = getDeploymentConfiguration() - .getInitParameters(); + Properties applicationProperties = new Properties(); // Read default parameters from the context final PortletContext context = config.getPortletContext(); @@ -328,45 +242,101 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet config.getInitParameter(name)); } - checkProductionMode(); - checkCrossSiteProtection(); + deploymentConfiguration = new AbstractDeploymentConfiguration( + getClass(), applicationProperties) { + @Override + public String getConfiguredWidgetset(WrappedRequest request) { - addonContext.init(); - } + String widgetset = getApplicationOrSystemProperty( + PARAMETER_WIDGETSET, null); - @Override - public void destroy() { - super.destroy(); + if (widgetset == null) { + // If no widgetset defined for the application, check the + // portal property + widgetset = WrappedPortletRequest.cast(request) + .getPortalProperty( + PORTAL_PARAMETER_VAADIN_WIDGETSET); + } - addonContext.destroy(); - } + if (widgetset == null) { + // If no widgetset defined for the portal, use the default + widgetset = DEFAULT_WIDGETSET; + } + + return widgetset; + } + + @Override + 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; + } + + @Override + public boolean isStandalone(WrappedRequest request) { + return false; + } - private void checkCrossSiteProtection() { - if (getDeploymentConfiguration().getApplicationOrSystemProperty( - SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, "false").equals( - "true")) { /* - * Print an information/warning message about running with xsrf - * protection disabled + * (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 (/). */ - getLogger().warning(WARNING_XSRF_PROTECTION_DISABLED); - } + + @Override + 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 String getMimeType(String resourceName) { + return getPortletContext().getMimeType(resourceName); + } + }; + + addonContext = new AddonContext(deploymentConfiguration); + addonContext.init(); } - private void checkProductionMode() { - // TODO Identical code in AbstractApplicationServlet -> refactor - // Check if the application is in production mode. - // We are in production mode if productionMode=true - if (getDeploymentConfiguration().getApplicationOrSystemProperty( - SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) { - productionMode = true; - } + @Override + public void destroy() { + super.destroy(); - if (!productionMode) { - /* Print an information/warning message about running in debug mode */ - // TODO Maybe we need a different message for portlets? - getLogger().warning(NOT_PRODUCTION_MODE_INFO); - } + addonContext.destroy(); } protected enum RequestType { @@ -415,13 +385,13 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet } /** - * Returns true if the servlet is running in production mode. Production + * Returns true if the portlet is running in production mode. Production * mode disables all debug facilities. * * @return true if in production mode, false if in debug mode */ public boolean isProductionMode() { - return productionMode; + return deploymentConfiguration.isProductionMode(); } protected void handleRequest(PortletRequest request, @@ -811,8 +781,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet application.setLocale(locale); // No application URL when running inside a portlet application.start(new ApplicationStartEvent(null, - getDeploymentConfiguration().getInitParameters(), context, - isProductionMode())); + getDeploymentConfiguration(), context)); addonContext.fireApplicationStarted(application); } } diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java index dcab8b44f5..062ba6cdf7 100644 --- a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java @@ -97,49 +97,11 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements // TODO Move some (all?) of the constants to a separate interface (shared // with portlet) - private boolean productionMode = false; - private final String resourcePath = null; - private int resourceCacheTime = 3600; - - private DeploymentConfiguration deploymentConfiguration = new AbstractDeploymentConfiguration( - getClass()) { - - @Override - public String getStaticFileLocation(WrappedRequest request) { - HttpServletRequest servletRequest = WrappedHttpServletRequest - .cast(request); - return AbstractApplicationServlet.this - .getStaticFilesLocation(servletRequest); - } - - @Override - public String getConfiguredWidgetset(WrappedRequest request) { - return getApplicationOrSystemProperty( - AbstractApplicationServlet.PARAMETER_WIDGETSET, - AbstractApplicationServlet.DEFAULT_WIDGETSET); - } - - @Override - public String getConfiguredTheme(WrappedRequest request) { - // Use the default - return AbstractApplicationServlet.getDefaultTheme(); - } - - @Override - public boolean isStandalone(WrappedRequest request) { - return true; - } + private DeploymentConfiguration deploymentConfiguration; - @Override - public String getMimeType(String resourceName) { - return getServletContext().getMimeType(resourceName); - } - }; - - private final AddonContext addonContext = new AddonContext( - getDeploymentConfiguration()); + private AddonContext addonContext; /** * Called by the servlet container to indicate to a servlet that the servlet @@ -156,8 +118,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements public void init(javax.servlet.ServletConfig servletConfig) throws javax.servlet.ServletException { super.init(servletConfig); - Properties applicationProperties = getDeploymentConfiguration() - .getInitParameters(); + Properties applicationProperties = new Properties(); // Read default parameters from server.xml final ServletContext context = servletConfig.getServletContext(); @@ -176,10 +137,42 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements servletConfig.getInitParameter(name)); } - checkProductionMode(); - checkCrossSiteProtection(); - checkResourceCacheTime(); + deploymentConfiguration = new AbstractDeploymentConfiguration( + getClass(), applicationProperties) { + + @Override + public String getStaticFileLocation(WrappedRequest request) { + HttpServletRequest servletRequest = WrappedHttpServletRequest + .cast(request); + return AbstractApplicationServlet.this + .getStaticFilesLocation(servletRequest); + } + + @Override + public String getConfiguredWidgetset(WrappedRequest request) { + return getApplicationOrSystemProperty( + AbstractApplicationServlet.PARAMETER_WIDGETSET, + AbstractApplicationServlet.DEFAULT_WIDGETSET); + } + + @Override + public String getConfiguredTheme(WrappedRequest request) { + // Use the default + return AbstractApplicationServlet.getDefaultTheme(); + } + + @Override + public boolean isStandalone(WrappedRequest request) { + return true; + } + @Override + public String getMimeType(String resourceName) { + return getServletContext().getMimeType(resourceName); + } + }; + + addonContext = new AddonContext(deploymentConfiguration); addonContext.init(); } @@ -190,47 +183,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements addonContext.destroy(); } - private void checkCrossSiteProtection() { - if (getDeploymentConfiguration().getApplicationOrSystemProperty( - SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, "false").equals( - "true")) { - /* - * Print an information/warning message about running with xsrf - * protection disabled - */ - getLogger().warning(WARNING_XSRF_PROTECTION_DISABLED); - } - } - - private void checkProductionMode() { - // Check if the application is in production mode. - // We are in production mode if productionMode=true - if (getDeploymentConfiguration().getApplicationOrSystemProperty( - SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) { - productionMode = true; - } - - if (!productionMode) { - /* Print an information/warning message about running in debug mode */ - getLogger().warning(NOT_PRODUCTION_MODE_INFO); - } - - } - - private void checkResourceCacheTime() { - // Check if the browser caching time has been set in web.xml - try { - String rct = getDeploymentConfiguration() - .getApplicationOrSystemProperty( - SERVLET_PARAMETER_RESOURCE_CACHE_TIME, "3600"); - resourceCacheTime = Integer.parseInt(rct); - } catch (NumberFormatException nfe) { - // Default is 1h - resourceCacheTime = 3600; - getLogger().warning(WARNING_RESOURCE_CACHING_TIME_NOT_NUMERIC); - } - } - /** * Returns true if the servlet is running in production mode. Production * mode disables all debug facilities. @@ -238,17 +190,17 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements * @return true if in production mode, false if in debug mode */ public boolean isProductionMode() { - return productionMode; + return getDeploymentConfiguration().isProductionMode(); } /** - * Returns the amount of milliseconds the browser should cache a file. - * Default is 1 hour (3600 ms). + * Returns the number of seconds the browser should cache a file. Default is + * 1 hour (3600 s). * - * @return The amount of milliseconds files are cached in the browser + * @return The number of seconds files are cached in the browser */ public int getResourceCacheTime() { - return resourceCacheTime; + return getDeploymentConfiguration().getResourceCacheTime(); } /** @@ -909,8 +861,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements Locale locale = request.getLocale(); application.setLocale(locale); application.start(new ApplicationStartEvent(applicationUrl, - getDeploymentConfiguration().getInitParameters(), - webApplicationContext, isProductionMode())); + getDeploymentConfiguration(), webApplicationContext)); addonContext.fireApplicationStarted(application); } } @@ -1056,7 +1007,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements * parameter in web.xml */ response.setHeader("Cache-Control", - "max-age= " + String.valueOf(resourceCacheTime)); + "max-age= " + String.valueOf(getResourceCacheTime())); } // Write the resource to the client. diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index 00e65382cd..99376ffd1f 100644 --- a/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -68,7 +68,9 @@ import com.vaadin.external.json.JSONException; import com.vaadin.external.json.JSONObject; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.Connector; +import com.vaadin.shared.JavaScriptConnectorState; import com.vaadin.shared.Version; +import com.vaadin.shared.communication.LegacyChangeVariablesInvocation; import com.vaadin.shared.communication.MethodInvocation; import com.vaadin.shared.communication.SharedState; import com.vaadin.shared.communication.UidlValue; @@ -818,6 +820,7 @@ public abstract class AbstractCommunicationManager implements Serializable { if (repaintAll) { getClientCache(root).clear(); rootConnectorTracker.markAllConnectorsDirty(); + rootConnectorTracker.markAllClientSidesUninitialized(); // Reset sent locales locales = null; @@ -832,9 +835,9 @@ public abstract class AbstractCommunicationManager implements Serializable { "Found " + dirtyVisibleConnectors.size() + " dirty connectors to paint"); for (ClientConnector connector : dirtyVisibleConnectors) { - if (connector instanceof Component) { - ((Component) connector).updateState(); - } + boolean initialized = rootConnectorTracker + .isClientSideInitialized(connector); + connector.beforeClientResponse(!initialized); } rootConnectorTracker.markAllConnectorsClean(); @@ -883,23 +886,36 @@ public abstract class AbstractCommunicationManager implements Serializable { try { Class<? extends SharedState> stateType = connector .getStateType(); - SharedState referenceState = null; - if (repaintAll) { + Object diffState = rootConnectorTracker + .getDiffState(connector); + if (diffState == null) { + diffState = new JSONObject(); // Use an empty state object as reference for full // repaints - try { - referenceState = stateType.newInstance(); - } catch (Exception e) { - getLogger().log( - Level.WARNING, - "Error creating reference object for state of type " - + stateType.getName()); + boolean emptyInitialState = JavaScriptConnectorState.class + .isAssignableFrom(stateType); + if (!emptyInitialState) { + try { + SharedState referenceState = stateType + .newInstance(); + diffState = JsonCodec.encode(referenceState, + null, stateType, + root.getConnectorTracker()); + } catch (Exception e) { + getLogger().log( + Level.WARNING, + "Error creating reference object for state of type " + + stateType.getName()); + } } + rootConnectorTracker.setDiffState(connector, diffState); } - Object stateJson = JsonCodec.encode(state, referenceState, - stateType, root.getConnectorTracker()); + JSONObject stateJson = (JSONObject) JsonCodec.encode(state, + diffState, stateType, root.getConnectorTracker()); - sharedStates.put(connector.getConnectorId(), stateJson); + if (stateJson.length() != 0) { + sharedStates.put(connector.getConnectorId(), stateJson); + } } catch (JSONException e) { throw new PaintException( "Failed to serialize shared state for connector " @@ -1250,6 +1266,10 @@ public abstract class AbstractCommunicationManager implements Serializable { dragAndDropService.printJSONResponse(outWriter); } + for (ClientConnector connector : dirtyVisibleConnectors) { + rootConnectorTracker.markClientSideInitialized(connector); + } + writePerformanceData(outWriter); } diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java b/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java index 33e1c43b38..ad5acad5e9 100644 --- a/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java +++ b/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java @@ -20,6 +20,7 @@ import java.lang.reflect.Constructor; import java.util.Iterator; import java.util.Properties; import java.util.ServiceLoader; +import java.util.logging.Logger; import com.vaadin.terminal.DeploymentConfiguration; @@ -27,11 +28,20 @@ public abstract class AbstractDeploymentConfiguration implements DeploymentConfiguration { private final Class<?> systemPropertyBaseClass; - private final Properties applicationProperties = new Properties(); + private final Properties applicationProperties; private AddonContext addonContext; + private boolean productionMode; + private boolean xsrfProtectionEnabled; + private int resourceCacheTime; - public AbstractDeploymentConfiguration(Class<?> systemPropertyBaseClass) { + public AbstractDeploymentConfiguration(Class<?> systemPropertyBaseClass, + Properties applicationProperties) { this.systemPropertyBaseClass = systemPropertyBaseClass; + this.applicationProperties = applicationProperties; + + checkProductionMode(); + checkXsrfProtection(); + checkResourceCacheTime(); } @Override @@ -152,4 +162,63 @@ public abstract class AbstractDeploymentConfiguration implements public AddonContext getAddonContext() { return addonContext; } + + @Override + public boolean isProductionMode() { + return productionMode; + } + + @Override + public boolean isXsrfProtectionEnabled() { + return xsrfProtectionEnabled; + } + + @Override + public int getResourceCacheTime() { + return resourceCacheTime; + } + + /** + * Log a warning if Vaadin is not running in production mode. + */ + private void checkProductionMode() { + productionMode = getApplicationOrSystemProperty( + Constants.SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals( + "true"); + if (!productionMode) { + getLogger().warning(Constants.NOT_PRODUCTION_MODE_INFO); + } + } + + /** + * Log a warning if cross-site request forgery protection is disabled. + */ + private void checkXsrfProtection() { + xsrfProtectionEnabled = !getApplicationOrSystemProperty( + Constants.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, "false") + .equals("true"); + if (!xsrfProtectionEnabled) { + getLogger().warning(Constants.WARNING_XSRF_PROTECTION_DISABLED); + } + } + + /** + * Log a warning if resource cache time is set but is not an integer. + */ + private void checkResourceCacheTime() { + try { + resourceCacheTime = Integer + .parseInt(getApplicationOrSystemProperty( + Constants.SERVLET_PARAMETER_RESOURCE_CACHE_TIME, + "3600")); + } catch (NumberFormatException e) { + getLogger().warning( + Constants.WARNING_RESOURCE_CACHING_TIME_NOT_NUMERIC); + resourceCacheTime = 3600; + } + } + + private Logger getLogger() { + return Logger.getLogger(getClass().getName()); + } } diff --git a/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java b/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java index eef4e240ec..c9fe2563f9 100644 --- a/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java +++ b/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java @@ -157,4 +157,24 @@ public interface ClientConnector extends Connector, RpcTarget { * attached to any Root */ public Root getRoot(); + + /** + * Called before the shared state and RPC invocations are sent to the + * client. Gives the connector an opportunity to set computed/dynamic state + * values or to invoke last minute RPC methods depending on other component + * features. + * <p> + * This method must not alter the component hierarchy in any way. Calling + * requestRepaint() from this method will have no effect. + * </p> + * + * @param initial + * <code>true</code> if the client-side connector will be created + * and initialized after this method has been invoked. + * <code>false</code> if there is already an initialized + * client-side connector. + * + * @since 7.0 + */ + public void beforeClientResponse(boolean initial); } diff --git a/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java b/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java index bb96c6e53e..56d5ed1393 100644 --- a/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java +++ b/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java @@ -322,4 +322,9 @@ public class DragAndDropService implements VariableOwner, ClientConnector { public Root getRoot() { return null; } + + @Override + public void beforeClientResponse(boolean initial) { + // Nothing to do + } } diff --git a/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java index 60197b0b3a..884e01f9a5 100644 --- a/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java +++ b/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java @@ -165,6 +165,10 @@ public class JsonCodec implements Serializable { } else if (targetType == JSONObject.class || targetType == JSONArray.class) { return value; + } else if (Enum.class.isAssignableFrom(getClassForType(targetType))) { + Class<?> classForType = getClassForType(targetType); + return decodeEnum(classForType.asSubclass(Enum.class), + (String) value); } else { return decodeObject(targetType, (JSONObject) value, connectorTracker); @@ -420,9 +424,8 @@ public class JsonCodec implements Serializable { } } - private static Object decodeEnum(Class<? extends Enum> cls, JSONObject value) { - String enumIdentifier = String.valueOf(value); - return Enum.valueOf(cls, enumIdentifier); + private static Object decodeEnum(Class<? extends Enum> cls, String value) { + return Enum.valueOf(cls, value); } private static String[] decodeStringArray(JSONArray jsonArray) @@ -491,10 +494,6 @@ public class JsonCodec implements Serializable { throws JSONException { Class<?> targetClass = getClassForType(targetType); - if (Enum.class.isAssignableFrom(targetClass)) { - return decodeEnum(targetClass.asSubclass(Enum.class), - serializedObject); - } try { Object decodedObject = targetClass.newInstance(); @@ -527,9 +526,8 @@ public class JsonCodec implements Serializable { } } - public static Object encode(Object value, Object referenceValue, - Type valueType, ConnectorTracker connectorTracker) - throws JSONException { + public static Object encode(Object value, Object diffState, Type valueType, + ConnectorTracker connectorTracker) throws JSONException { if (valueType == null) { throw new IllegalArgumentException("type must be defined"); @@ -596,7 +594,7 @@ public class JsonCodec implements Serializable { } else { // Any object that we do not know how to encode we encode by looping // through fields - return encodeObject(value, referenceValue, connectorTracker); + return encodeObject(value, (JSONObject) diffState, connectorTracker); } } @@ -604,7 +602,7 @@ public class JsonCodec implements Serializable { return JSONObject.NULL; } - private static Object encodeObject(Object value, Object referenceValue, + private static Object encodeObject(Object value, JSONObject diffState, ConnectorTracker connectorTracker) throws JSONException { JSONObject jsonMap = new JSONObject(); @@ -621,10 +619,11 @@ public class JsonCodec implements Serializable { Type fieldType = getterMethod.getGenericReturnType(); Object fieldValue = getterMethod.invoke(value, (Object[]) null); boolean equals = false; - Object referenceFieldValue = null; - if (referenceValue != null) { - referenceFieldValue = getterMethod.invoke(referenceValue, - (Object[]) null); + Object diffStateValue = null; + if (diffState != null) { + diffStateValue = diffState.get(fieldName); + Object referenceFieldValue = decodeInternalOrCustomType( + fieldType, diffStateValue, connectorTracker); equals = equals(fieldValue, referenceFieldValue); } if (!equals) { @@ -638,8 +637,15 @@ public class JsonCodec implements Serializable { } jsonMap.put( fieldName, - encode(fieldValue, referenceFieldValue, fieldType, + encode(fieldValue, diffStateValue, fieldType, connectorTracker)); + if (diffState != null) { + diffState.put( + fieldName, + encode(fieldValue, null, fieldType, + connectorTracker)); + } + // } else { // System.out.println("Skipping field " + fieldName // + " of type " + fieldType.getName() diff --git a/server/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java b/server/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java deleted file mode 100644 index fc3fbd6c00..0000000000 --- a/server/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2011 Vaadin Ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.vaadin.terminal.gwt.server; - -import java.util.HashMap; -import java.util.Map; - -import com.vaadin.shared.ApplicationConstants; -import com.vaadin.shared.communication.MethodInvocation; - -public class LegacyChangeVariablesInvocation extends MethodInvocation { - private Map<String, Object> variableChanges = new HashMap<String, Object>(); - - public LegacyChangeVariablesInvocation(String connectorId, - String variableName, Object value) { - super(connectorId, ApplicationConstants.UPDATE_VARIABLE_INTERFACE, - ApplicationConstants.UPDATE_VARIABLE_METHOD); - setVariableChange(variableName, value); - } - - public static boolean isLegacyVariableChange(String interfaceName, - String methodName) { - return ApplicationConstants.UPDATE_VARIABLE_METHOD - .equals(interfaceName) - && ApplicationConstants.UPDATE_VARIABLE_METHOD - .equals(methodName); - } - - public void setVariableChange(String name, Object value) { - variableChanges.put(name, value); - } - - public Map<String, Object> getVariableChanges() { - return variableChanges; - } - -} diff --git a/server/src/com/vaadin/ui/AbsoluteLayout.java b/server/src/com/vaadin/ui/AbsoluteLayout.java index 9851a79bcd..a3bc577fe3 100644 --- a/server/src/com/vaadin/ui/AbsoluteLayout.java +++ b/server/src/com/vaadin/ui/AbsoluteLayout.java @@ -169,8 +169,8 @@ public class AbsoluteLayout extends AbstractLayout implements } @Override - public void updateState() { - super.updateState(); + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); // This could be in internalRemoveComponent and internalSetComponent if // Map<Connector,String> was supported. We cannot get the child diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java index fb3993d0cf..cde5217ca1 100644 --- a/server/src/com/vaadin/ui/AbstractComponent.java +++ b/server/src/com/vaadin/ui/AbstractComponent.java @@ -717,13 +717,9 @@ public abstract class AbstractComponent extends AbstractClientConnector return (ComponentState) super.getState(); } - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component#updateState() - */ @Override - public void updateState() { + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); // TODO This logic should be on the client side and the state should // simply be a data object with "width" and "height". if (getHeight() >= 0 diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java index 2d14acf442..67a1826100 100644 --- a/server/src/com/vaadin/ui/AbstractField.java +++ b/server/src/com/vaadin/ui/AbstractField.java @@ -1620,8 +1620,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements } @Override - public void updateState() { - super.updateState(); + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); // Hide the error indicator if needed getState().setHideErrors(shouldHideErrors()); diff --git a/server/src/com/vaadin/ui/AbstractTextField.java b/server/src/com/vaadin/ui/AbstractTextField.java index c8bbadd0ab..86315f801f 100644 --- a/server/src/com/vaadin/ui/AbstractTextField.java +++ b/server/src/com/vaadin/ui/AbstractTextField.java @@ -97,8 +97,8 @@ public abstract class AbstractTextField extends AbstractField<String> implements } @Override - public void updateState() { - super.updateState(); + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); String value = getValue(); if (value == null) { diff --git a/server/src/com/vaadin/ui/Component.java b/server/src/com/vaadin/ui/Component.java index ac668168f2..ff7ed47930 100644 --- a/server/src/com/vaadin/ui/Component.java +++ b/server/src/com/vaadin/ui/Component.java @@ -637,18 +637,6 @@ public interface Component extends ClientConnector, Sizeable, Serializable { public ComponentState getState(); /** - * Called before the shared state is sent to the client. Gives the component - * an opportunity to set computed/dynamic state values e.g. state values - * that depend on other component features. - * <p> - * This method must not alter the component hierarchy in any way. - * </p> - * - * @since 7.0 - */ - public void updateState(); - - /** * Adds an unique id for component that get's transferred to terminal for * testing purposes. Keeping identifiers unique is the responsibility of the * programmer. diff --git a/server/src/com/vaadin/ui/ConnectorTracker.java b/server/src/com/vaadin/ui/ConnectorTracker.java index 12ad377b62..2afe7f9025 100644 --- a/server/src/com/vaadin/ui/ConnectorTracker.java +++ b/server/src/com/vaadin/ui/ConnectorTracker.java @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -39,7 +40,8 @@ import com.vaadin.terminal.gwt.server.ClientConnector; * Tracks which {@link ClientConnector}s are dirty so they can be updated to the * client when the following response is sent. A connector is dirty when an * operation has been performed on it on the server and as a result of this - * operation new information needs to be sent to its {@link ServerConnector}. + * operation new information needs to be sent to its + * {@link com.vaadin.terminal.gwt.client.ServerConnector}. * </p> * * @author Vaadin Ltd @@ -50,8 +52,10 @@ public class ConnectorTracker implements Serializable { private final HashMap<String, ClientConnector> connectorIdToConnector = new HashMap<String, ClientConnector>(); private Set<ClientConnector> dirtyConnectors = new HashSet<ClientConnector>(); + private Set<ClientConnector> uninitializedConnectors = new HashSet<ClientConnector>(); private Root root; + private Map<ClientConnector, Object> diffStates = new HashMap<ClientConnector, Object>(); /** * Gets a logger for this class @@ -91,6 +95,7 @@ public class ConnectorTracker implements Serializable { .get(connectorId); if (previouslyRegistered == null) { connectorIdToConnector.put(connectorId, connector); + uninitializedConnectors.add(connector); getLogger().fine( "Registered " + connector.getClass().getSimpleName() + " (" + connectorId + ")"); @@ -136,6 +141,49 @@ public class ConnectorTracker implements Serializable { "Unregistered " + connector.getClass().getSimpleName() + " (" + connectorId + ")"); connectorIdToConnector.remove(connectorId); + uninitializedConnectors.remove(connector); + diffStates.remove(connector); + } + + /** + * Checks whether the given connector has already been initialized in the + * browser. The given connector should be registered with this connector + * tracker. + * + * @param connector + * the client connector to check + * @return <code>true</code> if the initial state has previously been sent + * to the browser, <code>false</code> if the client-side doesn't + * already know anything about the connector. + */ + public boolean isClientSideInitialized(ClientConnector connector) { + assert connectorIdToConnector.get(connector.getConnectorId()) == connector : "Connector should be registered with this ConnectorTracker"; + return !uninitializedConnectors.contains(connector); + } + + /** + * Marks the given connector as initialized, meaning that the client-side + * state has been initialized for the connector. + * + * @see #isClientSideInitialized(ClientConnector) + * + * @param connector + * the connector that should be marked as initialized + */ + public void markClientSideInitialized(ClientConnector connector) { + uninitializedConnectors.remove(connector); + } + + /** + * Marks all currently registered connectors as uninitialized. This should + * be done when the client-side has been reset but the server-side state is + * retained. + * + * @see #isClientSideInitialized(ClientConnector) + */ + public void markAllClientSidesUninitialized() { + uninitializedConnectors.addAll(connectorIdToConnector.values()); + diffStates.clear(); } /** @@ -175,6 +223,8 @@ public class ConnectorTracker implements Serializable { "cleanConnectorMap unregistered connector " + getConnectorAndParentInfo(connector) + "). This should have been done when the connector was detached."); + uninitializedConnectors.remove(connector); + diffStates.remove(connector); iterator.remove(); } } @@ -327,4 +377,12 @@ public class ConnectorTracker implements Serializable { return dirtyConnectors; } + public Object getDiffState(ClientConnector connector) { + return diffStates.get(connector); + } + + public void setDiffState(ClientConnector connector, Object diffState) { + diffStates.put(connector, diffState); + } + } diff --git a/server/src/com/vaadin/ui/CssLayout.java b/server/src/com/vaadin/ui/CssLayout.java index c43f347e68..0192debc4a 100644 --- a/server/src/com/vaadin/ui/CssLayout.java +++ b/server/src/com/vaadin/ui/CssLayout.java @@ -197,8 +197,8 @@ public class CssLayout extends AbstractLayout implements LayoutClickNotifier { } @Override - public void updateState() { - super.updateState(); + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); getState().getChildCss().clear(); for (Iterator<Component> ci = getComponentIterator(); ci.hasNext();) { Component child = ci.next(); diff --git a/server/src/com/vaadin/ui/Root.java b/server/src/com/vaadin/ui/Root.java index 685296c55a..b37005a16e 100644 --- a/server/src/com/vaadin/ui/Root.java +++ b/server/src/com/vaadin/ui/Root.java @@ -434,6 +434,13 @@ public abstract class Root extends AbstractComponentContainer implements public void click(MouseEventDetails mouseDetails) { fireEvent(new ClickEvent(Root.this, mouseDetails)); } + + @Override + public void resize(int viewWidth, int viewHeight, int windowWidth, + int windowHeight) { + // TODO We're not doing anything with the view dimensions + getPage().setBrowserWindowSize(windowWidth, windowHeight); + } }; /** @@ -582,12 +589,6 @@ public abstract class Root extends AbstractComponentContainer implements .get(RootConstants.FRAGMENT_VARIABLE); getPage().setFragment(fragment, true); } - - if (variables.containsKey("height") || variables.containsKey("width")) { - getPage().setBrowserWindowSize((Integer) variables.get("width"), - (Integer) variables.get("height")); - } - } /* diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java index 13ef7e5784..d1d2c25d8b 100644 --- a/server/src/com/vaadin/ui/Window.java +++ b/server/src/com/vaadin/ui/Window.java @@ -32,7 +32,6 @@ import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.event.ShortcutAction.ModifierKey; import com.vaadin.event.ShortcutListener; import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.root.RootConstants; import com.vaadin.shared.ui.window.WindowServerRpc; import com.vaadin.shared.ui.window.WindowState; import com.vaadin.terminal.PaintException; @@ -76,10 +75,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, } }; - private int browserWindowWidth = -1; - - private int browserWindowHeight = -1; - /** * Creates a new unnamed window with a default layout. */ @@ -170,20 +165,6 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier, .get("width") != getWidth())) { sizeHasChanged = true; } - Integer browserHeightVar = (Integer) variables - .get(RootConstants.BROWSER_HEIGHT_VAR); - if (browserHeightVar != null - && browserHeightVar.intValue() != browserWindowHeight) { - browserWindowHeight = browserHeightVar.intValue(); - sizeHasChanged = true; - } - Integer browserWidthVar = (Integer) variables - .get(RootConstants.BROWSER_WIDTH_VAR); - if (browserWidthVar != null - && browserWidthVar.intValue() != browserWindowWidth) { - browserWindowWidth = browserWidthVar.intValue(); - sizeHasChanged = true; - } super.changeVariables(source, variables); |