summaryrefslogtreecommitdiffstats
path: root/server/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/com')
-rw-r--r--server/src/com/vaadin/Application.java519
-rw-r--r--server/src/com/vaadin/UIRequiresMoreInformationException.java (renamed from server/src/com/vaadin/RootRequiresMoreInformationException.java)6
-rw-r--r--server/src/com/vaadin/annotations/EagerInit.java6
-rw-r--r--server/src/com/vaadin/annotations/Theme.java4
-rw-r--r--server/src/com/vaadin/annotations/Widgetset.java4
-rw-r--r--server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java4
-rw-r--r--server/src/com/vaadin/service/ApplicationContext.java6
-rw-r--r--server/src/com/vaadin/terminal/AbstractClientConnector.java36
-rw-r--r--server/src/com/vaadin/terminal/AbstractUIProvider.java (renamed from server/src/com/vaadin/terminal/AbstractRootProvider.java)8
-rw-r--r--server/src/com/vaadin/terminal/DefaultUIProvider.java (renamed from server/src/com/vaadin/terminal/DefaultRootProvider.java)26
-rw-r--r--server/src/com/vaadin/terminal/DeploymentConfiguration.java34
-rw-r--r--server/src/com/vaadin/terminal/Page.java84
-rw-r--r--server/src/com/vaadin/terminal/UIProvider.java (renamed from server/src/com/vaadin/terminal/RootProvider.java)14
-rw-r--r--server/src/com/vaadin/terminal/WrappedRequest.java11
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java59
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java31
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java261
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java53
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java4
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/BootstrapFragmentResponse.java9
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java80
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/BootstrapPageResponse.java8
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java47
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/ClientConnector.java10
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java2
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/CommunicationManager.java10
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/Constants.java11
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java4
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/EncodeResult.java48
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/JsonCodec.java151
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java51
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java10
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java31
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java4
-rw-r--r--server/src/com/vaadin/ui/AbstractComponent.java22
-rw-r--r--server/src/com/vaadin/ui/AbstractEmbedded.java84
-rw-r--r--server/src/com/vaadin/ui/Button.java4
-rw-r--r--server/src/com/vaadin/ui/Component.java16
-rw-r--r--server/src/com/vaadin/ui/ConnectorTracker.java51
-rw-r--r--server/src/com/vaadin/ui/EmbeddedBrowser.java19
-rw-r--r--server/src/com/vaadin/ui/Flash.java136
-rw-r--r--server/src/com/vaadin/ui/Image.java94
-rw-r--r--server/src/com/vaadin/ui/LoginForm.java4
-rw-r--r--server/src/com/vaadin/ui/Select.java14
-rw-r--r--server/src/com/vaadin/ui/Slider.java172
-rw-r--r--server/src/com/vaadin/ui/UI.java (renamed from server/src/com/vaadin/ui/Root.java)388
-rw-r--r--server/src/com/vaadin/ui/Window.java28
47 files changed, 1690 insertions, 988 deletions
diff --git a/server/src/com/vaadin/Application.java b/server/src/com/vaadin/Application.java
index d2924eb716..bdad94355d 100644
--- a/server/src/com/vaadin/Application.java
+++ b/server/src/com/vaadin/Application.java
@@ -31,6 +31,7 @@ import java.util.EventObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -51,14 +52,14 @@ import com.vaadin.data.util.converter.ConverterFactory;
import com.vaadin.data.util.converter.DefaultConverterFactory;
import com.vaadin.event.EventRouter;
import com.vaadin.service.ApplicationContext;
-import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.terminal.AbstractErrorMessage;
import com.vaadin.terminal.ApplicationResource;
import com.vaadin.terminal.CombinedRequest;
import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.RequestHandler;
-import com.vaadin.terminal.RootProvider;
import com.vaadin.terminal.Terminal;
+import com.vaadin.terminal.UIProvider;
import com.vaadin.terminal.VariableOwner;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.WrappedRequest.BrowserDetails;
@@ -74,8 +75,8 @@ import com.vaadin.terminal.gwt.server.WebApplicationContext;
import com.vaadin.tools.ReflectTools;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractField;
-import com.vaadin.ui.Root;
import com.vaadin.ui.Table;
+import com.vaadin.ui.UI;
import com.vaadin.ui.Window;
/**
@@ -134,9 +135,9 @@ public class Application implements Terminal.ErrorListener, Serializable {
/**
* The name of the parameter that is by default used in e.g. web.xml to
- * define the name of the default {@link Root} class.
+ * define the name of the default {@link UI} class.
*/
- public static final String ROOT_PARAMETER = "root";
+ public static final String UI_PARAMETER = "UI";
private static final Method BOOTSTRAP_FRAGMENT_METHOD = ReflectTools
.findMethod(BootstrapListener.class, "modifyBootstrapFragment",
@@ -164,19 +165,19 @@ public class Application implements Terminal.ErrorListener, Serializable {
private static final Pattern WINDOW_NAME_PATTERN = Pattern
.compile("^/?([^/]+).*");
- private Root.LegacyWindow mainWindow;
+ private UI.LegacyWindow mainWindow;
private String theme;
- private Map<String, Root.LegacyWindow> legacyRootNames = new HashMap<String, Root.LegacyWindow>();
+ private Map<String, UI.LegacyWindow> legacyUINames = new HashMap<String, UI.LegacyWindow>();
/**
* Sets the main window of this application. Setting window as a main
* window of this application also adds the window to this application.
*
* @param mainWindow
- * the root to set as the default window
+ * the UI to set as the default window
*/
- public void setMainWindow(Root.LegacyWindow mainWindow) {
+ public void setMainWindow(UI.LegacyWindow mainWindow) {
if (this.mainWindow != null) {
throw new IllegalStateException(
"mainWindow has already been set");
@@ -201,9 +202,9 @@ public class Application implements Terminal.ErrorListener, Serializable {
* Note that each application must have at least one main window.
* </p>
*
- * @return the root used as the default window
+ * @return the UI used as the default window
*/
- public Root.LegacyWindow getMainWindow() {
+ public UI.LegacyWindow getMainWindow() {
return mainWindow;
}
@@ -215,11 +216,11 @@ public class Application implements Terminal.ErrorListener, Serializable {
* {@inheritDoc}
*
* @see #getWindow(String)
- * @see Application#getRoot(WrappedRequest)
+ * @see Application#getUI(WrappedRequest)
*/
@Override
- public Root.LegacyWindow getRoot(WrappedRequest request) {
+ public UI.LegacyWindow getUI(WrappedRequest request) {
String pathInfo = request.getRequestPathInfo();
String name = null;
if (pathInfo != null && pathInfo.length() > 0) {
@@ -229,7 +230,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
name = matcher.group(1);
}
}
- Root.LegacyWindow window = getWindow(name);
+ UI.LegacyWindow window = getWindow(name);
if (window != null) {
return window;
}
@@ -239,8 +240,8 @@ public class Application implements Terminal.ErrorListener, Serializable {
/**
* Sets the application's theme.
* <p>
- * Note that this theme can be overridden for a specific root with
- * {@link Application#getThemeForRoot(Root)}. Setting theme to be
+ * Note that this theme can be overridden for a specific UI with
+ * {@link Application#getThemeForUI(UI)}. Setting theme to be
* <code>null</code> selects the default theme. For the available theme
* names, see the contents of the VAADIN/themes directory.
* </p>
@@ -254,7 +255,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
/**
* Gets the application's theme. The application's theme is the default
- * theme used by all the roots for which a theme is not explicitly
+ * theme used by all the uIs for which a theme is not explicitly
* defined. If the application theme is not explicitly set,
* <code>null</code> is returned.
*
@@ -272,70 +273,70 @@ public class Application implements Terminal.ErrorListener, Serializable {
*/
@Override
- public String getThemeForRoot(Root root) {
+ public String getThemeForUI(UI uI) {
return theme;
}
/**
* <p>
- * Gets a root by name. Returns <code>null</code> if the application is
+ * Gets a UI by name. Returns <code>null</code> if the application is
* not running or it does not contain a window corresponding to the
* name.
* </p>
*
* @param name
* the name of the requested window
- * @return a root corresponding to the name, or <code>null</code> to use
+ * @return a UI corresponding to the name, or <code>null</code> to use
* the default window
*/
- public Root.LegacyWindow getWindow(String name) {
- return legacyRootNames.get(name);
+ public UI.LegacyWindow getWindow(String name) {
+ return legacyUINames.get(name);
}
/**
* Counter to get unique names for windows with no explicit name
*/
- private int namelessRootIndex = 0;
+ private int namelessUIIndex = 0;
/**
* Adds a new browser level window to this application. Please note that
- * Root doesn't have a name that is used in the URL - to add a named
- * window you should instead use {@link #addWindow(Root, String)}
+ * UI doesn't have a name that is used in the URL - to add a named
+ * window you should instead use {@link #addWindow(UI, String)}
*
- * @param root
- * the root window to add to the application
+ * @param uI
+ * the UI window to add to the application
* @return returns the name that has been assigned to the window
*
- * @see #addWindow(Root, String)
+ * @see #addWindow(UI, String)
*/
- public void addWindow(Root.LegacyWindow root) {
- if (root.getName() == null) {
- String name = Integer.toString(namelessRootIndex++);
- root.setName(name);
+ public void addWindow(UI.LegacyWindow uI) {
+ if (uI.getName() == null) {
+ String name = Integer.toString(namelessUIIndex++);
+ uI.setName(name);
}
- legacyRootNames.put(root.getName(), root);
- root.setApplication(this);
+ legacyUINames.put(uI.getName(), uI);
+ uI.setApplication(this);
}
/**
* Removes the specified window from the application. This also removes
- * all name mappings for the window (see
- * {@link #addWindow(Root, String) and #getWindowName(Root)}.
+ * all name mappings for the window (see {@link #addWindow(UI, String)
+ * and #getWindowName(UI)}.
*
* <p>
* Note that removing window from the application does not close the
* browser window - the window is only removed from the server-side.
* </p>
*
- * @param root
- * the root to remove
+ * @param uI
+ * the UI to remove
*/
- public void removeWindow(Root.LegacyWindow root) {
- for (Entry<String, Root.LegacyWindow> entry : legacyRootNames
+ public void removeWindow(UI.LegacyWindow uI) {
+ for (Entry<String, UI.LegacyWindow> entry : legacyUINames
.entrySet()) {
- if (entry.getValue() == root) {
- legacyRootNames.remove(entry.getKey());
+ if (entry.getValue() == uI) {
+ legacyUINames.remove(entry.getKey());
}
}
}
@@ -349,8 +350,8 @@ public class Application implements Terminal.ErrorListener, Serializable {
*
* @return the unmodifiable collection of windows.
*/
- public Collection<Root.LegacyWindow> getWindows() {
- return Collections.unmodifiableCollection(legacyRootNames.values());
+ public Collection<UI.LegacyWindow> getWindows() {
+ return Collections.unmodifiableCollection(legacyUINames.values());
}
}
@@ -489,23 +490,23 @@ public class Application implements Terminal.ErrorListener, Serializable {
private LinkedList<RequestHandler> requestHandlers = new LinkedList<RequestHandler>();
- private int nextRootId = 0;
- private Map<Integer, Root> roots = new HashMap<Integer, Root>();
+ private int nextUIId = 0;
+ private Map<Integer, UI> uIs = new HashMap<Integer, UI>();
- private final Map<String, Integer> retainOnRefreshRoots = new HashMap<String, Integer>();
+ private final Map<String, Integer> retainOnRefreshUIs = new HashMap<String, Integer>();
private final EventRouter eventRouter = new EventRouter();
/**
- * Keeps track of which roots have been inited.
+ * Keeps track of which uIs have been inited.
* <p>
* TODO Investigate whether this might be derived from the different states
- * in getRootForRrequest.
+ * in getUIForRrequest.
* </p>
*/
- private Set<Integer> initedRoots = new HashSet<Integer>();
+ private Set<Integer> initedUIs = new HashSet<Integer>();
- private List<RootProvider> rootProviders = new LinkedList<RootProvider>();
+ private List<UIProvider> uiProviders = new LinkedList<UIProvider>();
/**
* Gets the user of the application.
@@ -579,19 +580,19 @@ public class Application implements Terminal.ErrorListener, Serializable {
/**
* Ends the Application.
- *
* <p>
* In effect this will cause the application stop returning any windows when
- * asked. When the application is closed, its state is removed from the
- * session and the browser window is redirected to the application logout
- * url set with {@link #setLogoutURL(String)}. If the logout url has not
- * been set, the browser window is reloaded and the application is
- * restarted.
- * </p>
- * .
+ * asked. When the application is closed, close events are fired for its
+ * UIs, its state is removed from the session, and the browser window is
+ * redirected to the application logout url set with
+ * {@link #setLogoutURL(String)}. If the logout url has not been set, the
+ * browser window is reloaded and the application is restarted.
*/
public void close() {
applicationIsRunning = false;
+ for (UI ui : getUIs()) {
+ ui.fireCloseEvent();
+ }
}
/**
@@ -1830,110 +1831,108 @@ public class Application implements Terminal.ErrorListener, Serializable {
}
/**
- * Gets a root for a request for which no root is already known. This method
- * is called when the framework processes a request that does not originate
- * from an existing root instance. This typically happens when a host page
- * is requested.
+ * Gets a UI for a request for which no UI is already known. This method is
+ * called when the framework processes a request that does not originate
+ * from an existing UI instance. This typically happens when a host page is
+ * requested.
*
* <p>
* Subclasses of Application may override this method to provide custom
- * logic for choosing how to create a suitable root or for picking an
- * already created root. If an existing root is picked, care should be taken
- * to avoid keeping the same root open in multiple browser windows, as that
- * will cause the states to go out of sync.
+ * logic for choosing how to create a suitable UI or for picking an already
+ * created UI. If an existing UI is picked, care should be taken to avoid
+ * keeping the same UI open in multiple browser windows, as that will cause
+ * the states to go out of sync.
* </p>
*
* <p>
- * If {@link BrowserDetails} are required to create a Root, the
- * implementation can throw a {@link RootRequiresMoreInformationException}
- * exception. In this case, the framework will instruct the browser to send
- * the additional details, whereupon this method is invoked again with the
- * browser details present in the wrapped request. Throwing the exception if
- * the browser details are already available is not supported.
+ * If {@link BrowserDetails} are required to create a UI, the implementation
+ * can throw a {@link UIRequiresMoreInformationException} exception. In this
+ * case, the framework will instruct the browser to send the additional
+ * details, whereupon this method is invoked again with the browser details
+ * present in the wrapped request. Throwing the exception if the browser
+ * details are already available is not supported.
* </p>
*
* <p>
* The default implementation in {@link Application} creates a new instance
- * of the Root class returned by {@link #getRootClassName(WrappedRequest)},
- * which in turn uses the {@value #ROOT_PARAMETER} parameter from web.xml.
- * If {@link DeploymentConfiguration#getClassLoader()} for the request
- * returns a {@link ClassLoader}, it is used for loading the Root class.
- * Otherwise the {@link ClassLoader} used to load this class is used.
+ * of the UI class returned by {@link #getUIClassName(WrappedRequest)},
+ * which in turn uses the {@value #UI_PARAMETER} parameter from web.xml. If
+ * {@link DeploymentConfiguration#getClassLoader()} for the request returns
+ * a {@link ClassLoader}, it is used for loading the UI class. Otherwise the
+ * {@link ClassLoader} used to load this class is used.
* </p>
*
* @param request
- * the wrapped request for which a root is needed
- * @return a root instance to use for the request
- * @throws RootRequiresMoreInformationException
+ * the wrapped request for which a UI is needed
+ * @return a UI instance to use for the request
+ * @throws UIRequiresMoreInformationException
* may be thrown by an implementation to indicate that
- * {@link BrowserDetails} are required to create a root
+ * {@link BrowserDetails} are required to create a UI
*
- * @see #getRootClassName(WrappedRequest)
- * @see Root
- * @see RootRequiresMoreInformationException
+ * @see #getUIClassName(WrappedRequest)
+ * @see UI
+ * @see UIRequiresMoreInformationException
* @see WrappedRequest#getBrowserDetails()
*
* @since 7.0
*/
- protected Root getRoot(WrappedRequest request)
- throws RootRequiresMoreInformationException {
+ protected UI getUI(WrappedRequest request)
+ throws UIRequiresMoreInformationException {
// Iterate in reverse order - test check newest provider first
- for (int i = rootProviders.size() - 1; i >= 0; i--) {
- RootProvider provider = rootProviders.get(i);
+ for (int i = uiProviders.size() - 1; i >= 0; i--) {
+ UIProvider provider = uiProviders.get(i);
- Class<? extends Root> rootClass = provider.getRootClass(this,
- request);
+ Class<? extends UI> uiClass = provider.getUIClass(this, request);
- if (rootClass != null) {
- return provider.instantiateRoot(this, rootClass, request);
+ if (uiClass != null) {
+ return provider.instantiateUI(this, uiClass, request);
}
}
throw new RuntimeException(
- "No root providers available or providers are not able to find root instance");
+ "No UI providers available or providers are not able to find UI instance");
}
/**
- * Finds the theme to use for a specific root. If no specific theme is
+ * Finds the theme to use for a specific UI. If no specific theme is
* required, <code>null</code> is returned.
*
* TODO Tell what the default implementation does once it does something.
*
- * @param root
- * the root to get a theme for
+ * @param uI
+ * the UI to get a theme for
* @return the name of the theme, or <code>null</code> if the default theme
* should be used
*
* @since 7.0
*/
- public String getThemeForRoot(Root root) {
- Theme rootTheme = getAnnotationFor(root.getClass(), Theme.class);
- if (rootTheme != null) {
- return rootTheme.value();
+ public String getThemeForUI(UI uI) {
+ Theme uiTheme = getAnnotationFor(uI.getClass(), Theme.class);
+ if (uiTheme != null) {
+ return uiTheme.value();
} else {
return null;
}
}
/**
- * Finds the widgetset to use for a specific root. If no specific widgetset
- * is required, <code>null</code> is returned.
+ * Finds the widgetset to use for a specific UI. If no specific widgetset is
+ * required, <code>null</code> is returned.
*
* TODO Tell what the default implementation does once it does something.
*
- * @param root
- * the root to get a widgetset for
+ * @param uI
+ * the UI to get a widgetset for
* @return the name of the widgetset, or <code>null</code> if the default
* widgetset should be used
*
* @since 7.0
*/
- public String getWidgetsetForRoot(Root root) {
- Widgetset rootWidgetset = getAnnotationFor(root.getClass(),
- Widgetset.class);
- if (rootWidgetset != null) {
- return rootWidgetset.value();
+ public String getWidgetsetForUI(UI uI) {
+ Widgetset uiWidgetset = getAnnotationFor(uI.getClass(), Widgetset.class);
+ if (uiWidgetset != null) {
+ return uiWidgetset.value();
} else {
return null;
}
@@ -2087,7 +2086,7 @@ public class Application implements Terminal.ErrorListener, Serializable {
*/
private static final ThreadLocal<Application> currentApplication = new ThreadLocal<Application>();
- private boolean rootPreserved = false;
+ private boolean uiPreserved = false;
/**
* Gets the currently used application. The current application is
@@ -2139,144 +2138,140 @@ public class Application implements Terminal.ErrorListener, Serializable {
return configuration.isProductionMode();
}
- public void addRootProvider(RootProvider rootProvider) {
- rootProviders.add(rootProvider);
+ public void addUIProvider(UIProvider uIProvider) {
+ uiProviders.add(uIProvider);
}
- public void removeRootProvider(RootProvider rootProvider) {
- rootProviders.remove(rootProvider);
+ public void removeUIProvider(UIProvider uIProvider) {
+ uiProviders.remove(uIProvider);
}
/**
- * Finds the {@link Root} to which a particular request belongs. If the
- * request originates from an existing Root, that root is returned. In other
- * cases, the method attempts to create and initialize a new root and might
- * throw a {@link RootRequiresMoreInformationException} if all required
+ * Finds the {@link UI} to which a particular request belongs. If the
+ * request originates from an existing UI, that UI is returned. In other
+ * cases, the method attempts to create and initialize a new UI and might
+ * throw a {@link UIRequiresMoreInformationException} if all required
* information is not available.
* <p>
* Please note that this method can also return a newly created
- * <code>Root</code> which has not yet been initialized. You can use
- * {@link #isRootInitPending(int)} with the root's id (
- * {@link Root#getRootId()} to check whether the initialization is still
- * pending.
+ * <code>UI</code> which has not yet been initialized. You can use
+ * {@link #isUIInitPending(int)} with the UI's id ( {@link UI#getUIId()} to
+ * check whether the initialization is still pending.
* </p>
*
* @param request
- * the request for which a root is desired
- * @return a root belonging to the request
- * @throws RootRequiresMoreInformationException
- * if no existing root could be found and creating a new root
+ * the request for which a UI is desired
+ * @return a UI belonging to the request
+ * @throws UIRequiresMoreInformationException
+ * if no existing UI could be found and creating a new UI
* requires additional information from the browser
*
- * @see #getRoot(WrappedRequest)
- * @see RootRequiresMoreInformationException
+ * @see #getUI(WrappedRequest)
+ * @see UIRequiresMoreInformationException
*
* @since 7.0
*/
- public Root getRootForRequest(WrappedRequest request)
- throws RootRequiresMoreInformationException {
- Root root = Root.getCurrent();
- if (root != null) {
- return root;
+ public UI getUIForRequest(WrappedRequest request)
+ throws UIRequiresMoreInformationException {
+ UI uI = UI.getCurrent();
+ if (uI != null) {
+ return uI;
}
- Integer rootId = getRootId(request);
+ Integer uiId = getUIId(request);
synchronized (this) {
BrowserDetails browserDetails = request.getBrowserDetails();
boolean hasBrowserDetails = browserDetails != null
&& browserDetails.getUriFragment() != null;
- root = roots.get(rootId);
+ uI = uIs.get(uiId);
- if (root == null && isRootPreserved()) {
- // Check for a known root
- if (!retainOnRefreshRoots.isEmpty()) {
+ if (uI == null && isUiPreserved()) {
+ // Check for a known UI
+ if (!retainOnRefreshUIs.isEmpty()) {
- Integer retainedRootId;
+ Integer retainedUIId;
if (!hasBrowserDetails) {
- throw new RootRequiresMoreInformationException();
+ throw new UIRequiresMoreInformationException();
} else {
String windowName = browserDetails.getWindowName();
- retainedRootId = retainOnRefreshRoots.get(windowName);
+ retainedUIId = retainOnRefreshUIs.get(windowName);
}
- if (retainedRootId != null) {
- rootId = retainedRootId;
- root = roots.get(rootId);
+ if (retainedUIId != null) {
+ uiId = retainedUIId;
+ uI = uIs.get(uiId);
}
}
}
- if (root == null) {
- // Throws exception if root can not yet be created
- root = getRoot(request);
+ if (uI == null) {
+ // Throws exception if UI can not yet be created
+ uI = getUI(request);
- // Initialize some fields for a newly created root
- if (root.getApplication() == null) {
- root.setApplication(this);
+ // Initialize some fields for a newly created UI
+ if (uI.getApplication() == null) {
+ uI.setApplication(this);
}
- if (root.getRootId() < 0) {
+ if (uI.getUIId() < 0) {
- if (rootId == null) {
+ if (uiId == null) {
// Get the next id if none defined
- rootId = Integer.valueOf(nextRootId++);
+ uiId = Integer.valueOf(nextUIId++);
}
- root.setRootId(rootId.intValue());
- roots.put(rootId, root);
+ uI.setUIId(uiId.intValue());
+ uIs.put(uiId, uI);
}
}
// Set thread local here so it is available in init
- Root.setCurrent(root);
+ UI.setCurrent(uI);
- if (!initedRoots.contains(rootId)) {
- boolean initRequiresBrowserDetails = isRootPreserved()
- || !root.getClass()
- .isAnnotationPresent(EagerInit.class);
+ if (!initedUIs.contains(uiId)) {
+ boolean initRequiresBrowserDetails = isUiPreserved()
+ || !uI.getClass().isAnnotationPresent(EagerInit.class);
if (!initRequiresBrowserDetails || hasBrowserDetails) {
- root.doInit(request);
+ uI.doInit(request);
- // Remember that this root has been initialized
- initedRoots.add(rootId);
+ // Remember that this UI has been initialized
+ initedUIs.add(uiId);
// init() might turn on preserve so do this afterwards
- if (isRootPreserved()) {
- // Remember this root
+ if (isUiPreserved()) {
+ // Remember this UI
String windowName = request.getBrowserDetails()
.getWindowName();
- retainOnRefreshRoots.put(windowName, rootId);
+ retainOnRefreshUIs.put(windowName, uiId);
}
}
}
} // end synchronized block
- return root;
+ return uI;
}
/**
- * Internal helper to finds the root id for a request.
+ * Internal helper to finds the UI id for a request.
*
* @param request
- * the request to get the root id for
- * @return a root id, or <code>null</code> if no root id is defined
+ * the request to get the UI id for
+ * @return a UI id, or <code>null</code> if no UI id is defined
*
* @since 7.0
*/
- private static Integer getRootId(WrappedRequest request) {
+ private static Integer getUIId(WrappedRequest request) {
if (request instanceof CombinedRequest) {
- // Combined requests has the rootid parameter in the second request
+ // Combined requests has the uiId parameter in the second request
CombinedRequest combinedRequest = (CombinedRequest) request;
request = combinedRequest.getSecondRequest();
}
- String rootIdString = request
- .getParameter(ApplicationConstants.ROOT_ID_PARAMETER);
- Integer rootId = rootIdString == null ? null
- : new Integer(rootIdString);
- return rootId;
+ String uiIdString = request.getParameter(UIConstants.UI_ID_PARAMETER);
+ Integer uiId = uiIdString == null ? null : new Integer(uiIdString);
+ return uiId;
}
/**
- * Sets whether the same Root state should be reused if the framework can
+ * Sets whether the same UI state should be reused if the framework can
* detect that the application is opened in a browser window where it has
* previously been open. The framework attempts to discover this by checking
* the value of window.name in the browser.
@@ -2285,62 +2280,62 @@ public class Application implements Terminal.ErrorListener, Serializable {
* the UI is already shown, as it might not be retained as intended.
* </p>
*
- * @param rootPreserved
- * <code>true</code>if the same Root instance should be reused
- * e.g. when the browser window is refreshed.
+ * @param uiPreserved
+ * <code>true</code>if the same UI instance should be reused e.g.
+ * when the browser window is refreshed.
*/
- public void setRootPreserved(boolean rootPreserved) {
- this.rootPreserved = rootPreserved;
- if (!rootPreserved) {
- retainOnRefreshRoots.clear();
+ public void setUiPreserved(boolean uiPreserved) {
+ this.uiPreserved = uiPreserved;
+ if (!uiPreserved) {
+ retainOnRefreshUIs.clear();
}
}
/**
- * Checks whether the same Root state should be reused if the framework can
+ * Checks whether the same UI state should be reused if the framework can
* detect that the application is opened in a browser window where it has
* previously been open. The framework attempts to discover this by checking
* the value of window.name in the browser.
*
- * @return <code>true</code>if the same Root instance should be reused e.g.
+ * @return <code>true</code>if the same UI instance should be reused e.g.
* when the browser window is refreshed.
*/
- public boolean isRootPreserved() {
- return rootPreserved;
+ public boolean isUiPreserved() {
+ return uiPreserved;
}
/**
- * Checks whether there's a pending initialization for the root with the
- * given id.
+ * Checks whether there's a pending initialization for the UI with the given
+ * id.
*
- * @param rootId
- * root id to check for
+ * @param uiId
+ * UI id to check for
* @return <code>true</code> of the initialization is pending,
- * <code>false</code> if the root id is not registered or if the
- * root has already been initialized
+ * <code>false</code> if the UI id is not registered or if the UI
+ * has already been initialized
*
- * @see #getRootForRequest(WrappedRequest)
+ * @see #getUIForRequest(WrappedRequest)
*/
- public boolean isRootInitPending(int rootId) {
- return !initedRoots.contains(Integer.valueOf(rootId));
+ public boolean isUIInitPending(int uiId) {
+ return !initedUIs.contains(Integer.valueOf(uiId));
}
/**
- * Gets all the roots of this application. This includes roots that have
- * been requested but not yet initialized. Please note, that roots are not
+ * Gets all the uIs of this application. This includes uIs that have been
+ * requested but not yet initialized. Please note, that uIs are not
* automatically removed e.g. if the browser window is closed and that there
- * is no way to manually remove a root. Inactive roots will thus not be
- * released for GC until the entire application is released when the session
- * has timed out (unless there are dangling references). Improved support
- * for releasing unused roots is planned for an upcoming alpha release of
- * Vaadin 7.
+ * is no way to manually remove a UI. Inactive uIs will thus not be released
+ * for GC until the entire application is released when the session has
+ * timed out (unless there are dangling references). Improved support for
+ * releasing unused uIs is planned for an upcoming alpha release of Vaadin
+ * 7.
*
- * @return a collection of roots belonging to this application
+ * @return a collection of uIs belonging to this application
*
* @since 7.0
*/
- public Collection<Root> getRoots() {
- return Collections.unmodifiableCollection(roots.values());
+ public Collection<UI> getUIs() {
+ return Collections.unmodifiableCollection(uIs.values());
}
private int connectorIdSequence = 0;
@@ -2362,17 +2357,17 @@ public class Application implements Terminal.ErrorListener, Serializable {
}
/**
- * Returns a Root with the given id.
+ * Returns a UI with the given id.
* <p>
* This is meant for framework internal use.
* </p>
*
- * @param rootId
- * The root id
- * @return The root with the given id or null if not found
+ * @param uiId
+ * The UI id
+ * @return The UI with the given id or null if not found
*/
- public Root getRootById(int rootId) {
- return roots.get(rootId);
+ public UI getUIById(int uiId) {
+ return uIs.get(uiId);
}
/**
@@ -2421,4 +2416,98 @@ public class Application implements Terminal.ErrorListener, Serializable {
public void modifyBootstrapResponse(BootstrapResponse response) {
eventRouter.fireEvent(response);
}
+
+ /**
+ * Removes all those UIs from the application for which {@link #isUIAlive}
+ * returns false. Close events are fired for the removed UIs.
+ * <p>
+ * Called by the framework at the end of every request.
+ *
+ * @see UI.CloseEvent
+ * @see UI.CloseListener
+ * @see #isUIAlive(UI)
+ *
+ * @since 7.0.0
+ */
+ public void closeInactiveUIs() {
+ for (Iterator<UI> i = uIs.values().iterator(); i.hasNext();) {
+ UI ui = i.next();
+ if (!isUIAlive(ui)) {
+ i.remove();
+ retainOnRefreshUIs.values().remove(ui.getUIId());
+ ui.fireCloseEvent();
+ getLogger().info(
+ "Closed UI #" + ui.getUIId() + " due to inactivity");
+ }
+ }
+ }
+
+ /**
+ * Returns the number of seconds that must pass without a valid heartbeat or
+ * UIDL request being received from a UI before that UI is removed from the
+ * application. This is a lower bound; it might take longer to close an
+ * inactive UI. Returns a negative number if heartbeat is disabled and
+ * timeout never occurs.
+ *
+ * @see #getUidlRequestTimeout()
+ * @see #closeInactiveUIs()
+ * @see DeploymentConfiguration#getHeartbeatInterval()
+ *
+ * @since 7.0.0
+ *
+ * @return The heartbeat timeout in seconds or a negative number if timeout
+ * never occurs.
+ */
+ protected int getHeartbeatTimeout() {
+ // Permit three missed heartbeats before closing the UI
+ return (int) (configuration.getHeartbeatInterval() * (3.1));
+ }
+
+ /**
+ * Returns the number of seconds that must pass without a valid UIDL request
+ * being received from a UI before the UI is removed from the application,
+ * even though heartbeat requests are received. This is a lower bound; it
+ * might take longer to close an inactive UI. Returns a negative number if
+ * <p>
+ * This timeout only has effect if cleanup of inactive UIs is enabled;
+ * otherwise heartbeat requests are enough to extend UI lifetime
+ * indefinitely.
+ *
+ * @see DeploymentConfiguration#isIdleUICleanupEnabled()
+ * @see #getHeartbeatTimeout()
+ * @see #closeInactiveUIs()
+ *
+ * @since 7.0.0
+ *
+ * @return The UIDL request timeout in seconds, or a negative number if
+ * timeout never occurs.
+ */
+ protected int getUidlRequestTimeout() {
+ return configuration.isIdleUICleanupEnabled() ? getContext()
+ .getMaxInactiveInterval() : -1;
+ }
+
+ /**
+ * Returns whether the given UI is alive (the client-side actively
+ * communicates with the server) or whether it can be removed from the
+ * application and eventually collected.
+ *
+ * @since 7.0.0
+ *
+ * @param ui
+ * The UI whose status to check
+ * @return true if the UI is alive, false if it could be removed.
+ */
+ protected boolean isUIAlive(UI ui) {
+ long now = System.currentTimeMillis();
+ if (getHeartbeatTimeout() >= 0
+ && now - ui.getLastHeartbeatTime() > 1000 * getHeartbeatTimeout()) {
+ return false;
+ }
+ if (getUidlRequestTimeout() >= 0
+ && now - ui.getLastUidlRequestTime() > 1000 * getUidlRequestTimeout()) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/server/src/com/vaadin/RootRequiresMoreInformationException.java b/server/src/com/vaadin/UIRequiresMoreInformationException.java
index 74026dd161..493c31acb6 100644
--- a/server/src/com/vaadin/RootRequiresMoreInformationException.java
+++ b/server/src/com/vaadin/UIRequiresMoreInformationException.java
@@ -20,18 +20,18 @@ import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.WrappedRequest.BrowserDetails;
/**
- * Exception that is thrown to indicate that creating or initializing the root
+ * Exception that is thrown to indicate that creating or initializing the UI
* requires information detailed from the web browser ({@link BrowserDetails})
* to be present.
*
* This exception may not be thrown if that information is already present in
* the current WrappedRequest.
*
- * @see Application#getRoot(WrappedRequest)
+ * @see Application#getUI(WrappedRequest)
* @see WrappedRequest#getBrowserDetails()
*
* @since 7.0
*/
-public class RootRequiresMoreInformationException extends Exception {
+public class UIRequiresMoreInformationException extends Exception {
// Nothing of interest here
}
diff --git a/server/src/com/vaadin/annotations/EagerInit.java b/server/src/com/vaadin/annotations/EagerInit.java
index 5131a79576..462c6bb5ac 100644
--- a/server/src/com/vaadin/annotations/EagerInit.java
+++ b/server/src/com/vaadin/annotations/EagerInit.java
@@ -21,15 +21,15 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.vaadin.terminal.WrappedRequest;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
- * Indicates that the init method in a Root class can be called before full
+ * Indicates that the init method in a UI class can be called before full
* browser details ({@link WrappedRequest#getBrowserDetails()}) are available.
* This will make the UI appear more quickly, as ensuring the availability of
* this information typically requires an additional round trip to the client.
*
- * @see Root#init(com.vaadin.terminal.WrappedRequest)
+ * @see UI#init(com.vaadin.terminal.WrappedRequest)
* @see WrappedRequest#getBrowserDetails()
*
* @since 7.0
diff --git a/server/src/com/vaadin/annotations/Theme.java b/server/src/com/vaadin/annotations/Theme.java
index e2610d2b3f..052bc245fd 100644
--- a/server/src/com/vaadin/annotations/Theme.java
+++ b/server/src/com/vaadin/annotations/Theme.java
@@ -21,10 +21,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
- * Defines a specific theme for a {@link Root}.
+ * Defines a specific theme for a {@link UI}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
diff --git a/server/src/com/vaadin/annotations/Widgetset.java b/server/src/com/vaadin/annotations/Widgetset.java
index e80f887691..69e3e19319 100644
--- a/server/src/com/vaadin/annotations/Widgetset.java
+++ b/server/src/com/vaadin/annotations/Widgetset.java
@@ -21,10 +21,10 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
- * Defines a specific theme for a {@link Root}.
+ * Defines a specific theme for a {@link UI}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
diff --git a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
index f772e2701c..13248f1e06 100644
--- a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
+++ b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
@@ -551,9 +551,7 @@ public class SQLContainer implements Container, Container.Filterable,
@Override
public void removeContainerFilter(Filter filter) {
filters.remove(filter);
- // TODO this cannot be added before ComboBox is fixed
- // (Select.requestRepaint() must not affect filter string)
- // refresh();
+ refresh();
}
/**
diff --git a/server/src/com/vaadin/service/ApplicationContext.java b/server/src/com/vaadin/service/ApplicationContext.java
index c6116d6e73..55495dcd5c 100644
--- a/server/src/com/vaadin/service/ApplicationContext.java
+++ b/server/src/com/vaadin/service/ApplicationContext.java
@@ -80,6 +80,12 @@ public interface ApplicationContext extends Serializable {
public void removeTransactionListener(TransactionListener listener);
/**
+ * Returns the time between requests, in seconds, before this context is
+ * invalidated. A negative time indicates the context should never timeout.
+ */
+ public int getMaxInactiveInterval();
+
+ /**
* Generate a URL that can be used as the relative location of e.g. an
* {@link ApplicationResource}.
*
diff --git a/server/src/com/vaadin/terminal/AbstractClientConnector.java b/server/src/com/vaadin/terminal/AbstractClientConnector.java
index d2490225fb..157bd17e41 100644
--- a/server/src/com/vaadin/terminal/AbstractClientConnector.java
+++ b/server/src/com/vaadin/terminal/AbstractClientConnector.java
@@ -43,7 +43,7 @@ import com.vaadin.terminal.gwt.server.RpcManager;
import com.vaadin.terminal.gwt.server.RpcTarget;
import com.vaadin.terminal.gwt.server.ServerRpcManager;
import com.vaadin.ui.HasComponents;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
* An abstract base class for ClientConnector implementations. This class
@@ -94,9 +94,9 @@ public abstract class AbstractClientConnector implements ClientConnector {
/* Documentation copied from interface */
@Override
public void markAsDirty() {
- Root root = getRoot();
- if (root != null) {
- root.getConnectorTracker().markDirty(this);
+ UI uI = getUI();
+ if (uI != null) {
+ uI.getConnectorTracker().markDirty(this);
}
}
@@ -154,8 +154,8 @@ public abstract class AbstractClientConnector implements ClientConnector {
sharedState = createState();
}
- Root root = getRoot();
- if (root != null && !root.getConnectorTracker().isDirty(this)) {
+ UI uI = getUI();
+ if (uI != null && !uI.getConnectorTracker().isDirty(this)) {
requestRepaint();
}
@@ -363,28 +363,28 @@ public abstract class AbstractClientConnector implements ClientConnector {
* @return The connector's application, or <code>null</code> if not attached
*/
protected Application getApplication() {
- Root root = getRoot();
- if (root == null) {
+ UI uI = getUI();
+ if (uI == null) {
return null;
} else {
- return root.getApplication();
+ return uI.getApplication();
}
}
/**
- * Finds a Root ancestor of this connector. <code>null</code> is returned if
- * no Root ancestor is found (typically because the connector is not
+ * Finds a UI ancestor of this connector. <code>null</code> is returned if
+ * no UI ancestor is found (typically because the connector is not
* attached to a proper hierarchy).
*
- * @return the Root ancestor of this connector, or <code>null</code> if none
+ * @return the UI ancestor of this connector, or <code>null</code> if none
* is found.
*/
@Override
- public Root getRoot() {
+ public UI getUI() {
ClientConnector connector = this;
while (connector != null) {
- if (connector instanceof Root) {
- return (Root) connector;
+ if (connector instanceof UI) {
+ return (UI) connector;
}
connector = connector.getParent();
}
@@ -528,7 +528,7 @@ public abstract class AbstractClientConnector implements ClientConnector {
public void attach() {
markAsDirty();
- getRoot().getConnectorTracker().registerConnector(this);
+ getUI().getConnectorTracker().registerConnector(this);
for (ClientConnector connector : getAllChildrenIterable(this)) {
connector.attach();
@@ -540,7 +540,7 @@ public abstract class AbstractClientConnector implements ClientConnector {
* {@inheritDoc}
*
* <p>
- * The {@link #getApplication()} and {@link #getRoot()} methods might return
+ * The {@link #getApplication()} and {@link #getUI()} methods might return
* <code>null</code> after this method is called.
* </p>
*/
@@ -550,7 +550,7 @@ public abstract class AbstractClientConnector implements ClientConnector {
connector.detach();
}
- getRoot().getConnectorTracker().unregisterConnector(this);
+ getUI().getConnectorTracker().unregisterConnector(this);
}
@Override
diff --git a/server/src/com/vaadin/terminal/AbstractRootProvider.java b/server/src/com/vaadin/terminal/AbstractUIProvider.java
index 0b63003440..5bb4d35b30 100644
--- a/server/src/com/vaadin/terminal/AbstractRootProvider.java
+++ b/server/src/com/vaadin/terminal/AbstractUIProvider.java
@@ -17,13 +17,13 @@
package com.vaadin.terminal;
import com.vaadin.Application;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
-public abstract class AbstractRootProvider implements RootProvider {
+public abstract class AbstractUIProvider implements UIProvider {
@Override
- public Root instantiateRoot(Application application,
- Class<? extends Root> type, WrappedRequest request) {
+ public UI instantiateUI(Application application,
+ Class<? extends UI> type, WrappedRequest request) {
try {
return type.newInstance();
} catch (InstantiationException e) {
diff --git a/server/src/com/vaadin/terminal/DefaultRootProvider.java b/server/src/com/vaadin/terminal/DefaultUIProvider.java
index cbf8c98828..8713c45b31 100644
--- a/server/src/com/vaadin/terminal/DefaultRootProvider.java
+++ b/server/src/com/vaadin/terminal/DefaultUIProvider.java
@@ -17,19 +17,19 @@
package com.vaadin.terminal;
import com.vaadin.Application;
-import com.vaadin.RootRequiresMoreInformationException;
-import com.vaadin.ui.Root;
+import com.vaadin.UIRequiresMoreInformationException;
+import com.vaadin.ui.UI;
-public class DefaultRootProvider extends AbstractRootProvider {
+public class DefaultUIProvider extends AbstractUIProvider {
@Override
- public Class<? extends Root> getRootClass(Application application,
- WrappedRequest request) throws RootRequiresMoreInformationException {
- Object rootClassNameObj = application
- .getProperty(Application.ROOT_PARAMETER);
+ public Class<? extends UI> getUIClass(Application application,
+ WrappedRequest request) throws UIRequiresMoreInformationException {
+ Object uiClassNameObj = application
+ .getProperty(Application.UI_PARAMETER);
- if (rootClassNameObj instanceof String) {
- String rootClassName = rootClassNameObj.toString();
+ if (uiClassNameObj instanceof String) {
+ String uiClassName = uiClassNameObj.toString();
ClassLoader classLoader = request.getDeploymentConfiguration()
.getClassLoader();
@@ -37,12 +37,12 @@ public class DefaultRootProvider extends AbstractRootProvider {
classLoader = getClass().getClassLoader();
}
try {
- Class<? extends Root> rootClass = Class.forName(rootClassName,
- true, classLoader).asSubclass(Root.class);
+ Class<? extends UI> uiClass = Class.forName(uiClassName, true,
+ classLoader).asSubclass(UI.class);
- return rootClass;
+ return uiClass;
} catch (ClassNotFoundException e) {
- throw new RuntimeException("Could not find root class", e);
+ throw new RuntimeException("Could not find UI class", e);
}
}
diff --git a/server/src/com/vaadin/terminal/DeploymentConfiguration.java b/server/src/com/vaadin/terminal/DeploymentConfiguration.java
index 14a5a3724f..0cfbdb7544 100644
--- a/server/src/com/vaadin/terminal/DeploymentConfiguration.java
+++ b/server/src/com/vaadin/terminal/DeploymentConfiguration.java
@@ -23,6 +23,7 @@ import java.util.Properties;
import javax.portlet.PortletContext;
import javax.servlet.ServletContext;
+import com.vaadin.service.ApplicationContext;
import com.vaadin.terminal.gwt.server.AddonContext;
import com.vaadin.terminal.gwt.server.AddonContextListener;
@@ -97,7 +98,7 @@ public interface DeploymentConfiguration extends Serializable {
/**
* Get the class loader to use for loading classes loaded by name, e.g.
- * custom Root classes. <code>null</code> indicates that the default class
+ * custom UI classes. <code>null</code> indicates that the default class
* loader should be used.
*
* @return the class loader to use, or <code>null</code>
@@ -136,6 +137,8 @@ public interface DeploymentConfiguration extends Serializable {
/**
* Returns whether Vaadin is in production mode.
*
+ * @since 7.0.0
+ *
* @return true if in production mode, false otherwise.
*/
public boolean isProductionMode();
@@ -143,6 +146,8 @@ public interface DeploymentConfiguration extends Serializable {
/**
* Returns whether cross-site request forgery protection is enabled.
*
+ * @since 7.0.0
+ *
* @return true if XSRF protection is enabled, false otherwise.
*/
public boolean isXsrfProtectionEnabled();
@@ -150,7 +155,34 @@ public interface DeploymentConfiguration extends Serializable {
/**
* Returns the time resources can be cached in the browsers, in seconds.
*
+ * @since 7.0.0
+ *
* @return The resource cache time.
*/
public int getResourceCacheTime();
+
+ /**
+ * Returns the number of seconds between heartbeat requests of a UI, or a
+ * non-positive number if heartbeat is disabled.
+ *
+ * @since 7.0.0
+ *
+ * @return The time between heartbeats.
+ */
+ public int getHeartbeatInterval();
+
+ /**
+ * Returns whether UIs that have no other activity than heartbeat requests
+ * should be closed after they have been idle the maximum inactivity time
+ * enforced by the session.
+ *
+ * @see ApplicationContext#getMaxInactiveInterval()
+ *
+ * @since 7.0.0
+ *
+ * @return True if UIs receiving only heartbeat requests are eventually
+ * closed; false if heartbeat requests extend UI lifetime
+ * indefinitely.
+ */
+ public boolean isIdleUICleanupEnabled();
}
diff --git a/server/src/com/vaadin/terminal/Page.java b/server/src/com/vaadin/terminal/Page.java
index 41ab8cc8b6..66ef7da296 100644
--- a/server/src/com/vaadin/terminal/Page.java
+++ b/server/src/com/vaadin/terminal/Page.java
@@ -25,27 +25,27 @@ import java.util.List;
import com.vaadin.event.EventRouter;
import com.vaadin.shared.ui.BorderStyle;
-import com.vaadin.shared.ui.root.PageClientRpc;
-import com.vaadin.shared.ui.root.RootConstants;
+import com.vaadin.shared.ui.ui.PageClientRpc;
+import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.terminal.WrappedRequest.BrowserDetails;
import com.vaadin.terminal.gwt.server.WebApplicationContext;
import com.vaadin.terminal.gwt.server.WebBrowser;
import com.vaadin.tools.ReflectTools;
import com.vaadin.ui.JavaScript;
import com.vaadin.ui.Notification;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
public class Page implements Serializable {
/**
* Listener that gets notified when the size of the browser window
- * containing the root has changed.
+ * containing the uI has changed.
*
- * @see Root#addListener(BrowserWindowResizeListener)
+ * @see UI#addListener(BrowserWindowResizeListener)
*/
public interface BrowserWindowResizeListener extends Serializable {
/**
- * Invoked when the browser window containing a Root has been resized.
+ * Invoked when the browser window containing a UI has been resized.
*
* @param event
* a browser window resize event
@@ -54,7 +54,7 @@ public class Page implements Serializable {
}
/**
- * Event that is fired when a browser window containing a root is resized.
+ * Event that is fired when a browser window containing a uI is resized.
*/
public class BrowserWindowResizeEvent extends EventObject {
@@ -65,7 +65,7 @@ public class Page implements Serializable {
* Creates a new event
*
* @param source
- * the root for which the browser window has been resized
+ * the uI for which the browser window has been resized
* @param width
* the new width of the browser window
* @param height
@@ -254,9 +254,9 @@ public class Page implements Serializable {
}
/**
- * Gets the root in which the fragment has changed.
+ * Gets the uI in which the fragment has changed.
*
- * @return the root in which the fragment has changed
+ * @return the uI in which the fragment has changed
*/
public Page getPage() {
return (Page) getSource();
@@ -279,15 +279,15 @@ public class Page implements Serializable {
*/
private String fragment;
- private final Root root;
+ private final UI uI;
private int browserWindowWidth = -1;
private int browserWindowHeight = -1;
private JavaScript javaScript;
- public Page(Root root) {
- this.root = root;
+ public Page(UI uI) {
+ this.uI = uI;
}
private void addListener(Class<?> eventType, Object target, Method method) {
@@ -332,7 +332,7 @@ public class Page implements Serializable {
if (fireEvents) {
fireEvent(new FragmentChangedEvent(this, newFragment));
}
- root.markAsDirty();
+ uI.markAsDirty();
}
}
@@ -374,7 +374,7 @@ public class Page implements Serializable {
}
public WebBrowser getWebBrowser() {
- return ((WebApplicationContext) root.getApplication().getContext())
+ return ((WebApplicationContext) uI.getApplication().getContext())
.getBrowser();
}
@@ -399,8 +399,8 @@ public class Page implements Serializable {
}
/**
- * Adds a new {@link BrowserWindowResizeListener} to this root. The listener
- * will be notified whenever the browser window within which this root
+ * Adds a new {@link BrowserWindowResizeListener} to this uI. The listener
+ * will be notified whenever the browser window within which this uI
* resides is resized.
*
* @param resizeListener
@@ -415,7 +415,7 @@ public class Page implements Serializable {
}
/**
- * Removes a {@link BrowserWindowResizeListener} from this root. The
+ * Removes a {@link BrowserWindowResizeListener} from this uI. The
* listener will no longer be notified when the browser window is resized.
*
* @param resizeListener
@@ -427,7 +427,7 @@ public class Page implements Serializable {
}
/**
- * Gets the last known height of the browser window in which this root
+ * Gets the last known height of the browser window in which this uI
* resides.
*
* @return the browser window height in pixels
@@ -437,7 +437,7 @@ public class Page implements Serializable {
}
/**
- * Gets the last known width of the browser window in which this root
+ * Gets the last known width of the browser window in which this uI
* resides.
*
* @return the browser window width in pixels
@@ -450,7 +450,7 @@ public class Page implements Serializable {
if (javaScript == null) {
// Create and attach on first use
javaScript = new JavaScript();
- javaScript.extend(root);
+ javaScript.extend(uI);
}
return javaScript;
@@ -474,32 +474,32 @@ public class Page implements Serializable {
target.startTag("notification");
if (n.getCaption() != null) {
target.addAttribute(
- RootConstants.ATTRIBUTE_NOTIFICATION_CAPTION,
+ UIConstants.ATTRIBUTE_NOTIFICATION_CAPTION,
n.getCaption());
}
if (n.getDescription() != null) {
target.addAttribute(
- RootConstants.ATTRIBUTE_NOTIFICATION_MESSAGE,
+ UIConstants.ATTRIBUTE_NOTIFICATION_MESSAGE,
n.getDescription());
}
if (n.getIcon() != null) {
target.addAttribute(
- RootConstants.ATTRIBUTE_NOTIFICATION_ICON,
+ UIConstants.ATTRIBUTE_NOTIFICATION_ICON,
n.getIcon());
}
if (!n.isHtmlContentAllowed()) {
target.addAttribute(
- RootConstants.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED,
+ UIConstants.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED,
true);
}
target.addAttribute(
- RootConstants.ATTRIBUTE_NOTIFICATION_POSITION, n
+ UIConstants.ATTRIBUTE_NOTIFICATION_POSITION, n
.getPosition().ordinal());
- target.addAttribute(RootConstants.ATTRIBUTE_NOTIFICATION_DELAY,
+ target.addAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_DELAY,
n.getDelayMsec());
if (n.getStyleName() != null) {
target.addAttribute(
- RootConstants.ATTRIBUTE_NOTIFICATION_STYLE,
+ UIConstants.ATTRIBUTE_NOTIFICATION_STYLE,
n.getStyleName());
}
target.endTag("notification");
@@ -509,21 +509,21 @@ public class Page implements Serializable {
}
if (fragment != null) {
- target.addAttribute(RootConstants.FRAGMENT_VARIABLE, fragment);
+ target.addAttribute(UIConstants.FRAGMENT_VARIABLE, fragment);
}
}
/**
- * Opens the given resource in this root. The contents of this Root is
+ * Opens the given resource in this uI. The contents of this UI is
* replaced by the {@code Resource}.
*
* @param resource
- * the resource to show in this root
+ * the resource to show in this uI
*/
public void open(Resource resource) {
openList.add(new OpenResource(resource, null, -1, -1, BORDER_DEFAULT));
- root.markAsDirty();
+ uI.markAsDirty();
}
/**
@@ -566,7 +566,7 @@ public class Page implements Serializable {
public void open(Resource resource, String windowName) {
openList.add(new OpenResource(resource, windowName, -1, -1,
BORDER_DEFAULT));
- root.markAsDirty();
+ uI.markAsDirty();
}
/**
@@ -589,7 +589,7 @@ public class Page implements Serializable {
int height, BorderStyle border) {
openList.add(new OpenResource(resource, windowName, width, height,
border));
- root.markAsDirty();
+ uI.markAsDirty();
}
/**
@@ -603,7 +603,7 @@ public class Page implements Serializable {
notifications = new LinkedList<Notification>();
}
notifications.add(notification);
- root.markAsDirty();
+ uI.markAsDirty();
}
/**
@@ -622,21 +622,21 @@ public class Page implements Serializable {
}
/**
- * Gets the Page to which the current root belongs. This is automatically
+ * Gets the Page to which the current uI belongs. This is automatically
* defined when processing requests to the server. In other cases, (e.g.
- * from background threads), the current root is not automatically defined.
+ * from background threads), the current uI is not automatically defined.
*
- * @see Root#getCurrent()
+ * @see UI#getCurrent()
*
* @return the current page instance if available, otherwise
* <code>null</code>
*/
public static Page getCurrent() {
- Root currentRoot = Root.getCurrent();
- if (currentRoot == null) {
+ UI currentUI = UI.getCurrent();
+ if (currentUI == null) {
return null;
}
- return currentRoot.getPage();
+ return currentUI.getPage();
}
/**
@@ -647,7 +647,7 @@ public class Page implements Serializable {
* the new page title to set
*/
public void setTitle(String title) {
- root.getRpcProxy(PageClientRpc.class).setTitle(title);
+ uI.getRpcProxy(PageClientRpc.class).setTitle(title);
}
}
diff --git a/server/src/com/vaadin/terminal/RootProvider.java b/server/src/com/vaadin/terminal/UIProvider.java
index 476cf1bd78..27b63fbcac 100644
--- a/server/src/com/vaadin/terminal/RootProvider.java
+++ b/server/src/com/vaadin/terminal/UIProvider.java
@@ -17,13 +17,13 @@
package com.vaadin.terminal;
import com.vaadin.Application;
-import com.vaadin.RootRequiresMoreInformationException;
-import com.vaadin.ui.Root;
+import com.vaadin.UIRequiresMoreInformationException;
+import com.vaadin.ui.UI;
-public interface RootProvider {
- public Class<? extends Root> getRootClass(Application application,
- WrappedRequest request) throws RootRequiresMoreInformationException;
+public interface UIProvider {
+ public Class<? extends UI> getUIClass(Application application,
+ WrappedRequest request) throws UIRequiresMoreInformationException;
- public Root instantiateRoot(Application application,
- Class<? extends Root> type, WrappedRequest request);
+ public UI instantiateUI(Application application,
+ Class<? extends UI> type, WrappedRequest request);
}
diff --git a/server/src/com/vaadin/terminal/WrappedRequest.java b/server/src/com/vaadin/terminal/WrappedRequest.java
index c317eae048..343a60848e 100644
--- a/server/src/com/vaadin/terminal/WrappedRequest.java
+++ b/server/src/com/vaadin/terminal/WrappedRequest.java
@@ -27,10 +27,10 @@ import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import com.vaadin.Application;
-import com.vaadin.RootRequiresMoreInformationException;
+import com.vaadin.UIRequiresMoreInformationException;
import com.vaadin.annotations.EagerInit;
import com.vaadin.terminal.gwt.server.WebBrowser;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
* A generic request to the server, wrapping a more specific request type, e.g.
@@ -219,9 +219,10 @@ public interface WrappedRequest extends Serializable {
* for instance using javascript in the browser.
*
* This information is only guaranteed to be available in some special
- * cases, for instance when {@link Application#getRoot} is called again
- * after throwing {@link RootRequiresMoreInformationException} or in
- * {@link Root#init(WrappedRequest)} for a Root class not annotated with
+ * cases, for instance when
+ * {@link Application#getUIForRequest(WrappedRequest)} is called again after
+ * throwing {@link UIRequiresMoreInformationException} or in
+ * {@link UI#init(WrappedRequest)} for a UI class not annotated with
* {@link EagerInit}
*
* @return the browser details, or <code>null</code> if details are not
diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
index bd39504237..345f462239 100644
--- a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
+++ b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
@@ -56,13 +56,13 @@ import com.liferay.portal.kernel.util.PropsUtil;
import com.vaadin.Application;
import com.vaadin.Application.ApplicationStartEvent;
import com.vaadin.Application.SystemMessages;
-import com.vaadin.RootRequiresMoreInformationException;
+import com.vaadin.UIRequiresMoreInformationException;
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.server.AbstractCommunicationManager.Callback;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
* Portlet 2.0 base class. This replaces the servlet in servlet/portlet 1.0
@@ -340,7 +340,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
}
protected enum RequestType {
- FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN, BROWSER_DETAILS, CONNECTOR_RESOURCE;
+ FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN, BROWSER_DETAILS, CONNECTOR_RESOURCE, HEARTBEAT;
}
protected RequestType getRequestType(WrappedPortletRequest wrappedRequest) {
@@ -361,6 +361,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
} else if (ServletPortletHelper
.isApplicationResourceRequest(wrappedRequest)) {
return RequestType.APPLICATION_RESOURCE;
+ } else if (ServletPortletHelper.isHeartbeatRequest(wrappedRequest)) {
+ return RequestType.HEARTBEAT;
} else if (isDummyRequest(resourceRequest)) {
return RequestType.DUMMY;
} else {
@@ -431,6 +433,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
Application application = null;
boolean transactionStarted = false;
boolean requestStarted = false;
+ boolean applicationRunning = false;
try {
// TODO What about PARAM_UNLOADBURST & redirectToApplication??
@@ -459,6 +462,10 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
applicationManager.serveConnectorResource(wrappedRequest,
wrappedResponse);
return;
+ } else if (requestType == RequestType.HEARTBEAT) {
+ applicationManager.handleHeartbeatRequest(wrappedRequest,
+ wrappedResponse, application);
+ return;
}
/* Update browser information from request */
@@ -477,6 +484,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
/* Start the newly created application */
startApplication(request, application, applicationContext);
+ applicationRunning = true;
/*
* Transaction starts. Call transaction listeners. Transaction
@@ -488,36 +496,35 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
/* Notify listeners */
// Finds the window within the application
- Root root = null;
+ UI uI = null;
synchronized (application) {
if (application.isRunning()) {
switch (requestType) {
case RENDER:
case ACTION:
// Both action requests and render requests are ok
- // without a Root as they render the initial HTML
+ // without a UI as they render the initial HTML
// and then do a second request
try {
- root = application
- .getRootForRequest(wrappedRequest);
- } catch (RootRequiresMoreInformationException e) {
- // Ignore problem and continue without root
+ uI = application
+ .getUIForRequest(wrappedRequest);
+ } catch (UIRequiresMoreInformationException e) {
+ // Ignore problem and continue without UI
}
break;
case BROWSER_DETAILS:
- // Should not try to find a root here as the
- // combined request details might change the root
+ // Should not try to find a UI here as the
+ // combined request details might change the UI
break;
case FILE_UPLOAD:
// no window
break;
case APPLICATION_RESOURCE:
// use main window - should not need any window
- // root = application.getRoot();
+ // UI = application.getUI();
break;
default:
- root = application
- .getRootForRequest(wrappedRequest);
+ uI = application.getUIForRequest(wrappedRequest);
}
// if window not found, not a problem - use null
}
@@ -527,25 +534,24 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
// starts?
if (request instanceof RenderRequest) {
applicationContext.firePortletRenderRequest(application,
- root, (RenderRequest) request,
+ uI, (RenderRequest) request,
(RenderResponse) response);
} else if (request instanceof ActionRequest) {
applicationContext.firePortletActionRequest(application,
- root, (ActionRequest) request,
+ uI, (ActionRequest) request,
(ActionResponse) response);
} else if (request instanceof EventRequest) {
- applicationContext.firePortletEventRequest(application,
- root, (EventRequest) request,
- (EventResponse) response);
+ applicationContext.firePortletEventRequest(application, uI,
+ (EventRequest) request, (EventResponse) response);
} else if (request instanceof ResourceRequest) {
applicationContext.firePortletResourceRequest(application,
- root, (ResourceRequest) request,
+ uI, (ResourceRequest) request,
(ResourceResponse) response);
}
/* Handle the request */
if (requestType == RequestType.FILE_UPLOAD) {
- // Root is resolved in handleFileUpload by
+ // UI is resolved in handleFileUpload by
// PortletCommunicationManager
applicationManager.handleFileUpload(application,
wrappedRequest, wrappedResponse);
@@ -557,7 +563,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
} else if (requestType == RequestType.UIDL) {
// Handles AJAX UIDL requests
applicationManager.handleUidlRequest(wrappedRequest,
- wrappedResponse, portletWrapper, root);
+ wrappedResponse, portletWrapper, uI);
return;
} else {
/*
@@ -585,6 +591,11 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
handleServiceException(wrappedRequest, wrappedResponse,
application, e);
} finally {
+
+ if (applicationRunning) {
+ application.closeInactiveUIs();
+ }
+
// Notifies transaction end
try {
if (transactionStarted) {
@@ -599,7 +610,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
}
} finally {
- Root.setCurrent(null);
+ UI.setCurrent(null);
Application.setCurrent(null);
PortletSession session = request
@@ -895,7 +906,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
throws PortletException {
try {
final Application application = getApplicationClass().newInstance();
- application.setRootPreserved(true);
+ application.setUiPreserved(true);
return application;
} catch (final IllegalAccessException e) {
throw new PortletException("getNewApplication failed", e);
diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
index 062ba6cdf7..13fd869166 100644
--- a/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
+++ b/server/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
@@ -56,7 +56,7 @@ import com.vaadin.terminal.ThemeResource;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.WrappedResponse;
import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
* Abstract implementation of the ApplicationServlet which handles all
@@ -248,6 +248,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
Application application = null;
boolean transactionStarted = false;
boolean requestStarted = false;
+ boolean applicationRunning = false;
try {
// If a duplicate "close application" URL is received for an
@@ -287,6 +288,10 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
if (requestType == RequestType.CONNECTOR_RESOURCE) {
applicationManager.serveConnectorResource(request, response);
return;
+ } else if (requestType == RequestType.HEARTBEAT) {
+ applicationManager.handleHeartbeatRequest(request, response,
+ application);
+ return;
}
/* Update browser information from the request */
@@ -304,6 +309,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
// Start the application if it's newly created
startApplication(request, application, webApplicationContext);
+ applicationRunning = true;
/*
* Transaction starts. Call transaction listeners. Transaction end
@@ -314,21 +320,21 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
/* Handle the request */
if (requestType == RequestType.FILE_UPLOAD) {
- // Root is resolved in communication manager
+ // UI is resolved in communication manager
applicationManager.handleFileUpload(application, request,
response);
return;
} else if (requestType == RequestType.UIDL) {
- Root root = application.getRootForRequest(request);
- if (root == null) {
- throw new ServletException(ERROR_NO_ROOT_FOUND);
+ UI uI = application.getUIForRequest(request);
+ if (uI == null) {
+ throw new ServletException(ERROR_NO_UI_FOUND);
}
// Handles AJAX UIDL requests
applicationManager.handleUidlRequest(request, response,
- servletWrapper, root);
+ servletWrapper, uI);
return;
} else if (requestType == RequestType.BROWSER_DETAILS) {
- // Browser details - not related to a specific root
+ // Browser details - not related to a specific UI
applicationManager.handleBrowserDetailsRequest(request,
response, application);
return;
@@ -354,6 +360,11 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
} catch (final Throwable e) {
handleServiceException(request, response, application, e);
} finally {
+
+ if (applicationRunning) {
+ application.closeInactiveUIs();
+ }
+
// Notifies transaction end
try {
if (transactionStarted) {
@@ -369,7 +380,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
.onRequestEnd(request, response);
}
} finally {
- Root.setCurrent(null);
+ UI.setCurrent(null);
Application.setCurrent(null);
HttpSession session = request.getSession(false);
@@ -1121,7 +1132,7 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
}
protected enum RequestType {
- FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE, CONNECTOR_RESOURCE;
+ FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE, CONNECTOR_RESOURCE, HEARTBEAT;
}
protected RequestType getRequestType(WrappedHttpServletRequest request) {
@@ -1137,6 +1148,8 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
return RequestType.STATIC_FILE;
} else if (ServletPortletHelper.isApplicationResourceRequest(request)) {
return RequestType.APPLICATION_RESOURCE;
+ } else if (ServletPortletHelper.isHeartbeatRequest(request)) {
+ return RequestType.HEARTBEAT;
}
return RequestType.OTHER;
diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
index 7ea4a7d097..81c497713b 100644
--- a/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
+++ b/server/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
@@ -60,7 +60,7 @@ import javax.servlet.http.HttpServletResponse;
import com.vaadin.Application;
import com.vaadin.Application.SystemMessages;
-import com.vaadin.RootRequiresMoreInformationException;
+import com.vaadin.UIRequiresMoreInformationException;
import com.vaadin.annotations.JavaScript;
import com.vaadin.annotations.StyleSheet;
import com.vaadin.external.json.JSONArray;
@@ -74,6 +74,7 @@ import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.communication.SharedState;
import com.vaadin.shared.communication.UidlValue;
+import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.terminal.AbstractClientConnector;
import com.vaadin.terminal.CombinedRequest;
import com.vaadin.terminal.LegacyPaint;
@@ -97,15 +98,15 @@ import com.vaadin.ui.AbstractField;
import com.vaadin.ui.Component;
import com.vaadin.ui.ConnectorTracker;
import com.vaadin.ui.HasComponents;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
import com.vaadin.ui.Window;
/**
* This is a common base class for the server-side implementations of the
* communication system between the client code (compiled with GWT into
* JavaScript) and the server side components. Its client side counterpart is
- * {@link ApplicationConstants}.
- *
+ * {@link com.vaadin.terminal.gwt.client.ApplicationConnection}.
+ * <p>
* TODO Document better!
*/
@SuppressWarnings("serial")
@@ -146,7 +147,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
public static final char VAR_ESCAPE_CHARACTER = '\u001b';
- private final HashMap<Integer, ClientCache> rootToClientCache = new HashMap<Integer, ClientCache>();
+ private final HashMap<Integer, ClientCache> uiToClientCache = new HashMap<Integer, ClientCache>();
private static final int MAX_BUFFER_SIZE = 64 * 1024;
@@ -506,7 +507,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
* Internally process a UIDL request from the client.
*
* This method calls
- * {@link #handleVariables(WrappedRequest, WrappedResponse, Callback, Application, Root)}
+ * {@link #handleVariables(WrappedRequest, WrappedResponse, Callback, Application, UI)}
* to process any changes to variables by the client and then repaints
* affected components using {@link #paintAfterVariableChanges()}.
*
@@ -520,7 +521,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
* @param request
* @param response
* @param callback
- * @param root
+ * @param uI
* target window for the UIDL request, can be null if target not
* found
* @throws IOException
@@ -528,7 +529,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
* @throws JSONException
*/
public void handleUidlRequest(WrappedRequest request,
- WrappedResponse response, Callback callback, Root root)
+ WrappedResponse response, Callback callback, UI uI)
throws IOException, InvalidUIDLSecurityKeyException, JSONException {
checkWidgetsetVersion(request);
@@ -550,7 +551,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
if (request.getParameter(GET_PARAM_HIGHLIGHT_COMPONENT) != null) {
String pid = request
.getParameter(GET_PARAM_HIGHLIGHT_COMPONENT);
- highlightedConnector = root.getConnectorTracker().getConnector(
+ highlightedConnector = uI.getConnectorTracker().getConnector(
pid);
highlightConnector(highlightedConnector);
}
@@ -567,10 +568,10 @@ public abstract class AbstractCommunicationManager implements Serializable {
// Finds the window within the application
if (application.isRunning()) {
// Returns if no window found
- if (root == null) {
+ if (uI == null) {
// This should not happen, no windows exists but
// application is still open.
- getLogger().warning("Could not get root for application");
+ getLogger().warning("Could not get UI for application");
return;
}
} else {
@@ -579,8 +580,11 @@ public abstract class AbstractCommunicationManager implements Serializable {
return;
}
+ // Keep the UI alive
+ uI.setLastUidlRequestTime(System.currentTimeMillis());
+
// Change all variables based on request parameters
- if (!handleVariables(request, response, callback, application, root)) {
+ if (!handleVariables(request, response, callback, application, uI)) {
// var inconsistency; the client is probably out-of-sync
SystemMessages ci = null;
@@ -611,8 +615,8 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
paintAfterVariableChanges(request, response, callback, repaintAll,
- outWriter, root, analyzeLayouts);
- postPaint(root);
+ outWriter, uI, analyzeLayouts);
+ postPaint(uI);
}
outWriter.close();
@@ -645,20 +649,20 @@ public abstract class AbstractCommunicationManager implements Serializable {
* Method called after the paint phase while still being synchronized on the
* application
*
- * @param root
+ * @param uI
*
*/
- protected void postPaint(Root root) {
+ protected void postPaint(UI uI) {
// Remove connectors that have been detached from the application during
// handling of the request
- root.getConnectorTracker().cleanConnectorMap();
+ uI.getConnectorTracker().cleanConnectorMap();
if (pidToNameToStreamVariable != null) {
Iterator<String> iterator = pidToNameToStreamVariable.keySet()
.iterator();
while (iterator.hasNext()) {
String connectorId = iterator.next();
- if (root.getConnectorTracker().getConnector(connectorId) == null) {
+ if (uI.getConnectorTracker().getConnector(connectorId) == null) {
// Owner is no longer attached to the application
Map<String, StreamVariable> removed = pidToNameToStreamVariable
.get(connectorId);
@@ -746,7 +750,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
*/
private void paintAfterVariableChanges(WrappedRequest request,
WrappedResponse response, Callback callback, boolean repaintAll,
- final PrintWriter outWriter, Root root, boolean analyzeLayouts)
+ final PrintWriter outWriter, UI uI, boolean analyzeLayouts)
throws PaintException, IOException, JSONException {
// Removes application if it has stopped during variable changes
@@ -765,7 +769,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
outWriter.print(getSecurityKeyUIDL(request));
}
- writeUidlResponse(request, repaintAll, outWriter, root, analyzeLayouts);
+ writeUidlResponse(request, repaintAll, outWriter, uI, analyzeLayouts);
closeJsonMessage(outWriter);
@@ -810,17 +814,17 @@ public abstract class AbstractCommunicationManager implements Serializable {
@SuppressWarnings("unchecked")
public void writeUidlResponse(WrappedRequest request, boolean repaintAll,
- final PrintWriter outWriter, Root root, boolean analyzeLayouts)
+ final PrintWriter outWriter, UI ui, boolean analyzeLayouts)
throws PaintException, JSONException {
ArrayList<ClientConnector> dirtyVisibleConnectors = new ArrayList<ClientConnector>();
- Application application = root.getApplication();
+ Application application = ui.getApplication();
// Paints components
- ConnectorTracker rootConnectorTracker = root.getConnectorTracker();
+ ConnectorTracker uiConnectorTracker = ui.getConnectorTracker();
getLogger().log(Level.FINE, "* Creating response to client");
if (repaintAll) {
- getClientCache(root).clear();
- rootConnectorTracker.markAllConnectorsDirty();
- rootConnectorTracker.markAllClientSidesUninitialized();
+ getClientCache(ui).clear();
+ uiConnectorTracker.markAllConnectorsDirty();
+ uiConnectorTracker.markAllClientSidesUninitialized();
// Reset sent locales
locales = null;
@@ -828,18 +832,18 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
dirtyVisibleConnectors
- .addAll(getDirtyVisibleConnectors(rootConnectorTracker));
+ .addAll(getDirtyVisibleConnectors(uiConnectorTracker));
getLogger().log(
Level.FINE,
"Found " + dirtyVisibleConnectors.size()
+ " dirty connectors to paint");
for (ClientConnector connector : dirtyVisibleConnectors) {
- boolean initialized = rootConnectorTracker
+ boolean initialized = uiConnectorTracker
.isClientSideInitialized(connector);
connector.beforeClientResponse(!initialized);
}
- rootConnectorTracker.markAllConnectorsClean();
+ uiConnectorTracker.markAllConnectorsClean();
outWriter.print("\"changes\":[");
@@ -851,12 +855,11 @@ public abstract class AbstractCommunicationManager implements Serializable {
if (analyzeLayouts) {
invalidComponentRelativeSizes = ComponentSizeValidator
- .validateComponentRelativeSizes(root.getContent(), null,
- null);
+ .validateComponentRelativeSizes(ui.getContent(), null, null);
// Also check any existing subwindows
- if (root.getWindows() != null) {
- for (Window subWindow : root.getWindows()) {
+ if (ui.getWindows() != null) {
+ for (Window subWindow : ui.getWindows()) {
invalidComponentRelativeSizes = ComponentSizeValidator
.validateComponentRelativeSizes(
subWindow.getContent(),
@@ -951,10 +954,10 @@ public abstract class AbstractCommunicationManager implements Serializable {
outWriter.append(hierarchyInfo.toString());
outWriter.print(", "); // close hierarchy
- // send server to client RPC calls for components in the root, in call
+ // send server to client RPC calls for components in the UI, in call
// order
- // collect RPC calls from components in the root in the order in
+ // collect RPC calls from components in the UI in the order in
// which they were performed, remove the calls from components
LinkedList<ClientConnector> rpcPendingQueue = new LinkedList<ClientConnector>(
@@ -983,9 +986,10 @@ public abstract class AbstractCommunicationManager implements Serializable {
// + parameterType.getName());
// }
// }
- paramJson.put(JsonCodec.encode(
+ EncodeResult encodeResult = JsonCodec.encode(
invocation.getParameters()[i], referenceParameter,
- parameterType, root.getConnectorTracker()));
+ parameterType, ui.getConnectorTracker());
+ paramJson.put(encodeResult.getEncodedValue());
}
invocationJson.put(paramJson);
rpcCalls.put(invocationJson);
@@ -1087,7 +1091,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
final String resource = (String) i.next();
InputStream is = null;
try {
- is = getThemeResourceAsStream(root, getTheme(root), resource);
+ is = getThemeResourceAsStream(ui, getTheme(ui), resource);
} catch (final Exception e) {
// FIXME: Handle exception
getLogger().log(Level.FINER,
@@ -1124,7 +1128,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
Collection<Class<? extends ClientConnector>> usedClientConnectors = paintTarget
.getUsedClientConnectors();
boolean typeMappingsOpen = false;
- ClientCache clientCache = getClientCache(root);
+ ClientCache clientCache = getClientCache(ui);
List<Class<? extends ClientConnector>> newConnectorTypes = new ArrayList<Class<? extends ClientConnector>>();
@@ -1237,7 +1241,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
for (ClientConnector connector : dirtyVisibleConnectors) {
- rootConnectorTracker.markClientSideInitialized(connector);
+ uiConnectorTracker.markClientSideInitialized(connector);
}
writePerformanceData(outWriter);
@@ -1245,33 +1249,35 @@ public abstract class AbstractCommunicationManager implements Serializable {
public static JSONObject encodeState(ClientConnector connector,
SharedState state) throws JSONException {
- Root root = connector.getRoot();
- ConnectorTracker connectorTracker = root.getConnectorTracker();
+ UI uI = connector.getUI();
+ ConnectorTracker connectorTracker = uI.getConnectorTracker();
Class<? extends SharedState> stateType = connector.getStateType();
Object diffState = connectorTracker.getDiffState(connector);
- if (diffState == null) {
- diffState = new JSONObject();
+ boolean supportsDiffState = !JavaScriptConnectorState.class
+ .isAssignableFrom(stateType);
+ if (diffState == null && supportsDiffState) {
// Use an empty state object as reference for full
// repaints
- 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());
- }
+
+ try {
+ SharedState referenceState = stateType.newInstance();
+ EncodeResult encodeResult = JsonCodec.encode(referenceState,
+ null, stateType, uI.getConnectorTracker());
+ diffState = encodeResult.getEncodedValue();
+ } catch (Exception e) {
+ getLogger().log(
+ Level.WARNING,
+ "Error creating reference object for state of type "
+ + stateType.getName());
}
- connectorTracker.setDiffState(connector, diffState);
}
- JSONObject stateJson = (JSONObject) JsonCodec.encode(state, diffState,
- stateType, root.getConnectorTracker());
- return stateJson;
+ EncodeResult encodeResult = JsonCodec.encode(state, diffState,
+ stateType, uI.getConnectorTracker());
+ if (supportsDiffState) {
+ connectorTracker.setDiffState(connector,
+ encodeResult.getEncodedValue());
+ }
+ return (JSONObject) encodeResult.getDiff();
}
/**
@@ -1388,12 +1394,12 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
- private ClientCache getClientCache(Root root) {
- Integer rootId = Integer.valueOf(root.getRootId());
- ClientCache cache = rootToClientCache.get(rootId);
+ private ClientCache getClientCache(UI uI) {
+ Integer uiId = Integer.valueOf(uI.getUIId());
+ ClientCache cache = uiToClientCache.get(uiId);
if (cache == null) {
cache = new ClientCache();
- rootToClientCache.put(rootId, cache);
+ uiToClientCache.put(uiId, cache);
}
return cache;
}
@@ -1409,7 +1415,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
* @return <code>true</code> if the connector is visible to the client,
* <code>false</code> otherwise
*/
- static boolean isVisible(ClientConnector connector) {
+ public static boolean isVisible(ClientConnector connector) {
if (connector instanceof Component) {
return isVisible((Component) connector);
} else {
@@ -1439,7 +1445,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
HasComponents parent = child.getParent();
if (parent == null) {
- if (child instanceof Root) {
+ if (child instanceof UI) {
return child.isVisible();
} else {
return false;
@@ -1506,15 +1512,15 @@ public abstract class AbstractCommunicationManager implements Serializable {
return pendingInvocations;
}
- protected abstract InputStream getThemeResourceAsStream(Root root,
+ protected abstract InputStream getThemeResourceAsStream(UI uI,
String themeName, String resource);
private int getTimeoutInterval() {
return maxInactiveInterval;
}
- private String getTheme(Root root) {
- String themeName = root.getApplication().getThemeForRoot(root);
+ private String getTheme(UI uI) {
+ String themeName = uI.getApplication().getThemeForUI(uI);
String requestThemeName = getRequestTheme();
if (requestThemeName != null) {
@@ -1553,7 +1559,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
*/
private boolean handleVariables(WrappedRequest request,
WrappedResponse response, Callback callback,
- Application application2, Root root) throws IOException,
+ Application application2, UI uI) throws IOException,
InvalidUIDLSecurityKeyException, JSONException {
boolean success = true;
@@ -1589,7 +1595,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
for (int bi = 1; bi < bursts.length; bi++) {
// unescape any encoded separator characters in the burst
final String burst = unescapeBurst(bursts[bi]);
- success &= handleBurst(request, root, burst);
+ success &= handleBurst(request, uI, burst);
// In case that there were multiple bursts, we know that this is
// a special synchronous case for closing window. Thus we are
@@ -1604,7 +1610,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
new CharArrayWriter());
paintAfterVariableChanges(request, response, callback,
- true, outWriter, root, false);
+ true, outWriter, uI, false);
}
@@ -1631,23 +1637,22 @@ public abstract class AbstractCommunicationManager implements Serializable {
* directly.
*
* @param source
- * @param root
- * the root receiving the burst
+ * @param uI
+ * the UI receiving the burst
* @param burst
* the content of the burst as a String to be parsed
* @return true if the processing of the burst was successful and there were
* no messages to non-existent components
*/
- public boolean handleBurst(WrappedRequest source, Root root,
- final String burst) {
+ public boolean handleBurst(WrappedRequest source, UI uI, final String burst) {
boolean success = true;
try {
Set<Connector> enabledConnectors = new HashSet<Connector>();
List<MethodInvocation> invocations = parseInvocations(
- root.getConnectorTracker(), burst);
+ uI.getConnectorTracker(), burst);
for (MethodInvocation invocation : invocations) {
- final ClientConnector connector = getConnector(root,
+ final ClientConnector connector = getConnector(uI,
invocation.getConnectorId());
if (connector != null && connector.isConnectorEnabled()) {
@@ -1658,7 +1663,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
for (int i = 0; i < invocations.size(); i++) {
MethodInvocation invocation = invocations.get(i);
- final ClientConnector connector = getConnector(root,
+ final ClientConnector connector = getConnector(uI,
invocation.getConnectorId());
if (connector == null) {
@@ -1714,7 +1719,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
if (connector instanceof Component) {
errorComponent = (Component) connector;
}
- handleChangeVariablesError(root.getApplication(),
+ handleChangeVariablesError(uI.getApplication(),
errorComponent, realException, null);
}
} else {
@@ -1746,7 +1751,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
errorComponent = (Component) dropHandlerOwner;
}
}
- handleChangeVariablesError(root.getApplication(),
+ handleChangeVariablesError(uI.getApplication(),
errorComponent, e, changes);
}
}
@@ -1876,9 +1881,8 @@ public abstract class AbstractCommunicationManager implements Serializable {
owner.changeVariables(source, m);
}
- protected ClientConnector getConnector(Root root, String connectorId) {
- ClientConnector c = root.getConnectorTracker()
- .getConnector(connectorId);
+ protected ClientConnector getConnector(UI uI, String connectorId) {
+ ClientConnector c = uI.getConnectorTracker().getConnector(connectorId);
if (c == null
&& connectorId.equals(getDragAndDropService().getConnectorId())) {
return getDragAndDropService();
@@ -2230,7 +2234,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
* invisible subtrees are omitted.
*
* @param w
- * root window for which dirty components is to be fetched
+ * UI window for which dirty components is to be fetched
* @return
*/
private ArrayList<ClientConnector> getDirtyVisibleConnectors(
@@ -2343,7 +2347,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
* We will use the same APP/* URI space as ApplicationResources but
* prefix url with UPLOAD
*
- * eg. APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY]
+ * eg. APP/UPLOAD/[UIID]/[PID]/[NAME]/[SECKEY]
*
* SECKEY is created on each paint to make URL's unpredictable (to
* prevent CSRF attacks).
@@ -2352,8 +2356,8 @@ public abstract class AbstractCommunicationManager implements Serializable {
* handling post
*/
String paintableId = owner.getConnectorId();
- int rootId = owner.getRoot().getRootId();
- String key = rootId + "/" + paintableId + "/" + name;
+ int uiId = owner.getUI().getUIId();
+ String key = uiId + "/" + paintableId + "/" + name;
if (pidToNameToStreamVariable == null) {
pidToNameToStreamVariable = new HashMap<String, Map<String, StreamVariable>>();
@@ -2414,34 +2418,34 @@ public abstract class AbstractCommunicationManager implements Serializable {
WrappedResponse response, Application application)
throws IOException {
- // if we do not yet have a currentRoot, it should be initialized
+ // if we do not yet have a currentUI, it should be initialized
// shortly, and we should send the initial UIDL
- boolean sendUIDL = Root.getCurrent() == null;
+ boolean sendUIDL = UI.getCurrent() == null;
try {
CombinedRequest combinedRequest = new CombinedRequest(request);
- Root root = application.getRootForRequest(combinedRequest);
+ UI uI = application.getUIForRequest(combinedRequest);
response.setContentType("application/json; charset=UTF-8");
- // Use the same logic as for determined roots
+ // Use the same logic as for determined UIs
BootstrapHandler bootstrapHandler = getBootstrapHandler();
BootstrapContext context = bootstrapHandler.createContext(
- combinedRequest, response, application, root.getRootId());
+ combinedRequest, response, application, uI.getUIId());
String widgetset = context.getWidgetsetName();
String theme = context.getThemeName();
String themeUri = bootstrapHandler.getThemeUri(context, theme);
- // TODO These are not required if it was only the init of the root
+ // TODO These are not required if it was only the init of the UI
// that was delayed
JSONObject params = new JSONObject();
params.put("widgetset", widgetset);
params.put("themeUri", themeUri);
- // Root id might have changed based on e.g. window.name
- params.put(ApplicationConstants.ROOT_ID_PARAMETER, root.getRootId());
+ // UI id might have changed based on e.g. window.name
+ params.put(UIConstants.UI_ID_PARAMETER, uI.getUIId());
if (sendUIDL) {
- String initialUIDL = getInitialUIDL(combinedRequest, root);
+ String initialUIDL = getInitialUIDL(combinedRequest, uI);
params.put("uidl", initialUIDL);
}
@@ -2456,7 +2460,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
// NOTE GateIn requires the buffers to be flushed to work
outWriter.flush();
out.flush();
- } catch (RootRequiresMoreInformationException e) {
+ } catch (UIRequiresMoreInformationException e) {
// Requiring more information at this point is not allowed
// TODO handle in a better way
throw new RuntimeException(e);
@@ -2472,24 +2476,24 @@ public abstract class AbstractCommunicationManager implements Serializable {
*
* @param request
* the request that caused the initialization
- * @param root
- * the root for which the UIDL should be generated
+ * @param uI
+ * the UI for which the UIDL should be generated
* @return a string with the initial UIDL message
* @throws PaintException
* if an exception occurs while painting
* @throws JSONException
* if an exception occurs while encoding output
*/
- protected String getInitialUIDL(WrappedRequest request, Root root)
+ protected String getInitialUIDL(WrappedRequest request, UI uI)
throws PaintException, JSONException {
// TODO maybe unify writeUidlResponse()?
StringWriter sWriter = new StringWriter();
PrintWriter pWriter = new PrintWriter(sWriter);
pWriter.print("{");
- if (isXSRFEnabled(root.getApplication())) {
+ if (isXSRFEnabled(uI.getApplication())) {
pWriter.print(getSecurityKeyUIDL(request));
}
- writeUidlResponse(request, true, pWriter, root, false);
+ writeUidlResponse(request, true, pWriter, uI, false);
pWriter.print("}");
String initialUIDL = sWriter.toString();
getLogger().log(Level.FINE, "Initial UIDL:" + initialUIDL);
@@ -2522,7 +2526,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
final String mimetype = response.getDeploymentConfiguration()
.getMimeType(resourceName);
- // Security check: avoid accidentally serving from the root of the
+ // Security check: avoid accidentally serving from the UI of the
// classpath instead of relative to the context class
if (resourceName.startsWith("/")) {
getLogger().warning(
@@ -2597,8 +2601,8 @@ public abstract class AbstractCommunicationManager implements Serializable {
/**
* Handles file upload request submitted via Upload component.
*
- * @param root
- * The root for this request
+ * @param UI
+ * The UI for this request
*
* @see #getStreamVariableTargetUrl(ReceiverOwner, String, StreamVariable)
*
@@ -2612,7 +2616,7 @@ public abstract class AbstractCommunicationManager implements Serializable {
throws IOException, InvalidUIDLSecurityKeyException {
/*
- * URI pattern: APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY] See
+ * URI pattern: APP/UPLOAD/[UIID]/[PID]/[NAME]/[SECKEY] See
* #createReceiverUrl
*/
@@ -2622,20 +2626,20 @@ public abstract class AbstractCommunicationManager implements Serializable {
.indexOf(ServletPortletHelper.UPLOAD_URL_PREFIX)
+ ServletPortletHelper.UPLOAD_URL_PREFIX.length();
String uppUri = pathInfo.substring(startOfData);
- String[] parts = uppUri.split("/", 4); // 0= rootid, 1 = cid, 2= name, 3
+ String[] parts = uppUri.split("/", 4); // 0= UIid, 1 = cid, 2= name, 3
// = sec key
- String rootId = parts[0];
+ String uiId = parts[0];
String connectorId = parts[1];
String variableName = parts[2];
- Root root = application.getRootById(Integer.parseInt(rootId));
- Root.setCurrent(root);
+ UI uI = application.getUIById(Integer.parseInt(uiId));
+ UI.setCurrent(uI);
StreamVariable streamVariable = getStreamVariable(connectorId,
variableName);
String secKey = streamVariableToSeckey.get(streamVariable);
if (secKey.equals(parts[3])) {
- ClientConnector source = getConnector(root, connectorId);
+ ClientConnector source = getConnector(uI, connectorId);
String contentType = request.getContentType();
if (contentType.contains("boundary")) {
// Multipart requests contain boundary string
@@ -2655,6 +2659,37 @@ public abstract class AbstractCommunicationManager implements Serializable {
}
+ /**
+ * Handles a heartbeat request. Heartbeat requests are periodically sent by
+ * the client-side to inform the server that the UI sending the heartbeat is
+ * still alive (the browser window is open, the connection is up) even when
+ * there are no UIDL requests for a prolonged period of time. UIs that do
+ * not receive either heartbeat or UIDL requests are eventually removed from
+ * the application and garbage collected.
+ *
+ * @param request
+ * @param response
+ * @param application
+ * @throws IOException
+ */
+ public void handleHeartbeatRequest(WrappedRequest request,
+ WrappedResponse response, Application application)
+ throws IOException {
+ UI ui = null;
+ try {
+ int uiId = Integer.parseInt(request
+ .getParameter(UIConstants.UI_ID_PARAMETER));
+ ui = application.getUIById(uiId);
+ } catch (NumberFormatException nfe) {
+ // null-check below handles this as well
+ }
+ if (ui != null) {
+ ui.setLastHeartbeatTime(System.currentTimeMillis());
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "UI not found");
+ }
+ }
+
public StreamVariable getStreamVariable(String connectorId,
String variableName) {
Map<String, StreamVariable> map = pidToNameToStreamVariable
diff --git a/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java b/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java
index ad5acad5e9..4052f5a400 100644
--- a/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java
+++ b/server/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java
@@ -33,6 +33,8 @@ public abstract class AbstractDeploymentConfiguration implements
private boolean productionMode;
private boolean xsrfProtectionEnabled;
private int resourceCacheTime;
+ private int heartbeatInterval;
+ private boolean idleRootCleanupEnabled;
public AbstractDeploymentConfiguration(Class<?> systemPropertyBaseClass,
Properties applicationProperties) {
@@ -42,12 +44,13 @@ public abstract class AbstractDeploymentConfiguration implements
checkProductionMode();
checkXsrfProtection();
checkResourceCacheTime();
+ checkHeartbeatInterval();
+ checkIdleUICleanup();
}
@Override
public String getApplicationOrSystemProperty(String propertyName,
String defaultValue) {
-
String val = null;
// Try application properties
@@ -163,22 +166,52 @@ public abstract class AbstractDeploymentConfiguration implements
return addonContext;
}
+ /**
+ * {@inheritDoc}
+ *
+ * The default is false.
+ */
@Override
public boolean isProductionMode() {
return productionMode;
}
+ /**
+ * {@inheritDoc}
+ *
+ * The default is true.
+ */
@Override
public boolean isXsrfProtectionEnabled() {
return xsrfProtectionEnabled;
}
+ /**
+ * {@inheritDoc}
+ *
+ * The default interval is 3600 seconds (1 hour).
+ */
@Override
public int getResourceCacheTime() {
return resourceCacheTime;
}
/**
+ * {@inheritDoc}
+ *
+ * The default interval is 300 seconds (5 minutes).
+ */
+ @Override
+ public int getHeartbeatInterval() {
+ return heartbeatInterval;
+ }
+
+ @Override
+ public boolean isIdleUICleanupEnabled() {
+ return idleRootCleanupEnabled;
+ }
+
+ /**
* Log a warning if Vaadin is not running in production mode.
*/
private void checkProductionMode() {
@@ -218,6 +251,24 @@ public abstract class AbstractDeploymentConfiguration implements
}
}
+ private void checkHeartbeatInterval() {
+ try {
+ heartbeatInterval = Integer
+ .parseInt(getApplicationOrSystemProperty(
+ Constants.SERVLET_PARAMETER_HEARTBEAT_RATE, "300"));
+ } catch (NumberFormatException e) {
+ getLogger().warning(
+ Constants.WARNING_HEARTBEAT_INTERVAL_NOT_NUMERIC);
+ heartbeatInterval = 300;
+ }
+ }
+
+ private void checkIdleUICleanup() {
+ idleRootCleanupEnabled = getApplicationOrSystemProperty(
+ Constants.SERVLET_PARAMETER_CLOSE_IDLE_UIS, "false").equals(
+ "true");
+ }
+
private Logger getLogger() {
return Logger.getLogger(getClass().getName());
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java b/server/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java
index 52885f3fbb..857c7c738c 100644
--- a/server/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java
+++ b/server/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java
@@ -20,7 +20,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import com.vaadin.Application;
-import com.vaadin.terminal.DefaultRootProvider;
+import com.vaadin.terminal.DefaultUIProvider;
import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException;
/**
@@ -70,7 +70,7 @@ public class ApplicationServlet extends AbstractApplicationServlet {
// Creates a new application instance
try {
final Application application = getApplicationClass().newInstance();
- application.addRootProvider(new DefaultRootProvider());
+ application.addUIProvider(new DefaultUIProvider());
return application;
} catch (final IllegalAccessException e) {
diff --git a/server/src/com/vaadin/terminal/gwt/server/BootstrapFragmentResponse.java b/server/src/com/vaadin/terminal/gwt/server/BootstrapFragmentResponse.java
index fabb69784f..6f69086523 100644
--- a/server/src/com/vaadin/terminal/gwt/server/BootstrapFragmentResponse.java
+++ b/server/src/com/vaadin/terminal/gwt/server/BootstrapFragmentResponse.java
@@ -48,17 +48,16 @@ public class BootstrapFragmentResponse extends BootstrapResponse {
* @param application
* the application for which the bootstrap page should be
* generated
- * @param rootId
- * the generated id of the Root that will be displayed on the
- * page
+ * @param uiId
+ * the generated id of the UI that will be displayed on the page
* @param fragmentNodes
* a mutable list containing the DOM nodes that will make up the
* application HTML
*/
public BootstrapFragmentResponse(BootstrapHandler handler,
- WrappedRequest request, Application application, Integer rootId,
+ WrappedRequest request, Application application, Integer uiId,
List<Node> fragmentNodes) {
- super(handler, request, application, rootId);
+ super(handler, request, application, uiId);
this.fragmentNodes = fragmentNodes;
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java b/server/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java
index fad80cacaa..02005e8d22 100644
--- a/server/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java
+++ b/server/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java
@@ -37,17 +37,18 @@ import org.jsoup.nodes.Node;
import org.jsoup.parser.Tag;
import com.vaadin.Application;
-import com.vaadin.RootRequiresMoreInformationException;
+import com.vaadin.UIRequiresMoreInformationException;
import com.vaadin.external.json.JSONException;
import com.vaadin.external.json.JSONObject;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.Version;
+import com.vaadin.shared.ui.ui.UIConstants;
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;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
public abstract class BootstrapHandler implements RequestHandler {
@@ -78,19 +79,19 @@ public abstract class BootstrapHandler implements RequestHandler {
return bootstrapResponse.getApplication();
}
- public Integer getRootId() {
- return bootstrapResponse.getRootId();
+ public Integer getUIId() {
+ return bootstrapResponse.getUIId();
}
- public Root getRoot() {
- return bootstrapResponse.getRoot();
+ public UI getUI() {
+ return bootstrapResponse.getUI();
}
public String getWidgetsetName() {
if (widgetsetName == null) {
- Root root = getRoot();
- if (root != null) {
- widgetsetName = getWidgetsetForRoot(this);
+ UI uI = getUI();
+ if (uI != null) {
+ widgetsetName = getWidgetsetForUI(this);
}
}
return widgetsetName;
@@ -98,8 +99,8 @@ public abstract class BootstrapHandler implements RequestHandler {
public String getThemeName() {
if (themeName == null) {
- Root root = getRoot();
- if (root != null) {
+ UI uI = getUI();
+ if (uI != null) {
themeName = findAndEscapeThemeName(this);
}
}
@@ -125,22 +126,22 @@ public abstract class BootstrapHandler implements RequestHandler {
throws IOException {
// TODO Should all urls be handled here?
- Integer rootId = null;
+ Integer uiId = null;
try {
- Root root = application.getRootForRequest(request);
- if (root == null) {
- writeError(response, new Throwable("No Root found"));
+ UI uI = application.getUIForRequest(request);
+ if (uI == null) {
+ writeError(response, new Throwable("No UI found"));
return true;
}
- rootId = Integer.valueOf(root.getRootId());
- } catch (RootRequiresMoreInformationException e) {
- // Just keep going without rootId
+ uiId = Integer.valueOf(uI.getUIId());
+ } catch (UIRequiresMoreInformationException e) {
+ // Just keep going without uiId
}
try {
BootstrapContext context = createContext(request, response,
- application, rootId);
+ application, uiId);
setupMainDiv(context);
BootstrapFragmentResponse fragmentResponse = context
@@ -170,8 +171,8 @@ public abstract class BootstrapHandler implements RequestHandler {
Map<String, Object> headers = new LinkedHashMap<String, Object>();
Document document = Document.createShell("");
BootstrapPageResponse pageResponse = new BootstrapPageResponse(
- this, request, context.getApplication(), context.getRootId(), document,
- headers);
+ this, request, context.getApplication(), context.getUIId(),
+ document, headers);
List<Node> fragmentNodes = fragmentResponse.getFragmentNodes();
Element body = document.body();
for (Node node : fragmentNodes) {
@@ -246,8 +247,8 @@ public abstract class BootstrapHandler implements RequestHandler {
head.appendElement("meta").attr("http-equiv", "X-UA-Compatible")
.attr("content", "chrome=1");
- Root root = context.getRoot();
- String title = ((root == null || root.getCaption() == null) ? "" : root
+ UI uI = context.getUI();
+ String title = ((uI == null || uI.getCaption() == null) ? "" : uI
.getCaption());
head.appendElement("title").appendText(title);
@@ -272,10 +273,10 @@ public abstract class BootstrapHandler implements RequestHandler {
}
public BootstrapContext createContext(WrappedRequest request,
- WrappedResponse response, Application application, Integer rootId) {
+ WrappedResponse response, Application application, Integer uiId) {
BootstrapContext context = new BootstrapContext(response,
- new BootstrapFragmentResponse(this, request,
- application, rootId, new ArrayList<Node>()));
+ new BootstrapFragmentResponse(this, request, application, uiId,
+ new ArrayList<Node>()));
return context;
}
@@ -293,11 +294,11 @@ public abstract class BootstrapHandler implements RequestHandler {
*/
protected abstract String getApplicationId(BootstrapContext context);
- public String getWidgetsetForRoot(BootstrapContext context) {
- Root root = context.getRoot();
+ public String getWidgetsetForUI(BootstrapContext context) {
+ UI uI = context.getUI();
WrappedRequest request = context.getRequest();
- String widgetset = root.getApplication().getWidgetsetForRoot(root);
+ String widgetset = uI.getApplication().getWidgetsetForUI(uI);
if (widgetset == null) {
widgetset = request.getDeploymentConfiguration()
.getConfiguredWidgetset(request);
@@ -417,12 +418,12 @@ public abstract class BootstrapHandler implements RequestHandler {
protected JSONObject getApplicationParameters(BootstrapContext context)
throws JSONException, PaintException {
Application application = context.getApplication();
- Integer rootId = context.getRootId();
+ Integer uiId = context.getUIId();
JSONObject appConfig = new JSONObject();
- if (rootId != null) {
- appConfig.put(ApplicationConstants.ROOT_ID_PARAMETER, rootId);
+ if (uiId != null) {
+ appConfig.put(UIConstants.UI_ID_PARAMETER, uiId);
}
if (context.getThemeName() != null) {
@@ -437,7 +438,7 @@ public abstract class BootstrapHandler implements RequestHandler {
appConfig.put("widgetset", context.getWidgetsetName());
- if (rootId == null || application.isRootInitPending(rootId.intValue())) {
+ if (uiId == null || application.isUIInitPending(uiId.intValue())) {
appConfig.put("initialPath", context.getRequest()
.getRequestPathInfo());
@@ -447,7 +448,7 @@ public abstract class BootstrapHandler implements RequestHandler {
} else {
// write the initial UIDL into the config
appConfig.put("uidl",
- getInitialUIDL(context.getRequest(), context.getRoot()));
+ getInitialUIDL(context.getRequest(), context.getUI()));
}
return appConfig;
@@ -500,6 +501,9 @@ public abstract class BootstrapHandler implements RequestHandler {
defaults.put("standalone", true);
}
+ defaults.put("heartbeatInterval",
+ deploymentConfiguration.getHeartbeatInterval());
+
defaults.put("appUri", getAppUri(context));
return defaults;
@@ -533,7 +537,7 @@ public abstract class BootstrapHandler implements RequestHandler {
* @return
*/
public String getThemeName(BootstrapContext context) {
- return context.getApplication().getThemeForRoot(context.getRoot());
+ return context.getApplication().getThemeForUI(context.getUI());
}
/**
@@ -568,15 +572,15 @@ public abstract class BootstrapHandler implements RequestHandler {
*
* @param request
* the originating request
- * @param root
- * the root for which the UIDL should be generated
+ * @param ui
+ * the UI for which the UIDL should be generated
* @return a string with the initial UIDL message
* @throws PaintException
* if an exception occurs while painting the components
* @throws JSONException
* if an exception occurs while formatting the output
*/
- protected abstract String getInitialUIDL(WrappedRequest request, Root root)
+ protected abstract String getInitialUIDL(WrappedRequest request, UI ui)
throws PaintException, JSONException;
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/BootstrapPageResponse.java b/server/src/com/vaadin/terminal/gwt/server/BootstrapPageResponse.java
index e7440f4c22..847578ef97 100644
--- a/server/src/com/vaadin/terminal/gwt/server/BootstrapPageResponse.java
+++ b/server/src/com/vaadin/terminal/gwt/server/BootstrapPageResponse.java
@@ -51,8 +51,8 @@ public class BootstrapPageResponse extends BootstrapResponse {
* @param application
* the application for which the bootstrap page should be
* generated
- * @param rootId
- * the generated id of the Root that will be displayed on the
+ * @param uiId
+ * the generated id of the UI that will be displayed on the
* page
* @param document
* the DOM document making up the HTML page
@@ -60,9 +60,9 @@ public class BootstrapPageResponse extends BootstrapResponse {
* a map into which header data can be added
*/
public BootstrapPageResponse(BootstrapHandler handler,
- WrappedRequest request, Application application, Integer rootId,
+ WrappedRequest request, Application application, Integer uiId,
Document document, Map<String, Object> headers) {
- super(handler, request, application, rootId);
+ super(handler, request, application, uiId);
this.headers = headers;
this.document = document;
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java b/server/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java
index 10f97e7e79..a422cba345 100644
--- a/server/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java
+++ b/server/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java
@@ -19,9 +19,9 @@ package com.vaadin.terminal.gwt.server;
import java.util.EventObject;
import com.vaadin.Application;
-import com.vaadin.RootRequiresMoreInformationException;
+import com.vaadin.UIRequiresMoreInformationException;
import com.vaadin.terminal.WrappedRequest;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
* Base class providing common functionality used in different bootstrap
@@ -33,7 +33,7 @@ import com.vaadin.ui.Root;
public abstract class BootstrapResponse extends EventObject {
private final WrappedRequest request;
private final Application application;
- private final Integer rootId;
+ private final Integer uiId;
/**
* Creates a new bootstrap event.
@@ -46,16 +46,15 @@ public abstract class BootstrapResponse extends EventObject {
* @param application
* the application for which the bootstrap page should be
* generated
- * @param rootId
- * the generated id of the Root that will be displayed on the
- * page
+ * @param uiId
+ * the generated id of the UI that will be displayed on the page
*/
public BootstrapResponse(BootstrapHandler handler, WrappedRequest request,
- Application application, Integer rootId) {
+ Application application, Integer uiId) {
super(handler);
this.request = request;
this.application = application;
- this.rootId = rootId;
+ this.uiId = uiId;
}
/**
@@ -91,32 +90,32 @@ public abstract class BootstrapResponse extends EventObject {
}
/**
- * Gets the root id that has been generated for this response. Please note
- * that if {@link Application#isRootPreserved()} is enabled, a previously
- * created Root with a different id might eventually end up being used.
+ * Gets the UI id that has been generated for this response. Please note
+ * that if {@link Application#isUiPreserved()} is enabled, a previously
+ * created UI with a different id might eventually end up being used.
*
- * @return the root id
+ * @return the UI id
*/
- public Integer getRootId() {
- return rootId;
+ public Integer getUIId() {
+ return uiId;
}
/**
- * Gets the Root for which this page is being rendered, if available. Some
- * features of the framework will postpone the Root selection until after
- * the bootstrap page has been rendered and required information from the
+ * Gets the UI for which this page is being rendered, if available. Some
+ * features of the framework will postpone the UI selection until after the
+ * bootstrap page has been rendered and required information from the
* browser has been sent back. This method will return <code>null</code> if
- * no Root instance is yet available.
+ * no UI instance is yet available.
*
- * @see Application#isRootPreserved()
- * @see Application#getRoot(WrappedRequest)
- * @see RootRequiresMoreInformationException
+ * @see Application#isUiPreserved()
+ * @see Application#getUI(WrappedRequest)
+ * @see UIRequiresMoreInformationException
*
- * @return The Root that will be displayed in the page being generated, or
+ * @return The UI that will be displayed in the page being generated, or
* <code>null</code> if all required information is not yet
* available.
*/
- public Root getRoot() {
- return Root.getCurrent();
+ public UI getUI() {
+ return UI.getCurrent();
}
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java b/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java
index 24675c9e45..c2fbbe37d4 100644
--- a/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java
+++ b/server/src/com/vaadin/terminal/gwt/server/ClientConnector.java
@@ -26,7 +26,7 @@ import com.vaadin.terminal.AbstractClientConnector;
import com.vaadin.terminal.Extension;
import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
* Interface implemented by all connectors that are capable of communicating
@@ -175,12 +175,12 @@ public interface ClientConnector extends Connector, RpcTarget {
public void removeExtension(Extension extension);
/**
- * Returns the root this connector is attached to
+ * Returns the UI this connector is attached to
*
- * @return The Root this connector is attached to or null if it is not
- * attached to any Root
+ * @return The UI this connector is attached to or null if it is not
+ * attached to any UI
*/
- public Root getRoot();
+ public UI getUI();
/**
* Called before the shared state and RPC invocations are sent to the
diff --git a/server/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java b/server/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java
index 25d0b23725..7cc5159bc0 100644
--- a/server/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java
+++ b/server/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java
@@ -34,7 +34,7 @@ public class ClientMethodInvocation implements Serializable,
private final Object[] parameters;
private Type[] parameterTypes;
- // used for sorting calls between different connectors in the same Root
+ // used for sorting calls between different connectors in the same UI
private final long sequenceNumber;
// TODO may cause problems when clustering etc.
private static long counter = 0;
diff --git a/server/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/server/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
index e0386b51b4..7551e849a1 100644
--- a/server/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
+++ b/server/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
@@ -25,7 +25,7 @@ import com.vaadin.Application;
import com.vaadin.external.json.JSONException;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.WrappedRequest;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
* Application manager processes changes and paints for single application
@@ -111,17 +111,17 @@ public class CommunicationManager extends AbstractCommunicationManager {
}
@Override
- protected String getInitialUIDL(WrappedRequest request, Root root)
+ protected String getInitialUIDL(WrappedRequest request, UI uI)
throws PaintException, JSONException {
- return CommunicationManager.this.getInitialUIDL(request, root);
+ return CommunicationManager.this.getInitialUIDL(request, uI);
}
};
}
@Override
- protected InputStream getThemeResourceAsStream(Root root, String themeName,
+ protected InputStream getThemeResourceAsStream(UI uI, String themeName,
String resource) {
- WebApplicationContext context = (WebApplicationContext) root
+ WebApplicationContext context = (WebApplicationContext) uI
.getApplication().getContext();
ServletContext servletContext = context.getHttpSession()
.getServletContext();
diff --git a/server/src/com/vaadin/terminal/gwt/server/Constants.java b/server/src/com/vaadin/terminal/gwt/server/Constants.java
index 78c043da69..9640216488 100644
--- a/server/src/com/vaadin/terminal/gwt/server/Constants.java
+++ b/server/src/com/vaadin/terminal/gwt/server/Constants.java
@@ -41,6 +41,12 @@ public interface Constants {
+ "in web.xml. The default of 1h will be used.\n"
+ "===========================================================";
+ static final String WARNING_HEARTBEAT_INTERVAL_NOT_NUMERIC = "\n"
+ + "===========================================================\n"
+ + "WARNING: heartbeatInterval has been set to a non integer value "
+ + "in web.xml. The default of 5min will be used.\n"
+ + "===========================================================";
+
static final String WIDGETSET_MISMATCH_INFO = "\n"
+ "=================================================================\n"
+ "The widgetset in use does not seem to be built for the Vaadin\n"
@@ -58,6 +64,8 @@ public interface Constants {
static final String SERVLET_PARAMETER_PRODUCTION_MODE = "productionMode";
static final String SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION = "disable-xsrf-protection";
static final String SERVLET_PARAMETER_RESOURCE_CACHE_TIME = "resourceCacheTime";
+ static final String SERVLET_PARAMETER_HEARTBEAT_RATE = "heartbeatRate";
+ static final String SERVLET_PARAMETER_CLOSE_IDLE_UIS = "closeIdleUIs";
// Configurable parameter names
static final String PARAMETER_VAADIN_RESOURCES = "Resources";
@@ -78,7 +86,7 @@ public interface Constants {
// Widget set parameter name
static final String PARAMETER_WIDGETSET = "widgetset";
- static final String ERROR_NO_ROOT_FOUND = "Application did not return a root for the request and did not request extra information either. Something is wrong.";
+ static final String ERROR_NO_UI_FOUND = "No UIProvider returned a UI for the request.";
static final String DEFAULT_THEME_NAME = "reindeer";
@@ -88,5 +96,4 @@ public interface Constants {
static final String PORTAL_PARAMETER_VAADIN_WIDGETSET = "vaadin.widgetset";
static final String PORTAL_PARAMETER_VAADIN_RESOURCE_PATH = "vaadin.resources.path";
static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme";
-
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java b/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java
index 221598171c..0106f466fc 100644
--- a/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java
+++ b/server/src/com/vaadin/terminal/gwt/server/DragAndDropService.java
@@ -40,7 +40,7 @@ import com.vaadin.terminal.Extension;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.VariableOwner;
import com.vaadin.ui.Component;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
public class DragAndDropService implements VariableOwner, ClientConnector {
@@ -327,7 +327,7 @@ public class DragAndDropService implements VariableOwner, ClientConnector {
}
@Override
- public Root getRoot() {
+ public UI getUI() {
return null;
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/EncodeResult.java b/server/src/com/vaadin/terminal/gwt/server/EncodeResult.java
new file mode 100644
index 0000000000..a62df2e632
--- /dev/null
+++ b/server/src/com/vaadin/terminal/gwt/server/EncodeResult.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+public class EncodeResult {
+ private final Object encodedValue;
+ private final Object diff;
+
+ public EncodeResult(Object encodedValue) {
+ this(encodedValue, null);
+ }
+
+ public EncodeResult(Object encodedValue, Object diff) {
+ this.encodedValue = encodedValue;
+ this.diff = diff;
+ }
+
+ public Object getEncodedValue() {
+ return encodedValue;
+ }
+
+ public Object getDiff() {
+ return diff;
+ }
+
+ public Object getDiffOrValue() {
+ Object diff = getDiff();
+ if (diff != null) {
+ return diff;
+ } else {
+ return getEncodedValue();
+ }
+ }
+}
diff --git a/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java
index 1eee9c4f52..3ba52a4e91 100644
--- a/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java
+++ b/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java
@@ -595,8 +595,9 @@ public class JsonCodec implements Serializable {
}
}
- public static Object encode(Object value, Object diffState, Type valueType,
- ConnectorTracker connectorTracker) throws JSONException {
+ public static EncodeResult encode(Object value, Object diffState,
+ Type valueType, ConnectorTracker connectorTracker)
+ throws JSONException {
if (valueType == null) {
throw new IllegalArgumentException("type must be defined");
@@ -617,37 +618,37 @@ public class JsonCodec implements Serializable {
for (int i = 0; i < array.length; ++i) {
jsonArray.put(array[i]);
}
- return jsonArray;
+ return new EncodeResult(jsonArray);
} else if (value instanceof String) {
- return value;
+ return new EncodeResult(value);
} else if (value instanceof Boolean) {
- return value;
+ return new EncodeResult(value);
} else if (value instanceof Number) {
- return value;
+ return new EncodeResult(value);
} else if (value instanceof Character) {
// Character is not a Number
- return value;
+ return new EncodeResult(value);
} else if (value instanceof Collection) {
Collection<?> collection = (Collection<?>) value;
JSONArray jsonArray = encodeCollection(valueType, collection,
connectorTracker);
- return jsonArray;
+ return new EncodeResult(jsonArray);
} else if (valueType instanceof Class<?>
&& ((Class<?>) valueType).isArray()) {
JSONArray jsonArray = encodeArrayContents(
((Class<?>) valueType).getComponentType(), value,
connectorTracker);
- return jsonArray;
+ return new EncodeResult(jsonArray);
} else if (valueType instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) valueType)
.getGenericComponentType();
JSONArray jsonArray = encodeArrayContents(componentType, value,
connectorTracker);
- return jsonArray;
+ return new EncodeResult(jsonArray);
} else if (value instanceof Map) {
Object jsonMap = encodeMap(valueType, (Map<?, ?>) value,
connectorTracker);
- return jsonMap;
+ return new EncodeResult(jsonMap);
} else if (value instanceof Connector) {
Connector connector = (Connector) value;
if (value instanceof Component
@@ -655,11 +656,11 @@ public class JsonCodec implements Serializable {
.isVisible((Component) value))) {
return encodeNull();
}
- return connector.getConnectorId();
+ return new EncodeResult(connector.getConnectorId());
} else if (value instanceof Enum) {
return encodeEnum((Enum<?>) value, connectorTracker);
} else if (value instanceof JSONArray || value instanceof JSONObject) {
- return value;
+ return new EncodeResult(value);
} else {
// Any object that we do not know how to encode we encode by looping
// through fields
@@ -667,8 +668,8 @@ public class JsonCodec implements Serializable {
}
}
- private static Object encodeNull() {
- return JSONObject.NULL;
+ private static EncodeResult encodeNull() {
+ return new EncodeResult(JSONObject.NULL);
}
public static Collection<BeanProperty> getProperties(Class<?> type)
@@ -681,9 +682,11 @@ public class JsonCodec implements Serializable {
return properties;
}
- private static Object encodeObject(Object value, JSONObject diffState,
- ConnectorTracker connectorTracker) throws JSONException {
- JSONObject jsonMap = new JSONObject();
+ private static EncodeResult encodeObject(Object value,
+ JSONObject referenceValue, ConnectorTracker connectorTracker)
+ throws JSONException {
+ JSONObject encoded = new JSONObject();
+ JSONObject diff = new JSONObject();
try {
for (BeanProperty property : getProperties(value.getClass())) {
@@ -692,49 +695,39 @@ public class JsonCodec implements Serializable {
// not support generics
Type fieldType = property.getType();
Object fieldValue = property.getValue(value);
- boolean equals = false;
- Object diffStateValue = null;
- if (diffState != null && diffState.has(fieldName)) {
- diffStateValue = diffState.get(fieldName);
- Object referenceFieldValue = decodeInternalOrCustomType(
- fieldType, diffStateValue, connectorTracker);
- if (JSONObject.NULL.equals(diffStateValue)) {
- diffStateValue = null;
- }
- equals = equals(fieldValue, referenceFieldValue);
+
+ if (encoded.has(fieldName)) {
+ throw new RuntimeException(
+ "Can't encode "
+ + value.getClass().getName()
+ + " as it has multiple fields with the name "
+ + fieldName.toLowerCase()
+ + ". This can happen if only casing distinguishes one property name from another.");
}
- if (!equals) {
- if (jsonMap.has(fieldName)) {
- throw new RuntimeException(
- "Can't encode "
- + value.getClass().getName()
- + " as it has multiple fields with the name "
- + fieldName.toLowerCase()
- + ". This can happen if only casing distinguishes one property name from another.");
- }
- jsonMap.put(
- fieldName,
- encode(fieldValue, diffStateValue, fieldType,
- connectorTracker));
- if (diffState != null) {
- diffState.put(
- fieldName,
- encode(fieldValue, null, fieldType,
- connectorTracker));
+
+ Object fieldReference;
+ if (referenceValue != null) {
+ fieldReference = referenceValue.get(fieldName);
+ if (JSONObject.NULL.equals(fieldReference)) {
+ fieldReference = null;
}
+ } else {
+ fieldReference = null;
+ }
+
+ EncodeResult encodeResult = encode(fieldValue, fieldReference,
+ fieldType, connectorTracker);
+ encoded.put(fieldName, encodeResult.getEncodedValue());
- // } else {
- // System.out.println("Skipping field " + fieldName
- // + " of type " + fieldType.getName()
- // + " for object " + value.getClass().getName()
- // + " as " + fieldValue + "==" + referenceFieldValue);
+ if (!jsonEquals(encodeResult.getEncodedValue(), fieldReference)) {
+ diff.put(fieldName, encodeResult.getDiffOrValue());
}
}
} catch (Exception e) {
// TODO: Should exceptions be handled in a different way?
throw new JSONException(e);
}
- return jsonMap;
+ return new EncodeResult(encoded, diff);
}
/**
@@ -744,21 +737,19 @@ public class JsonCodec implements Serializable {
* @param referenceValue
* @return
*/
- private static boolean equals(Object fieldValue, Object referenceValue) {
- if (fieldValue == null) {
- return referenceValue == null;
- }
-
- if (fieldValue.equals(referenceValue)) {
+ private static boolean jsonEquals(Object fieldValue, Object referenceValue) {
+ if (fieldValue == referenceValue) {
return true;
+ } else if (fieldValue == null || referenceValue == null) {
+ return false;
+ } else {
+ return fieldValue.toString().equals(referenceValue.toString());
}
-
- return false;
}
- private static String encodeEnum(Enum<?> e,
+ private static EncodeResult encodeEnum(Enum<?> e,
ConnectorTracker connectorTracker) throws JSONException {
- return e.name();
+ return new EncodeResult(e.name());
}
private static JSONArray encodeArrayContents(Type componentType,
@@ -766,8 +757,9 @@ public class JsonCodec implements Serializable {
throws JSONException {
JSONArray jsonArray = new JSONArray();
for (int i = 0; i < Array.getLength(array); i++) {
- jsonArray.put(encode(Array.get(array, i), null, componentType,
- connectorTracker));
+ EncodeResult encodeResult = encode(Array.get(array, i), null,
+ componentType, connectorTracker);
+ jsonArray.put(encodeResult.getEncodedValue());
}
return jsonArray;
}
@@ -788,7 +780,9 @@ public class JsonCodec implements Serializable {
Type childType = ((ParameterizedType) targetType)
.getActualTypeArguments()[typeIndex];
// Encode using the given type
- return encode(o, null, childType, connectorTracker);
+ EncodeResult encodeResult = encode(o, null, childType,
+ connectorTracker);
+ return encodeResult.getEncodedValue();
} else {
throw new JSONException("Collection is missing generics");
}
@@ -827,13 +821,13 @@ public class JsonCodec implements Serializable {
JSONArray values = new JSONArray();
for (Entry<?, ?> entry : map.entrySet()) {
- Object encodedKey = encode(entry.getKey(), null, keyType,
- connectorTracker);
- Object encodedValue = encode(entry.getValue(), null, valueType,
+ EncodeResult encodedKey = encode(entry.getKey(), null, keyType,
connectorTracker);
+ EncodeResult encodedValue = encode(entry.getValue(), null,
+ valueType, connectorTracker);
- keys.put(encodedKey);
- values.put(encodedValue);
+ keys.put(encodedKey.getEncodedValue());
+ values.put(encodedValue.getEncodedValue());
}
return new JSONArray(Arrays.asList(keys, values));
@@ -844,10 +838,13 @@ public class JsonCodec implements Serializable {
JSONObject jsonMap = new JSONObject();
for (Entry<?, ?> entry : map.entrySet()) {
- Connector key = (Connector) entry.getKey();
- Object encodedValue = encode(entry.getValue(), null, valueType,
- connectorTracker);
- jsonMap.put(key.getConnectorId(), encodedValue);
+ ClientConnector key = (ClientConnector) entry.getKey();
+ if (AbstractCommunicationManager.isVisible(key)) {
+ EncodeResult encodedValue = encode(entry.getValue(), null,
+ valueType, connectorTracker);
+ jsonMap.put(key.getConnectorId(),
+ encodedValue.getEncodedValue());
+ }
}
return jsonMap;
@@ -859,9 +856,9 @@ public class JsonCodec implements Serializable {
for (Entry<?, ?> entry : map.entrySet()) {
String key = (String) entry.getKey();
- Object encodedValue = encode(entry.getValue(), null, valueType,
- connectorTracker);
- jsonMap.put(key, encodedValue);
+ EncodeResult encodedValue = encode(entry.getValue(), null,
+ valueType, connectorTracker);
+ jsonMap.put(key, encodedValue.getEncodedValue());
}
return jsonMap;
diff --git a/server/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java b/server/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
index eba7d6e3a3..3e0f8d6b99 100644
--- a/server/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
+++ b/server/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
@@ -46,7 +46,7 @@ import javax.xml.namespace.QName;
import com.vaadin.Application;
import com.vaadin.terminal.ExternalResource;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
* TODO Write documentation, fix JavaDoc tags.
@@ -180,18 +180,18 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
}
}
- public void firePortletRenderRequest(Application app, Root root,
+ public void firePortletRenderRequest(Application app, UI uI,
RenderRequest request, RenderResponse response) {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
l.handleRenderRequest(request, new RestrictedRenderResponse(
- response), root);
+ response), uI);
}
}
}
- public void firePortletActionRequest(Application app, Root root,
+ public void firePortletActionRequest(Application app, UI uI,
ActionRequest request, ActionResponse response) {
String key = request.getParameter(ActionRequest.ACTION_NAME);
if (eventActionDestinationMap.containsKey(key)) {
@@ -213,28 +213,28 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
- l.handleActionRequest(request, response, root);
+ l.handleActionRequest(request, response, uI);
}
}
}
}
- public void firePortletEventRequest(Application app, Root root,
+ public void firePortletEventRequest(Application app, UI uI,
EventRequest request, EventResponse response) {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
- l.handleEventRequest(request, response, root);
+ l.handleEventRequest(request, response, uI);
}
}
}
- public void firePortletResourceRequest(Application app, Root root,
+ public void firePortletResourceRequest(Application app, UI uI,
ResourceRequest request, ResourceResponse response) {
Set<PortletListener> listeners = portletListeners.get(app);
if (listeners != null) {
for (PortletListener l : listeners) {
- l.handleResourceRequest(request, response, root);
+ l.handleResourceRequest(request, response, uI);
}
}
}
@@ -242,16 +242,16 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
public interface PortletListener extends Serializable {
public void handleRenderRequest(RenderRequest request,
- RenderResponse response, Root root);
+ RenderResponse response, UI uI);
public void handleActionRequest(ActionRequest request,
- ActionResponse response, Root root);
+ ActionResponse response, UI uI);
public void handleEventRequest(EventRequest request,
- EventResponse response, Root root);
+ EventResponse response, UI uI);
public void handleResourceRequest(ResourceRequest request,
- ResourceResponse response, Root root);
+ ResourceResponse response, UI uI);
}
/**
@@ -295,7 +295,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* Event names for events sent and received by a portlet need to be declared
* in portlet.xml .
*
- * @param root
+ * @param uI
* a window in which a temporary action URL can be opened if
* necessary
* @param name
@@ -304,7 +304,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* event value object that is Serializable and, if appropriate,
* has a valid JAXB annotation
*/
- public void sendPortletEvent(Root root, QName name, Serializable value)
+ public void sendPortletEvent(UI uI, QName name, Serializable value)
throws IllegalStateException {
if (response instanceof MimeResponse) {
String actionKey = "" + System.currentTimeMillis();
@@ -315,7 +315,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
if (actionUrl != null) {
eventActionDestinationMap.put(actionKey, name);
eventActionValueMap.put(actionKey, value);
- root.getPage().open(new ExternalResource(actionUrl.toString()));
+ uI.getPage().open(new ExternalResource(actionUrl.toString()));
} else {
// this should never happen as we already know the response is a
// MimeResponse
@@ -342,7 +342,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* Shared parameters set or read by a portlet need to be declared in
* portlet.xml .
*
- * @param root
+ * @param uI
* a window in which a temporary action URL can be opened if
* necessary
* @param name
@@ -350,7 +350,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* @param value
* parameter value
*/
- public void setSharedRenderParameter(Root root, String name, String value)
+ public void setSharedRenderParameter(UI uI, String name, String value)
throws IllegalStateException {
if (response instanceof MimeResponse) {
String actionKey = "" + System.currentTimeMillis();
@@ -361,7 +361,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
if (actionUrl != null) {
sharedParameterActionNameMap.put(actionKey, name);
sharedParameterActionValueMap.put(actionKey, value);
- root.getPage().open(new ExternalResource(actionUrl.toString()));
+ uI.getPage().open(new ExternalResource(actionUrl.toString()));
} else {
// this should never happen as we already know the response is a
// MimeResponse
@@ -381,7 +381,7 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
*
* Portlet modes used by a portlet need to be declared in portlet.xml .
*
- * @param root
+ * @param uI
* a window in which the render URL can be opened if necessary
* @param portletMode
* the portlet mode to switch to
@@ -389,13 +389,13 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
* if the portlet mode is not allowed for some reason
* (configuration, permissions etc.)
*/
- public void setPortletMode(Root root, PortletMode portletMode)
+ public void setPortletMode(UI uI, PortletMode portletMode)
throws IllegalStateException, PortletModeException {
if (response instanceof MimeResponse) {
PortletURL url = ((MimeResponse) response).createRenderURL();
url.setPortletMode(portletMode);
- throw new RuntimeException("Root.open has not yet been implemented");
- // root.open(new ExternalResource(url.toString()));
+ throw new RuntimeException("UI.open has not yet been implemented");
+ // UI.open(new ExternalResource(url.toString()));
} else if (response instanceof StateAwareResponse) {
((StateAwareResponse) response).setPortletMode(portletMode);
} else {
@@ -404,6 +404,11 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
}
}
+ @Override
+ public int getMaxInactiveInterval() {
+ return getPortletSession().getMaxInactiveInterval();
+ }
+
private Logger getLogger() {
return Logger.getLogger(PortletApplicationContext2.class.getName());
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/server/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
index b6fbbec298..e127425786 100644
--- a/server/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
+++ b/server/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
@@ -34,7 +34,7 @@ import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.WrappedResponse;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/**
* TODO document me!
@@ -142,10 +142,10 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
}
@Override
- protected String getInitialUIDL(WrappedRequest request, Root root)
+ protected String getInitialUIDL(WrappedRequest request, UI uI)
throws PaintException, JSONException {
return PortletCommunicationManager.this.getInitialUIDL(request,
- root);
+ uI);
}
@Override
@@ -168,9 +168,9 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
}
@Override
- protected InputStream getThemeResourceAsStream(Root root, String themeName,
+ protected InputStream getThemeResourceAsStream(UI uI, String themeName,
String resource) {
- PortletApplicationContext2 context = (PortletApplicationContext2) root
+ PortletApplicationContext2 context = (PortletApplicationContext2) uI
.getApplication().getContext();
PortletContext portletContext = context.getPortletSession()
.getPortletContext();
diff --git a/server/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java b/server/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java
index 200f9a9103..1d35785a57 100644
--- a/server/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java
+++ b/server/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java
@@ -6,10 +6,10 @@ import com.vaadin.Application;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.terminal.DeploymentConfiguration;
import com.vaadin.terminal.WrappedRequest;
-import com.vaadin.ui.Root;
+import com.vaadin.ui.UI;
/*
- * Copyright 2011 Vaadin Ltd.
+ * 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
@@ -43,14 +43,14 @@ class ServletPortletHelper implements Serializable {
throws ApplicationClassException {
String applicationParameter = deploymentConfiguration
.getInitParameters().getProperty("application");
- String rootParameter = deploymentConfiguration.getInitParameters()
- .getProperty(Application.ROOT_PARAMETER);
+ String uiParameter = deploymentConfiguration.getInitParameters()
+ .getProperty(Application.UI_PARAMETER);
ClassLoader classLoader = deploymentConfiguration.getClassLoader();
if (applicationParameter == null) {
// Validate the parameter value
- verifyRootClass(rootParameter, classLoader);
+ verifyUIClass(uiParameter, classLoader);
// Application can be used if a valid rootLayout is defined
return Application.class;
@@ -66,22 +66,22 @@ class ServletPortletHelper implements Serializable {
}
}
- private static void verifyRootClass(String className,
- ClassLoader classLoader) throws ApplicationClassException {
+ private static void verifyUIClass(String className, ClassLoader classLoader)
+ throws ApplicationClassException {
if (className == null) {
- throw new ApplicationClassException(Application.ROOT_PARAMETER
+ throw new ApplicationClassException(Application.UI_PARAMETER
+ " init parameter not defined");
}
- // Check that the root layout class can be found
+ // Check that the UI layout class can be found
try {
- Class<?> rootClass = classLoader.loadClass(className);
- if (!Root.class.isAssignableFrom(rootClass)) {
+ Class<?> uiClass = classLoader.loadClass(className);
+ if (!UI.class.isAssignableFrom(uiClass)) {
throw new ApplicationClassException(className
- + " does not implement Root");
+ + " does not implement UI");
}
// Try finding a default constructor, else throw exception
- rootClass.getConstructor();
+ uiClass.getConstructor();
} catch (ClassNotFoundException e) {
throw new ApplicationClassException(className
+ " could not be loaded", e);
@@ -129,4 +129,9 @@ class ServletPortletHelper implements Serializable {
return hasPathPrefix(request, ApplicationConstants.APP_REQUEST_PATH);
}
+ public static boolean isHeartbeatRequest(WrappedRequest request) {
+ return hasPathPrefix(request,
+ ApplicationConstants.HEARTBEAT_REQUEST_PATH);
+ }
+
}
diff --git a/server/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java b/server/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java
index 4cc0ed188d..bfcc0c1038 100644
--- a/server/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java
+++ b/server/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java
@@ -187,4 +187,8 @@ public class WebApplicationContext extends AbstractWebApplicationContext {
return mgr;
}
+ @Override
+ public int getMaxInactiveInterval() {
+ return getHttpSession().getMaxInactiveInterval();
+ }
}
diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java
index b1393488f7..a52a07f266 100644
--- a/server/src/com/vaadin/ui/AbstractComponent.java
+++ b/server/src/com/vaadin/ui/AbstractComponent.java
@@ -557,16 +557,6 @@ public abstract class AbstractComponent extends AbstractClientConnector
}
/*
- * Gets the parent window of the component. Don't add a JavaDoc comment
- * here, we use the default documentation from implemented interface.
- */
- @Override
- public Root getRoot() {
- // Just make method from implemented Component interface public
- return super.getRoot();
- }
-
- /*
* Notify the component that it's attached to a window. Don't add a JavaDoc
* comment here, we use the default documentation from implemented
* interface.
@@ -588,9 +578,9 @@ public abstract class AbstractComponent extends AbstractClientConnector
public void detach() {
super.detach();
if (actionManager != null) {
- // Remove any existing viewer. Root cast is just to make the
+ // Remove any existing viewer. UI cast is just to make the
// compiler happy
- actionManager.setViewer((Root) null);
+ actionManager.setViewer((UI) null);
}
}
@@ -601,7 +591,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
if (this instanceof Focusable) {
final Application app = getApplication();
if (app != null) {
- getRoot().setFocusedComponent((Focusable) this);
+ getUI().setFocusedComponent((Focusable) this);
delayedFocus = false;
} else {
delayedFocus = true;
@@ -1304,19 +1294,19 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Set a viewer for the action manager to be the parent sub window (if the
- * component is in a window) or the root (otherwise). This is still a
+ * component is in a window) or the UI (otherwise). This is still a
* simplification of the real case as this should be handled by the parent
* VOverlay (on the client side) if the component is inside an VOverlay
* component.
*/
private void setActionManagerViewer() {
- if (actionManager != null && getRoot() != null) {
+ if (actionManager != null && getUI() != null) {
// Attached and has action manager
Window w = findAncestor(Window.class);
if (w != null) {
actionManager.setViewer(w);
} else {
- actionManager.setViewer(getRoot());
+ actionManager.setViewer(getUI());
}
}
diff --git a/server/src/com/vaadin/ui/AbstractEmbedded.java b/server/src/com/vaadin/ui/AbstractEmbedded.java
new file mode 100644
index 0000000000..9396af5c44
--- /dev/null
+++ b/server/src/com/vaadin/ui/AbstractEmbedded.java
@@ -0,0 +1,84 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.ui;
+
+import com.vaadin.shared.ui.AbstractEmbeddedState;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.gwt.server.ResourceReference;
+
+/**
+ * Abstract base for embedding components.
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+@SuppressWarnings("serial")
+public abstract class AbstractEmbedded extends AbstractComponent {
+
+ @Override
+ public AbstractEmbeddedState getState() {
+ return (AbstractEmbeddedState) super.getState();
+ }
+
+ /**
+ * Sets the object source resource. The dimensions are assumed if possible.
+ * The type is guessed from resource.
+ *
+ * @param source
+ * the source to set.
+ */
+ public void setSource(Resource source) {
+ if (source == null) {
+ getState().setSource(null);
+ } else {
+ getState().setSource(new ResourceReference(source));
+ }
+ requestRepaint();
+ }
+
+ /**
+ * Get the object source resource.
+ *
+ * @return the source
+ */
+ public Resource getSource() {
+ ResourceReference ref = ((ResourceReference) getState().getSource());
+ if (ref == null) {
+ return null;
+ } else {
+ return ref.getResource();
+ }
+ }
+
+ /**
+ * Sets this component's alternate text that can be presented instead of the
+ * component's normal content for accessibility purposes.
+ *
+ * @param altText
+ * A short, human-readable description of this component's
+ * content.
+ */
+ public void setAlternateText(String altText) {
+ if (altText != getState().getAlternateText()
+ || (altText != null && !altText.equals(getState()
+ .getAlternateText()))) {
+ getState().setAlternateText(altText);
+ requestRepaint();
+ }
+ }
+
+ /**
+ * Gets this component's alternate text that can be presented instead of the
+ * component's normal content for accessibility purposes.
+ *
+ * @returns Alternate text
+ */
+ public String getAlternateText() {
+ return getState().getAlternateText();
+ }
+
+}
diff --git a/server/src/com/vaadin/ui/Button.java b/server/src/com/vaadin/ui/Button.java
index 8546d8f830..68b9f1392f 100644
--- a/server/src/com/vaadin/ui/Button.java
+++ b/server/src/com/vaadin/ui/Button.java
@@ -472,6 +472,10 @@ public class Button extends AbstractComponent implements
* Determines if a button is automatically disabled when clicked. If this is
* set to true the button will be automatically disabled when clicked,
* typically to prevent (accidental) extra clicks on a button.
+ * <p>
+ * Note that this is only used when the click comes from the user, not when
+ * calling {@link #click()}.
+ * </p>
*
* @param disableOnClick
* true to disable button when it is clicked, false otherwise
diff --git a/server/src/com/vaadin/ui/Component.java b/server/src/com/vaadin/ui/Component.java
index 89e282d4e1..400dd66cac 100644
--- a/server/src/com/vaadin/ui/Component.java
+++ b/server/src/com/vaadin/ui/Component.java
@@ -507,18 +507,18 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
public void setIcon(Resource icon);
/**
- * Gets the Root the component is attached to.
+ * Gets the UI the component is attached to.
*
* <p>
- * If the component is not attached to a Root through a component
+ * If the component is not attached to a UI through a component
* containment hierarchy, <code>null</code> is returned.
* </p>
*
- * @return the Root of the component or <code>null</code> if it is not
- * attached to a Root
+ * @return the UI of the component or <code>null</code> if it is not
+ * attached to a UI
*/
@Override
- public Root getRoot();
+ public UI getUI();
/**
* Gets the application object to which the component is attached.
@@ -548,7 +548,7 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
* <p>
* Reimplementing the {@code attach()} method is useful for tasks that need
* to get a reference to the parent, window, or application object with the
- * {@link #getParent()}, {@link #getRoot()}, and {@link #getApplication()}
+ * {@link #getParent()}, {@link #getUI()}, and {@link #getApplication()}
* methods. A component does not yet know these objects in the constructor,
* so in such case, the methods will return {@code null}. For example, the
* following is invalid:
@@ -574,8 +574,8 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
* {@link #setParent(Component)}.
* </p>
* <p>
- * This method must call {@link Root#componentAttached(Component)} to let
- * the Root know that a new Component has been attached.
+ * This method must call {@link UI#componentAttached(Component)} to let
+ * the UI know that a new Component has been attached.
* </p>
*
*
diff --git a/server/src/com/vaadin/ui/ConnectorTracker.java b/server/src/com/vaadin/ui/ConnectorTracker.java
index 72879e0a25..b44189f838 100644
--- a/server/src/com/vaadin/ui/ConnectorTracker.java
+++ b/server/src/com/vaadin/ui/ConnectorTracker.java
@@ -26,11 +26,12 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import com.vaadin.terminal.AbstractClientConnector;
+import com.vaadin.terminal.gwt.server.AbstractCommunicationManager;
import com.vaadin.terminal.gwt.server.ClientConnector;
/**
* A class which takes care of book keeping of {@link ClientConnector}s for a
- * Root.
+ * UI.
* <p>
* Provides {@link #getConnector(String)} which can be used to lookup a
* connector from its id. This is for framework use only and should not be
@@ -54,7 +55,7 @@ public class ConnectorTracker implements Serializable {
private Set<ClientConnector> dirtyConnectors = new HashSet<ClientConnector>();
private Set<ClientConnector> uninitializedConnectors = new HashSet<ClientConnector>();
- private Root root;
+ private UI uI;
private Map<ClientConnector, Object> diffStates = new HashMap<ClientConnector, Object>();
/**
@@ -68,15 +69,15 @@ public class ConnectorTracker implements Serializable {
}
/**
- * Creates a new ConnectorTracker for the given root. A tracker is always
- * attached to a root and the root cannot be changed during the lifetime of
- * a {@link ConnectorTracker}.
+ * Creates a new ConnectorTracker for the given uI. A tracker is always
+ * attached to a uI and the uI cannot be changed during the lifetime of a
+ * {@link ConnectorTracker}.
*
- * @param root
- * The root to attach to. Cannot be null.
+ * @param uI
+ * The uI to attach to. Cannot be null.
*/
- public ConnectorTracker(Root root) {
- this.root = root;
+ public ConnectorTracker(UI uI) {
+ this.uI = uI;
}
/**
@@ -210,8 +211,8 @@ public class ConnectorTracker implements Serializable {
while (iterator.hasNext()) {
String connectorId = iterator.next();
ClientConnector connector = connectorIdToConnector.get(connectorId);
- if (getRootForConnector(connector) != root) {
- // If connector is no longer part of this root,
+ if (getUIForConnector(connector) != uI) {
+ // If connector is no longer part of this uI,
// remove it from the map. If it is re-attached to the
// application at some point it will be re-added through
// registerConnector(connector)
@@ -226,28 +227,36 @@ public class ConnectorTracker implements Serializable {
uninitializedConnectors.remove(connector);
diffStates.remove(connector);
iterator.remove();
+ } else if (!AbstractCommunicationManager.isVisible(connector)
+ && !uninitializedConnectors.contains(connector)) {
+ uninitializedConnectors.add(connector);
+ diffStates.remove(connector);
+ getLogger().fine(
+ "cleanConnectorMap removed state for "
+ + getConnectorAndParentInfo(connector)
+ + " as it is not visible");
}
}
}
/**
- * Finds the root that the connector is attached to.
+ * Finds the uI that the connector is attached to.
*
* @param connector
* The connector to lookup
- * @return The root the connector is attached to or null if it is not
- * attached to any root.
+ * @return The uI the connector is attached to or null if it is not attached
+ * to any uI.
*/
- private Root getRootForConnector(ClientConnector connector) {
+ private UI getUIForConnector(ClientConnector connector) {
if (connector == null) {
return null;
}
if (connector instanceof Component) {
- return ((Component) connector).getRoot();
+ return ((Component) connector).getUI();
}
- return getRootForConnector(connector.getParent());
+ return getUIForConnector(connector.getParent());
}
/**
@@ -330,15 +339,15 @@ public class ConnectorTracker implements Serializable {
}
/**
- * Mark all connectors in this root as dirty.
+ * Mark all connectors in this uI as dirty.
*/
public void markAllConnectorsDirty() {
- markConnectorsDirtyRecursively(root);
+ markConnectorsDirtyRecursively(uI);
getLogger().fine("All connectors are now dirty");
}
/**
- * Mark all connectors in this root as clean.
+ * Mark all connectors in this uI as clean.
*/
public void markAllConnectorsClean() {
dirtyConnectors.clear();
@@ -370,7 +379,7 @@ public class ConnectorTracker implements Serializable {
* client in the following request.
* </p>
*
- * @return A collection of all dirty connectors for this root. This list may
+ * @return A collection of all dirty connectors for this uI. This list may
* contain invisible connectors.
*/
public Collection<ClientConnector> getDirtyConnectors() {
diff --git a/server/src/com/vaadin/ui/EmbeddedBrowser.java b/server/src/com/vaadin/ui/EmbeddedBrowser.java
new file mode 100644
index 0000000000..4e2ae18de8
--- /dev/null
+++ b/server/src/com/vaadin/ui/EmbeddedBrowser.java
@@ -0,0 +1,19 @@
+package com.vaadin.ui;
+
+import com.vaadin.shared.ui.embeddedbrowser.EmbeddedBrowserState;
+
+/**
+ * Component for embedding browser "iframe".
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+public class EmbeddedBrowser extends AbstractEmbedded {
+
+ @Override
+ public EmbeddedBrowserState getState() {
+ return (EmbeddedBrowserState) super.getState();
+ }
+}
diff --git a/server/src/com/vaadin/ui/Flash.java b/server/src/com/vaadin/ui/Flash.java
new file mode 100644
index 0000000000..0e6cf63a91
--- /dev/null
+++ b/server/src/com/vaadin/ui/Flash.java
@@ -0,0 +1,136 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.ui;
+
+import java.util.HashMap;
+
+import com.vaadin.shared.ui.flash.FlashState;
+
+/**
+ * Component for embedding flash objects.
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+@SuppressWarnings("serial")
+public class Flash extends AbstractEmbedded {
+
+ @Override
+ public FlashState getState() {
+ return (FlashState) super.getState();
+ }
+
+ /**
+ * This attribute specifies the base path used to resolve relative URIs
+ * specified by the classid, data, and archive attributes. When absent, its
+ * default value is the base URI of the current document.
+ *
+ * @param codebase
+ * The base path
+ */
+ public void setCodebase(String codebase) {
+ if (codebase != getState().getCodebase()
+ || (codebase != null && !codebase.equals(getState()
+ .getCodebase()))) {
+ getState().setCodebase(codebase);
+ requestRepaint();
+ }
+ }
+
+ /**
+ * This attribute specifies the content type of data expected when
+ * downloading the object specified by classid. This attribute is optional
+ * but recommended when classid is specified since it allows the user agent
+ * to avoid loading information for unsupported content types. When absent,
+ * it defaults to the value of the type attribute.
+ *
+ * @param codetype
+ * the codetype to set.
+ */
+ public void setCodetype(String codetype) {
+ if (codetype != getState().getCodetype()
+ || (codetype != null && !codetype.equals(getState()
+ .getCodetype()))) {
+ getState().setCodetype(codetype);
+ requestRepaint();
+ }
+ }
+
+ /**
+ * This attribute may be used to specify a space-separated list of URIs for
+ * archives containing resources relevant to the object, which may include
+ * the resources specified by the classid and data attributes. Preloading
+ * archives will generally result in reduced load times for objects.
+ * Archives specified as relative URIs should be interpreted relative to the
+ * codebase attribute.
+ *
+ * @param archive
+ * Space-separated list of URIs with resources relevant to the
+ * object
+ */
+ public void setArchive(String archive) {
+ if (archive != getState().getArchive()
+ || (archive != null && !archive.equals(getState().getArchive()))) {
+ getState().setArchive(archive);
+ requestRepaint();
+ }
+ }
+
+ public void setStandby(String standby) {
+ if (standby != getState().getStandby()
+ || (standby != null && !standby.equals(getState().getStandby()))) {
+ getState().setStandby(standby);
+ requestRepaint();
+ }
+ }
+
+ /**
+ * Sets an object parameter. Parameters are optional information, and they
+ * are passed to the instantiated object. Parameters are are stored as name
+ * value pairs. This overrides the previous value assigned to this
+ * parameter.
+ *
+ * @param name
+ * the name of the parameter.
+ * @param value
+ * the value of the parameter.
+ */
+ public void setParameter(String name, String value) {
+ if (getState().getEmbedParams() == null) {
+ getState().setEmbedParams(new HashMap<String, String>());
+ }
+ getState().getEmbedParams().put(name, value);
+ requestRepaint();
+ }
+
+ /**
+ * Gets the value of an object parameter. Parameters are optional
+ * information, and they are passed to the instantiated object. Parameters
+ * are are stored as name value pairs.
+ *
+ * @return the Value of parameter or null if not found.
+ */
+ public String getParameter(String name) {
+ return getState().getEmbedParams() != null ? getState()
+ .getEmbedParams().get(name) : null;
+ }
+
+ /**
+ * Removes an object parameter from the list.
+ *
+ * @param name
+ * the name of the parameter to remove.
+ */
+ public void removeParameter(String name) {
+ if (getState().getEmbedParams() == null) {
+ return;
+ }
+ getState().getEmbedParams().remove(name);
+ requestRepaint();
+ }
+
+}
diff --git a/server/src/com/vaadin/ui/Image.java b/server/src/com/vaadin/ui/Image.java
new file mode 100644
index 0000000000..b0dbc9e629
--- /dev/null
+++ b/server/src/com/vaadin/ui/Image.java
@@ -0,0 +1,94 @@
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.ui;
+
+import com.vaadin.event.MouseEvents.ClickEvent;
+import com.vaadin.event.MouseEvents.ClickListener;
+import com.vaadin.shared.EventId;
+import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.ui.image.ImageServerRpc;
+import com.vaadin.shared.ui.image.ImageState;
+import com.vaadin.terminal.Resource;
+
+/**
+ * Component for embedding images.
+ *
+ * @author Vaadin Ltd.
+ * @version
+ * @VERSION@
+ * @since 7.0
+ */
+@SuppressWarnings("serial")
+public class Image extends AbstractEmbedded {
+
+ protected ImageServerRpc rpc = new ImageServerRpc() {
+ @Override
+ public void click(MouseEventDetails mouseDetails) {
+ fireEvent(new ClickEvent(Image.this, mouseDetails));
+ }
+ };
+
+ /**
+ * Creates a new empty Image.
+ */
+ public Image() {
+ registerRpc(rpc);
+ }
+
+ /**
+ * Creates a new empty Image with caption.
+ *
+ * @param caption
+ */
+ public Image(String caption) {
+ this();
+ setCaption(caption);
+ }
+
+ /**
+ * Creates a new Image whose contents is loaded from given resource. The
+ * dimensions are assumed if possible. The type is guessed from resource.
+ *
+ * @param caption
+ * @param source
+ * the Source of the embedded object.
+ */
+ public Image(String caption, Resource source) {
+ this(caption);
+ setSource(source);
+ }
+
+ @Override
+ public ImageState getState() {
+ return (ImageState) super.getState();
+ }
+
+ /**
+ * Add a click listener to the component. The listener is called whenever
+ * the user clicks inside the component. Depending on the content the event
+ * may be blocked and in that case no event is fired.
+ *
+ * Use {@link #removeListener(ClickListener)} to remove the listener.
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addListener(ClickListener listener) {
+ addListener(EventId.CLICK_EVENT_IDENTIFIER, ClickEvent.class, listener,
+ ClickListener.clickMethod);
+ }
+
+ /**
+ * Remove a click listener from the component. The listener should earlier
+ * have been added using {@link #addListener(ClickListener)}.
+ *
+ * @param listener
+ * The listener to remove
+ */
+ public void removeListener(ClickListener listener) {
+ removeListener(EventId.CLICK_EVENT_IDENTIFIER, ClickEvent.class,
+ listener);
+ }
+}
diff --git a/server/src/com/vaadin/ui/LoginForm.java b/server/src/com/vaadin/ui/LoginForm.java
index bb7767084c..1c154699d8 100644
--- a/server/src/com/vaadin/ui/LoginForm.java
+++ b/server/src/com/vaadin/ui/LoginForm.java
@@ -99,8 +99,8 @@ public class LoginForm extends CustomComponent {
throws IOException {
String requestPathInfo = request.getRequestPathInfo();
if ("/loginHandler".equals(requestPathInfo)) {
- // Ensure Root.getCurrent() works in listeners
- Root.setCurrent(getRoot());
+ // Ensure UI.getCurrent() works in listeners
+ UI.setCurrent(getUI());
response.setCacheTime(-1);
response.setContentType("text/html; charset=utf-8");
diff --git a/server/src/com/vaadin/ui/Select.java b/server/src/com/vaadin/ui/Select.java
index 20345b55e0..6ff7c9c9bc 100644
--- a/server/src/com/vaadin/ui/Select.java
+++ b/server/src/com/vaadin/ui/Select.java
@@ -654,7 +654,7 @@ public class Select extends AbstractSelect implements AbstractSelect.Filtering,
if (filterstring != null) {
filterstring = filterstring.toLowerCase();
}
- optionRepaint();
+ requestRepaint();
} else if (isNewItemsAllowed()) {
// New option entered (and it is allowed)
final String newitem = (String) variables.get("newitem");
@@ -682,18 +682,6 @@ public class Select extends AbstractSelect implements AbstractSelect.Filtering,
}
@Override
- public void markAsDirty() {
- super.markAsDirty();
- optionRequest = false;
- prevfilterstring = filterstring;
- filterstring = null;
- }
-
- private void optionRepaint() {
- super.markAsDirty();
- }
-
- @Override
public void setFilteringMode(int filteringMode) {
this.filteringMode = filteringMode;
}
diff --git a/server/src/com/vaadin/ui/Slider.java b/server/src/com/vaadin/ui/Slider.java
index d4e2db4853..a0b1d01b01 100644
--- a/server/src/com/vaadin/ui/Slider.java
+++ b/server/src/com/vaadin/ui/Slider.java
@@ -16,11 +16,9 @@
package com.vaadin.ui;
-import java.util.Map;
-
-import com.vaadin.terminal.PaintException;
-import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.Vaadin6Component;
+import com.vaadin.shared.ui.slider.SliderOrientation;
+import com.vaadin.shared.ui.slider.SliderServerRpc;
+import com.vaadin.shared.ui.slider.SliderState;
/**
* A component for selecting a numerical value within a range.
@@ -41,9 +39,9 @@ import com.vaadin.terminal.Vaadin6Component;
* vl.addComponent(volumeIndicator);
* volumeIndicator.setValue("Current volume:" + 50.0);
* slider.addListener(this);
- *
+ *
* }
- *
+ *
* public void setVolume(double d) {
* volumeIndicator.setValue("Current volume: " + d);
* }
@@ -58,28 +56,29 @@ import com.vaadin.terminal.Vaadin6Component;
*
* @author Vaadin Ltd.
*/
-public class Slider extends AbstractField<Double> implements Vaadin6Component {
-
- public static final int ORIENTATION_HORIZONTAL = 0;
-
- public static final int ORIENTATION_VERTICAL = 1;
+public class Slider extends AbstractField<Double> {
- /** Minimum value of slider */
- private double min = 0;
+ private SliderServerRpc rpc = new SliderServerRpc() {
- /** Maximum value of slider */
- private double max = 100;
+ @Override
+ public void valueChanged(double value) {
- /**
- * Resolution, how many digits are considered relevant after the decimal
- * point. Must be a non-negative value
- */
- private int resolution = 0;
+ try {
+ setValue(value, true);
+ } catch (final ValueOutOfBoundsException e) {
+ // Convert to nearest bound
+ double out = e.getValue().doubleValue();
+ if (out < getState().getMinValue()) {
+ out = getState().getMinValue();
+ }
+ if (out > getState().getMaxValue()) {
+ out = getState().getMaxValue();
+ }
+ Slider.super.setValue(new Double(out), false);
+ }
+ }
- /**
- * Slider orientation (horizontal/vertical), defaults .
- */
- private int orientation = ORIENTATION_HORIZONTAL;
+ };
/**
* Default slider constructor. Sets all values to defaults and the slide
@@ -88,7 +87,8 @@ public class Slider extends AbstractField<Double> implements Vaadin6Component {
*/
public Slider() {
super();
- super.setValue(new Double(min));
+ registerRpc(rpc);
+ super.setValue(new Double(getState().getMinValue()));
}
/**
@@ -153,13 +153,18 @@ public class Slider extends AbstractField<Double> implements Vaadin6Component {
setCaption(caption);
}
+ @Override
+ public SliderState getState() {
+ return (SliderState) super.getState();
+ }
+
/**
* Gets the maximum slider value
*
* @return the largest value the slider can have
*/
public double getMax() {
- return max;
+ return getState().getMaxValue();
}
/**
@@ -170,11 +175,10 @@ public class Slider extends AbstractField<Double> implements Vaadin6Component {
* The new maximum slider value
*/
public void setMax(double max) {
- this.max = max;
+ getState().setMaxValue(max);
if (getValue() > max) {
setValue(max);
}
- markAsDirty();
}
/**
@@ -183,7 +187,7 @@ public class Slider extends AbstractField<Double> implements Vaadin6Component {
* @return the smallest value the slider can have
*/
public double getMin() {
- return min;
+ return getState().getMinValue();
}
/**
@@ -194,33 +198,32 @@ public class Slider extends AbstractField<Double> implements Vaadin6Component {
* The new minimum slider value
*/
public void setMin(double min) {
- this.min = min;
+ getState().setMinValue(min);
if (getValue() < min) {
setValue(min);
}
- markAsDirty();
}
/**
* Get the current orientation of the slider (horizontal or vertical).
*
- * @return {@link #ORIENTATION_HORIZONTAL} or
- * {@link #ORIENTATION_HORIZONTAL}
+ * @return {@link SliderOrientation#HORIZONTAL} or
+ * {@link SliderOrientation#VERTICAL}
*/
- public int getOrientation() {
- return orientation;
+ public SliderOrientation getOrientation() {
+ return getState().getOrientation();
}
/**
* Set the orientation of the slider.
*
- * @param The
- * new orientation, either {@link #ORIENTATION_HORIZONTAL} or
- * {@link #ORIENTATION_VERTICAL}
+ * @param orientation
+ * The new orientation, either
+ * {@link SliderOrientation#HORIZONTAL} or
+ * {@link SliderOrientation#VERTICAL}
*/
- public void setOrientation(int orientation) {
- this.orientation = orientation;
- markAsDirty();
+ public void setOrientation(SliderOrientation orientation) {
+ getState().setOrientation(orientation);
}
/**
@@ -230,21 +233,24 @@ public class Slider extends AbstractField<Double> implements Vaadin6Component {
* @return resolution
*/
public int getResolution() {
- return resolution;
+ return getState().getResolution();
}
/**
* Set a new resolution for the slider. The resolution is the number of
* digits after the decimal point.
*
+ * @throws IllegalArgumentException
+ * if resolution is negative.
+ *
* @param resolution
*/
public void setResolution(int resolution) {
if (resolution < 0) {
- return;
+ throw new IllegalArgumentException(
+ "Cannot set a negative resolution to Slider");
}
- this.resolution = resolution;
- markAsDirty();
+ getState().setResolution(resolution);
}
/**
@@ -261,87 +267,36 @@ public class Slider extends AbstractField<Double> implements Vaadin6Component {
@Override
protected void setValue(Double value, boolean repaintIsNotNeeded) {
final double v = value.doubleValue();
+ final int resolution = getResolution();
double newValue;
+
if (resolution > 0) {
// Round up to resolution
newValue = (int) (v * Math.pow(10, resolution));
newValue = newValue / Math.pow(10, resolution);
- if (min > newValue || max < newValue) {
+ if (getMin() > newValue || getMax() < newValue) {
throw new ValueOutOfBoundsException(value);
}
} else {
newValue = (int) v;
- if (min > newValue || max < newValue) {
+ if (getMin() > newValue || getMax() < newValue) {
throw new ValueOutOfBoundsException(value);
}
}
+
+ getState().setValue(newValue);
super.setValue(newValue, repaintIsNotNeeded);
}
@Override
- public void setValue(Object newFieldValue)
- throws com.vaadin.data.Property.ReadOnlyException {
- if (newFieldValue != null && newFieldValue instanceof Number
- && !(newFieldValue instanceof Double)) {
+ public void setValue(Object newFieldValue) {
+ if (newFieldValue instanceof Number) {
// Support setting all types of Numbers
newFieldValue = ((Number) newFieldValue).doubleValue();
}
-
- super.setValue(newFieldValue);
- }
-
- @Override
- public void paintContent(PaintTarget target) throws PaintException {
-
- target.addAttribute("min", min);
- if (max > min) {
- target.addAttribute("max", max);
- } else {
- target.addAttribute("max", min);
- }
- target.addAttribute("resolution", resolution);
-
- if (resolution > 0) {
- target.addVariable(this, "value", getValue().doubleValue());
- } else {
- target.addVariable(this, "value", getValue().intValue());
- }
-
- if (orientation == ORIENTATION_VERTICAL) {
- target.addAttribute("vertical", true);
- }
-
- }
-
- /**
- * Invoked when the value of a variable has changed. Slider listeners are
- * notified if the slider value has changed.
- *
- * @param source
- * @param variables
- */
- @Override
- public void changeVariables(Object source, Map<String, Object> variables) {
- if (variables.containsKey("value")) {
- final Object value = variables.get("value");
- final Double newValue = new Double(value.toString());
- if (newValue != null && newValue != getValue()
- && !newValue.equals(getValue())) {
- try {
- setValue(newValue, true);
- } catch (final ValueOutOfBoundsException e) {
- // Convert to nearest bound
- double out = e.getValue().doubleValue();
- if (out < min) {
- out = min;
- }
- if (out > max) {
- out = max;
- }
- super.setValue(new Double(out), false);
- }
- }
- }
+ setValue(newFieldValue);
+ // The cast is safe if the above call returned without throwing
+ getState().setValue((Double) newFieldValue);
}
/**
@@ -373,7 +328,6 @@ public class Slider extends AbstractField<Double> implements Vaadin6Component {
public Double getValue() {
return value;
}
-
}
@Override
diff --git a/server/src/com/vaadin/ui/Root.java b/server/src/com/vaadin/ui/UI.java
index 67f2e04a65..17a028bcdf 100644
--- a/server/src/com/vaadin/ui/Root.java
+++ b/server/src/com/vaadin/ui/UI.java
@@ -16,11 +16,13 @@
package com.vaadin.ui;
+import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.EventListener;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -35,9 +37,9 @@ import com.vaadin.event.MouseEvents.ClickListener;
import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.BorderStyle;
-import com.vaadin.shared.ui.root.RootConstants;
-import com.vaadin.shared.ui.root.RootServerRpc;
-import com.vaadin.shared.ui.root.RootState;
+import com.vaadin.shared.ui.ui.UIConstants;
+import com.vaadin.shared.ui.ui.UIServerRpc;
+import com.vaadin.shared.ui.ui.UIState;
import com.vaadin.terminal.Page;
import com.vaadin.terminal.Page.BrowserWindowResizeEvent;
import com.vaadin.terminal.Page.BrowserWindowResizeListener;
@@ -47,27 +49,28 @@ import com.vaadin.terminal.Resource;
import com.vaadin.terminal.Vaadin6Component;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.terminal.WrappedRequest.BrowserDetails;
-import com.vaadin.ui.Window.CloseListener;
+import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;
+import com.vaadin.tools.ReflectTools;
/**
- * The topmost component in any component hierarchy. There is one root for every
- * Vaadin instance in a browser window. A root may either represent an entire
+ * The topmost component in any component hierarchy. There is one UI for every
+ * Vaadin instance in a browser window. A UI may either represent an entire
* browser window (or tab) or some part of a html page where a Vaadin
* application is embedded.
* <p>
- * The root is the server side entry point for various client side features that
+ * The UI is the server side entry point for various client side features that
* are not represented as components added to a layout, e.g notifications, sub
* windows, and executing javascript in the browser.
* </p>
* <p>
- * When a new application instance is needed, typically because the user opens
- * the application in a browser window,
- * {@link Application#gerRoot(WrappedRequest)} is invoked to get a root. That
- * method does by default create a root according to the
- * {@value Application#ROOT_PARAMETER} parameter from web.xml.
+ * When a new UI instance is needed, typically because the user opens a URL in a
+ * browser window which points to {@link AbstractApplicationServlet},
+ * {@link Application#getUIForRequest(WrappedRequest)} is invoked to get a UI.
+ * That method does by default create a UI according to the
+ * {@value Application#UI_PARAMETER} parameter from web.xml.
* </p>
* <p>
- * After a root has been created by the application, it is initialized using
+ * After a UI has been created by the application, it is initialized using
* {@link #init(WrappedRequest)}. This method is intended to be overridden by
* the developer to add components to the user interface and initialize
* non-component functionality. The component hierarchy is initialized by
@@ -76,27 +79,27 @@ import com.vaadin.ui.Window.CloseListener;
* </p>
* <p>
* If a {@link EagerInit} annotation is present on a class extending
- * <code>Root</code>, the framework will use a faster initialization method
- * which will not ensure that {@link BrowserDetails} are present in the
+ * <code>UI</code>, the framework will use a faster initialization method which
+ * will not ensure that {@link BrowserDetails} are present in the
* {@link WrappedRequest} passed to the init method.
* </p>
*
* @see #init(WrappedRequest)
- * @see Application#getRoot(WrappedRequest)
+ * @see Application#getUI(WrappedRequest)
*
* @since 7.0
*/
-public abstract class Root extends AbstractComponentContainer implements
+public abstract class UI extends AbstractComponentContainer implements
Action.Container, Action.Notifier, Vaadin6Component {
/**
- * Helper class to emulate the main window from Vaadin 6 using roots. This
+ * Helper class to emulate the main window from Vaadin 6 using UIs. This
* class should be used in the same way as Window used as a browser level
* window in Vaadin 6 with {@link com.vaadin.Application.LegacyApplication}
*/
@Deprecated
@EagerInit
- public static class LegacyWindow extends Root {
+ public static class LegacyWindow extends UI {
private String name;
/**
@@ -210,11 +213,11 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Opens the given resource in this root. The contents of this Root is
+ * Opens the given resource in this UI. The contents of this UI is
* replaced by the {@code Resource}.
*
* @param resource
- * the resource to show in this root
+ * the resource to show in this UI
*
* @deprecated As of 7.0, use getPage().open instead
*/
@@ -294,9 +297,9 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Adds a new {@link BrowserWindowResizeListener} to this root. The
+ * Adds a new {@link BrowserWindowResizeListener} to this UI. The
* listener will be notified whenever the browser window within which
- * this root resides is resized.
+ * this UI resides is resized.
*
* @param resizeListener
* the listener to add
@@ -312,7 +315,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Removes a {@link BrowserWindowResizeListener} from this root. The
+ * Removes a {@link BrowserWindowResizeListener} from this UI. The
* listener will no longer be notified when the browser window is
* resized.
*
@@ -326,7 +329,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Gets the last known height of the browser window in which this root
+ * Gets the last known height of the browser window in which this UI
* resides.
*
* @return the browser window height in pixels
@@ -338,7 +341,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Gets the last known width of the browser window in which this root
+ * Gets the last known width of the browser window in which this UI
* resides.
*
* @return the browser window width in pixels
@@ -389,12 +392,48 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * The application to which this root belongs
+ * Event fired when a UI is removed from the application.
+ */
+ public static class CloseEvent extends Event {
+
+ private static final String CLOSE_EVENT_IDENTIFIER = "uiClose";
+
+ public CloseEvent(UI source) {
+ super(source);
+ }
+
+ public UI getUI() {
+ return (UI) getSource();
+ }
+ }
+
+ /**
+ * Interface for listening {@link UI.CloseEvent UI close events}.
+ *
+ */
+ public interface CloseListener extends EventListener {
+
+ public static final Method closeMethod = ReflectTools.findMethod(
+ CloseListener.class, "click", CloseEvent.class);
+
+ /**
+ * Called when a CloseListener is notified of a CloseEvent.
+ * {@link UI#getCurrent()} returns <code>event.getUI()</code> within
+ * this method.
+ *
+ * @param event
+ * The close event that was fired.
+ */
+ public void close(CloseEvent event);
+ }
+
+ /**
+ * The application to which this UI belongs
*/
private Application application;
/**
- * List of windows in this root.
+ * List of windows in this UI.
*/
private final LinkedHashSet<Window> windows = new LinkedHashSet<Window>();
@@ -405,13 +444,13 @@ public abstract class Root extends AbstractComponentContainer implements
private Component scrollIntoView;
/**
- * The id of this root, used to find the server side instance of the root
- * form which a request originates. A negative value indicates that the root
- * id has not yet been assigned by the Application.
+ * The id of this UI, used to find the server side instance of the UI form
+ * which a request originates. A negative value indicates that the UI id has
+ * not yet been assigned by the Application.
*
- * @see Application#nextRootId
+ * @see Application#nextUIId
*/
- private int rootId = -1;
+ private int uiId = -1;
/**
* Keeps track of the Actions added to this component, and manages the
@@ -420,19 +459,19 @@ public abstract class Root extends AbstractComponentContainer implements
protected ActionManager actionManager;
/**
- * Thread local for keeping track of the current root.
+ * Thread local for keeping track of the current UI.
*/
- private static final ThreadLocal<Root> currentRoot = new ThreadLocal<Root>();
+ private static final ThreadLocal<UI> currentUI = new ThreadLocal<UI>();
/** Identifies the click event */
private ConnectorTracker connectorTracker = new ConnectorTracker(this);
private Page page = new Page(this);
- private RootServerRpc rpc = new RootServerRpc() {
+ private UIServerRpc rpc = new UIServerRpc() {
@Override
public void click(MouseEventDetails mouseDetails) {
- fireEvent(new ClickEvent(Root.this, mouseDetails));
+ fireEvent(new ClickEvent(UI.this, mouseDetails));
}
@Override
@@ -444,80 +483,89 @@ public abstract class Root extends AbstractComponentContainer implements
};
/**
- * Creates a new empty root without a caption. This root will have a
+ * Timestamp keeping track of the last heartbeat of this UI. Updated to the
+ * current time whenever the application receives a heartbeat or UIDL
+ * request from the client for this UI.
+ */
+ private long lastHeartbeat = System.currentTimeMillis();
+
+ private long lastUidlRequest = System.currentTimeMillis();
+
+ /**
+ * Creates a new empty UI without a caption. This UI will have a
* {@link VerticalLayout} with margins enabled as its content.
*/
- public Root() {
+ public UI() {
this((ComponentContainer) null);
}
/**
- * Creates a new root with the given component container as its content.
+ * Creates a new UI with the given component container as its content.
*
* @param content
- * the content container to use as this roots content.
+ * the content container to use as this UIs content.
*
* @see #setContent(ComponentContainer)
*/
- public Root(ComponentContainer content) {
+ public UI(ComponentContainer content) {
registerRpc(rpc);
setSizeFull();
setContent(content);
}
/**
- * Creates a new empty root with the given caption. This root will have a
+ * Creates a new empty UI with the given caption. This UI will have a
* {@link VerticalLayout} with margins enabled as its content.
*
* @param caption
- * the caption of the root, used as the page title if there's
+ * the caption of the UI, used as the page title if there's
* nothing but the application on the web page
*
* @see #setCaption(String)
*/
- public Root(String caption) {
+ public UI(String caption) {
this((ComponentContainer) null);
setCaption(caption);
}
/**
- * Creates a new root with the given caption and content.
+ * Creates a new UI with the given caption and content.
*
* @param caption
- * the caption of the root, used as the page title if there's
+ * the caption of the UI, used as the page title if there's
* nothing but the application on the web page
* @param content
- * the content container to use as this roots content.
+ * the content container to use as this UIs content.
*
* @see #setContent(ComponentContainer)
* @see #setCaption(String)
*/
- public Root(String caption, ComponentContainer content) {
+ public UI(String caption, ComponentContainer content) {
this(content);
setCaption(caption);
}
@Override
- protected RootState getState() {
- return (RootState) super.getState();
+ protected UIState getState() {
+ return (UIState) super.getState();
}
@Override
- public Class<? extends RootState> getStateType() {
+ public Class<? extends UIState> getStateType() {
// This is a workaround for a problem with creating the correct state
// object during build
- return RootState.class;
+ return UIState.class;
}
/**
* Overridden to return a value instead of referring to the parent.
*
- * @return this root
+ * @return this UI
*
- * @see com.vaadin.ui.AbstractComponent#getRoot()
+ * @see com.vaadin.ui.AbstractComponent#getUI()
*/
@Override
- public Root getRoot() {
+ public UI getUI() {
return this;
}
@@ -542,9 +590,9 @@ public abstract class Root extends AbstractComponentContainer implements
if (pendingFocus != null) {
// ensure focused component is still attached to this main window
- if (pendingFocus.getRoot() == this
- || (pendingFocus.getRoot() != null && pendingFocus
- .getRoot().getParent() == this)) {
+ if (pendingFocus.getUI() == this
+ || (pendingFocus.getUI() != null && pendingFocus.getUI()
+ .getParent() == this)) {
target.addAttribute("focused", pendingFocus);
}
pendingFocus = null;
@@ -555,7 +603,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
if (isResizeLazy()) {
- target.addAttribute(RootConstants.RESIZE_LAZY, true);
+ target.addAttribute(UIConstants.RESIZE_LAZY, true);
}
}
@@ -571,6 +619,16 @@ public abstract class Root extends AbstractComponentContainer implements
fireEvent(new ClickEvent(this, mouseDetails));
}
+ /**
+ * For internal use only.
+ */
+ public void fireCloseEvent() {
+ UI current = UI.getCurrent();
+ UI.setCurrent(this);
+ fireEvent(new CloseEvent(this));
+ UI.setCurrent(current);
+ }
+
@Override
@SuppressWarnings("unchecked")
public void changeVariables(Object source, Map<String, Object> variables) {
@@ -584,9 +642,9 @@ public abstract class Root extends AbstractComponentContainer implements
actionManager.handleActions(variables, this);
}
- if (variables.containsKey(RootConstants.FRAGMENT_VARIABLE)) {
+ if (variables.containsKey(UIConstants.FRAGMENT_VARIABLE)) {
String fragment = (String) variables
- .get(RootConstants.FRAGMENT_VARIABLE);
+ .get(UIConstants.FRAGMENT_VARIABLE);
getPage().setFragment(fragment, true);
}
}
@@ -622,7 +680,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Sets the application to which this root is assigned. It is not legal to
+ * Sets the application to which this UI is assigned. It is not legal to
* change the application once it has been set nor to set a
* <code>null</code> application.
* <p>
@@ -652,46 +710,46 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Sets the id of this root within its application. The root id is used to
- * route requests to the right root.
+ * Sets the id of this UI within its application. The UI id is used to route
+ * requests to the right UI.
* <p>
* This method is mainly intended for internal use by the framework.
* </p>
*
- * @param rootId
- * the id of this root
+ * @param uiId
+ * the id of this UI
*
* @throws IllegalStateException
- * if the root id has already been set
+ * if the UI id has already been set
*
- * @see #getRootId()
+ * @see #getUIId()
*/
- public void setRootId(int rootId) {
- if (this.rootId != -1) {
- throw new IllegalStateException("Root id has already been defined");
+ public void setUIId(int uiId) {
+ if (this.uiId != -1) {
+ throw new IllegalStateException("UI id has already been defined");
}
- this.rootId = rootId;
+ this.uiId = uiId;
}
/**
- * Gets the id of the root, used to identify this root within its
- * application when processing requests. The root id should be present in
- * every request to the server that originates from this root.
- * {@link Application#getRootForRequest(WrappedRequest)} uses this id to
- * find the route to which the request belongs.
+ * Gets the id of the UI, used to identify this UI within its application
+ * when processing requests. The UI id should be present in every request to
+ * the server that originates from this UI.
+ * {@link Application#getUIForRequest(WrappedRequest)} uses this id to find
+ * the route to which the request belongs.
*
* @return
*/
- public int getRootId() {
- return rootId;
+ public int getUIId() {
+ return uiId;
}
/**
- * Adds a window as a subwindow inside this root. To open a new browser
- * window or tab, you should instead use {@link open(Resource)} with an url
+ * Adds a window as a subwindow inside this UI. To open a new browser window
+ * or tab, you should instead use {@link open(Resource)} with an url
* pointing to this application and ensure
- * {@link Application#getRoot(WrappedRequest)} returns an appropriate root
- * for the request.
+ * {@link Application#getUI(WrappedRequest)} returns an appropriate UI for
+ * the request.
*
* @param window
* @throws IllegalArgumentException
@@ -727,7 +785,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Remove the given subwindow from this root.
+ * Remove the given subwindow from this UI.
*
* Since Vaadin 6.5, {@link CloseListener}s are called also when explicitly
* removing a window by calling this method.
@@ -741,7 +799,7 @@ public abstract class Root extends AbstractComponentContainer implements
*/
public boolean removeWindow(Window window) {
if (!windows.remove(window)) {
- // Window window is not a subwindow of this root.
+ // Window window is not a subwindow of this UI.
return false;
}
window.setParent(null);
@@ -752,7 +810,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Gets all the windows added to this root.
+ * Gets all the windows added to this UI.
*
* @return an unmodifiable collection of windows
*/
@@ -792,28 +850,28 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Scrolls any component between the component and root to a suitable
- * position so the component is visible to the user. The given component
- * must belong to this root.
+ * Scrolls any component between the component and UI to a suitable position
+ * so the component is visible to the user. The given component must belong
+ * to this UI.
*
* @param component
* the component to be scrolled into view
* @throws IllegalArgumentException
- * if {@code component} does not belong to this root
+ * if {@code component} does not belong to this UI
*/
public void scrollIntoView(Component component)
throws IllegalArgumentException {
- if (component.getRoot() != this) {
+ if (component.getUI() != this) {
throw new IllegalArgumentException(
- "The component where to scroll must belong to this root.");
+ "The component where to scroll must belong to this UI.");
}
scrollIntoView = component;
markAsDirty();
}
/**
- * Gets the content of this root. The content is a component container that
- * serves as the outermost item of the visual contents of this root.
+ * Gets the content of this UI. The content is a component container that
+ * serves as the outermost item of the visual contents of this UI.
*
* @return a component container to use as content
*
@@ -837,15 +895,15 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Sets the content of this root. The content is a component container that
- * serves as the outermost item of the visual contents of this root. If no
+ * Sets the content of this UI. The content is a component container that
+ * serves as the outermost item of the visual contents of this UI. If no
* content has been set, a {@link VerticalLayout} with margins enabled will
* be used by default - see {@link #createDefaultLayout()}. The content can
* also be set in a constructor.
*
* @return a component container to use as content
*
- * @see #Root(ComponentContainer)
+ * @see #UI(ComponentContainer)
* @see #createDefaultLayout()
*/
public void setContent(ComponentContainer content) {
@@ -863,11 +921,11 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Adds a component to this root. The component is not added directly to the
- * root, but instead to the content container ({@link #getContent()}).
+ * Adds a component to this UI. The component is not added directly to the
+ * UI, but instead to the content container ({@link #getContent()}).
*
* @param component
- * the component to add to this root
+ * the component to add to this UI
*
* @see #getContent()
*/
@@ -878,7 +936,7 @@ public abstract class Root extends AbstractComponentContainer implements
/**
* This implementation removes the component from the content container (
- * {@link #getContent()}) instead of from the actual root.
+ * {@link #getContent()}) instead of from the actual UI.
*/
@Override
public void removeComponent(Component component) {
@@ -887,7 +945,7 @@ public abstract class Root extends AbstractComponentContainer implements
/**
* This implementation removes the components from the content container (
- * {@link #getContent()}) instead of from the actual root.
+ * {@link #getContent()}) instead of from the actual UI.
*/
@Override
public void removeAllComponents() {
@@ -910,56 +968,55 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Initializes this root. This method is intended to be overridden by
+ * Initializes this UI. This method is intended to be overridden by
* subclasses to build the view and configure non-component functionality.
* Performing the initialization in a constructor is not suggested as the
- * state of the root is not properly set up when the constructor is invoked.
+ * state of the UI is not properly set up when the constructor is invoked.
* <p>
* The {@link WrappedRequest} can be used to get information about the
- * request that caused this root to be created. By default, the
+ * request that caused this UI to be created. By default, the
* {@link BrowserDetails} will be available in the request. If the browser
* details are not required, loading the application in the browser can take
* some shortcuts giving a faster initial rendering. This can be indicated
- * by adding the {@link EagerInit} annotation to the Root class.
+ * by adding the {@link EagerInit} annotation to the UI class.
* </p>
*
* @param request
- * the wrapped request that caused this root to be created
+ * the wrapped request that caused this UI to be created
*/
protected abstract void init(WrappedRequest request);
/**
- * Sets the thread local for the current root. This method is used by the
+ * Sets the thread local for the current UI. This method is used by the
* framework to set the current application whenever a new request is
* processed and it is cleared when the request has been processed.
* <p>
* The application developer can also use this method to define the current
- * root outside the normal request handling, e.g. when initiating custom
+ * UI outside the normal request handling, e.g. when initiating custom
* background threads.
* </p>
*
- * @param root
- * the root to register as the current root
+ * @param uI
+ * the UI to register as the current UI
*
* @see #getCurrent()
* @see ThreadLocal
*/
- public static void setCurrent(Root root) {
- currentRoot.set(root);
+ public static void setCurrent(UI ui) {
+ currentUI.set(ui);
}
/**
- * Gets the currently used root. The current root is automatically defined
- * when processing requests to the server. In other cases, (e.g. from
- * background threads), the current root is not automatically defined.
+ * Gets the currently used UI. The current UI is automatically defined when
+ * processing requests to the server. In other cases, (e.g. from background
+ * threads), the current UI is not automatically defined.
*
- * @return the current root instance if available, otherwise
- * <code>null</code>
+ * @return the current UI instance if available, otherwise <code>null</code>
*
- * @see #setCurrent(Root)
+ * @see #setCurrent(UI)
*/
- public static Root getCurrent() {
- return currentRoot.get();
+ public static UI getCurrent() {
+ return currentUI.get();
}
public void setScrollTop(int scrollTop) {
@@ -1027,10 +1084,10 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Add a click listener to the Root. The listener is called whenever the
- * user clicks inside the Root. Also when the click targets a component
- * inside the Root, provided the targeted component does not prevent the
- * click event from propagating.
+ * Add a click listener to the UI. The listener is called whenever the user
+ * clicks inside the UI. Also when the click targets a component inside the
+ * UI, provided the targeted component does not prevent the click event from
+ * propagating.
*
* Use {@link #removeListener(ClickListener)} to remove the listener.
*
@@ -1043,7 +1100,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Remove a click listener from the Root. The listener should earlier have
+ * Remove a click listener from the UI. The listener should earlier have
* been added using {@link #addListener(ClickListener)}.
*
* @param listener
@@ -1054,9 +1111,33 @@ public abstract class Root extends AbstractComponentContainer implements
listener);
}
+ /**
+ * Adds a close listener to the UI. The listener is called when the UI is
+ * removed from the application.
+ *
+ * @param listener
+ * The listener to add.
+ */
+ public void addListener(CloseListener listener) {
+ addListener(CloseEvent.CLOSE_EVENT_IDENTIFIER, CloseEvent.class,
+ listener, CloseListener.closeMethod);
+ }
+
+ /**
+ * Removes a close listener from the UI if it has previously been added with
+ * {@link #addListener(ClickListener)}. Otherwise, has no effect.
+ *
+ * @param listener
+ * The listener to remove.
+ */
+ public void removeListener(CloseListener listener) {
+ removeListener(CloseEvent.CLOSE_EVENT_IDENTIFIER, CloseEvent.class,
+ listener);
+ }
+
@Override
public boolean isConnectorEnabled() {
- // TODO How can a Root be invisible? What does it mean?
+ // TODO How can a UI be invisible? What does it mean?
return isVisible() && isEnabled();
}
@@ -1069,7 +1150,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Setting the caption of a Root is not supported. To set the title of the
+ * Setting the caption of a UI is not supported. To set the title of the
* HTML page, use Page.setTitle
*
* @deprecated as of 7.0.0, use {@link Page#setTitle(String)}
@@ -1078,11 +1159,11 @@ public abstract class Root extends AbstractComponentContainer implements
@Deprecated
public void setCaption(String caption) {
throw new IllegalStateException(
- "You can not set the title of a Root. To set the title of the HTML page, use Page.setTitle");
+ "You can not set the title of a UI. To set the title of the HTML page, use Page.setTitle");
}
/**
- * Shows a notification message on the middle of the root. The message
+ * Shows a notification message on the middle of the UI. The message
* automatically disappears ("humanized message").
*
* Care should be taken to to avoid XSS vulnerabilities as the caption is
@@ -1105,7 +1186,7 @@ public abstract class Root extends AbstractComponentContainer implements
}
/**
- * Shows a notification message the root. The position and behavior of the
+ * Shows a notification message the UI. The position and behavior of the
* message depends on the type, which is one of the basic types defined in
* {@link Notification}, for instance Notification.TYPE_WARNING_MESSAGE.
*
@@ -1132,8 +1213,8 @@ public abstract class Root extends AbstractComponentContainer implements
/**
* Shows a notification consisting of a bigger caption and a smaller
- * description on the middle of the root. The message automatically
- * disappears ("humanized message").
+ * description on the middle of the UI. The message automatically disappears
+ * ("humanized message").
*
* Care should be taken to to avoid XSS vulnerabilities as the caption and
* description are rendered as html.
@@ -1238,4 +1319,43 @@ public abstract class Root extends AbstractComponentContainer implements
getPage().showNotification(notification);
}
+ /**
+ * Returns the timestamp (milliseconds since the epoch) of the last received
+ * heartbeat for this UI.
+ *
+ * @see #heartbeat()
+ * @see Application#closeInactiveUIs()
+ *
+ * @return The time the last heartbeat request occurred.
+ */
+ public long getLastHeartbeatTime() {
+ return lastHeartbeat;
+ }
+
+ /**
+ * Returns the timestamp (milliseconds since the epoch) of the last received
+ * UIDL request for this UI.
+ *
+ * @return
+ */
+ public long getLastUidlRequestTime() {
+ return lastUidlRequest;
+ }
+
+ /**
+ * Sets the last heartbeat request timestamp for this UI. Called by the
+ * framework whenever the application receives a valid heartbeat request for
+ * this UI.
+ */
+ public void setLastHeartbeatTime(long lastHeartbeat) {
+ this.lastHeartbeat = lastHeartbeat;
+ }
+
+ /**
+ * Sets the last UIDL request timestamp for this UI. Called by the framework
+ * whenever the application receives a valid UIDL request for this UI.
+ */
+ public void setLastUidlRequestTime(long lastUidlRequest) {
+ this.lastUidlRequest = lastUidlRequest;
+ }
}
diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java
index d79588cc63..6102350566 100644
--- a/server/src/com/vaadin/ui/Window.java
+++ b/server/src/com/vaadin/ui/Window.java
@@ -40,8 +40,8 @@ import com.vaadin.terminal.Vaadin6Component;
/**
* A component that represents a floating popup window that can be added to a
- * {@link Root}. A window is added to a {@code Root} using
- * {@link Root#addWindow(Window)}. </p>
+ * {@link UI}. A window is added to a {@code UI} using
+ * {@link UI#addWindow(Window)}. </p>
* <p>
* The contents of a window is set using {@link #setContent(ComponentContainer)}
* or by using the {@link #Window(String, ComponentContainer)} constructor. The
@@ -57,7 +57,7 @@ import com.vaadin.terminal.Vaadin6Component;
* </p>
* <p>
* In Vaadin versions prior to 7.0.0, Window was also used as application level
- * windows. This function is now covered by the {@link Root} class.
+ * windows. This function is now covered by the {@link UI} class.
* </p>
*
* @author Vaadin Ltd.
@@ -222,14 +222,14 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
* </p>
*/
public void close() {
- Root root = getRoot();
+ UI uI = getUI();
- // Don't do anything if not attached to a root
- if (root != null) {
+ // Don't do anything if not attached to a UI
+ if (uI != null) {
// focus is restored to the parent window
- root.focus();
- // subwindow is removed from the root
- root.removeWindow(this);
+ uI.focus();
+ // subwindow is removed from the UI
+ uI.removeWindow(this);
}
}
@@ -470,22 +470,22 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
* If there are currently several windows visible, calling this method makes
* this window topmost.
* <p>
- * This method can only be called if this window connected a root. Else an
+ * This method can only be called if this window connected a UI. Else an
* illegal state exception is thrown. Also if there are modal windows and
* this window is not modal, and illegal state exception is thrown.
* <p>
*/
public void bringToFront() {
- Root root = getRoot();
- if (root == null) {
+ UI uI = getUI();
+ if (uI == null) {
throw new IllegalStateException(
"Window must be attached to parent before calling bringToFront method.");
}
int maxBringToFront = -1;
- for (Window w : root.getWindows()) {
+ for (Window w : uI.getWindows()) {
if (!isModal() && w.isModal()) {
throw new IllegalStateException(
- "The root contains modal windows, non-modal window cannot be brought to front.");
+ "The UI contains modal windows, non-modal window cannot be brought to front.");
}
if (w.bringToFront != null) {
maxBringToFront = Math.max(maxBringToFront,