diff options
author | Leif Åstrand <leif@vaadin.com> | 2013-06-07 14:12:41 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2013-06-07 14:12:41 +0300 |
commit | 808b65581554dad8b670538b1830a8f90b3db5db (patch) | |
tree | f2323317e420e7c76b17994660cdbbd0f78145b4 /server/src/com/vaadin/ui/UI.java | |
parent | fe8d330c3c9f2ae2c0ace28fa5c34e5b2b131112 (diff) | |
parent | b0574f7b33c4d3d437c8c11cd53389e5522f6999 (diff) | |
download | vaadin-framework-808b65581554dad8b670538b1830a8f90b3db5db.tar.gz vaadin-framework-808b65581554dad8b670538b1830a8f90b3db5db.zip |
Merge changes from origin/7.1
2772641 OSGi support for vaadin-push (#11691)
42c4b20 Use "\0" instead of "|" as a push message delimiter (#11692)
778de06 Derive current servlet/portlet from the current service (#11779)
f8fb8b7 Upgrade to Atmosphere 1.0.13 (#11861)
fea4c5e Don't build and publish sources for package without source files
6a7683b Disable Atmosphere version number check (#11890)
ebb92e6 Improve error message if vaadinPush.js failed to load (#11673)
70131cd Extracted common code for number conveters to abstract super class (#11900)
0b63506 Fixed order of parameters in javadoc (#11158)
6bf83a4 Modified the logic in setPropertyDatasource which determines if a new converter is needed (#11863)
53a9c11 Fix TestingPushConnection.init signature (#11673)
05ef43f Updated client-compiler to depend on client-compiler-deps 1.0.2 #11879
9686323 Added isInitialStateChange to StateChangeEvent (#10477)
7cced5e Fixed test which had never passed
ada3311 Avoid creating an instance of every view while searching for the correct view (#11722)
5b35dd9 Added text file encoding and line delimiter info (#11907)
f8c4f99 Prevent spurious "Could not determine ApplicationConnection" error when using the debug window
8a42394 Fixed locators in test (aria div conflict)
6de01ac Fix text / javascript mismatch issue in Chrome (#11275)
f7f1e3e Added Java Date to Sql Date converter to better support sql dates (#11224)
2882cf9 Added Serializable where missing and ignore classes which do not need Serializable
4d7f190 Make access() enqueue the runnable if the session is locked (#11897)
4c2b86d Stop using PlaceHolder widgets in VTabsheet (#11026)
87018cd Add missing license header
cb1f63b Send window mode changes to the server immediately (#11737)
e52df7c Added ComponentConnector.isAttached (#11928)
2b5ba96 Define how CurrentInstance works with access() (#11897)
d345838 Remove ThreadLocal references from CurrentInstance (#11914)
bb7b404 Remove outdated testing (#11897)
f64d944 Merge "event not reported as target when context clicking in month view" to Vaadin 7.1 (#10217)
51c9fb5 Fix debug window SEVERE style, add styles for FINE, FINER and FINEST (#11891)
3b888fe Support nested SASS imports (#11909)
b2137f5 Ensure calendar panel is updated when range changes (#11940)
f8319eb Avoid deadlock checking in runPendingAccessTasks() (#11897)
51a98a3 Moved enums to avoid running them as tests
7c613d1 Exclude parsers from checkstyle as they are generated
35f3532 Fixes current text being overwritten in server update on RTA #11741
a744d21 Remove UI.runSafely and VaadinSession.runSafely (#11901)
84edd19 Make test independent of browser language (#11940)
a3ad62d Updated to custom build of Smartsprites 0.2.10 which includes a fix for SMARTSPRITES-36 (#9959)
a9afca6 Moved Locale data handling to LocaleService (#11378)
5e548ae Fixed javadoc compilation error
91182e2 Extract ProgressBar and deprecate ProgressIndicator (#11925)
a5b8209 Add primary style name support for ProgressBar/Indicator (#9913)
86b3689 Make ProgressInidcatorConnector use VProgressIndicator (#11925)
29fcadc Flush the output writer in case of SSE transport as well (#11955)
5e26b0b Fix streaming issue with iOS6 (#11934)
1b274c4 Limit sub window minimum size (#11510)
46cc08b Remove workarounds for broken Timer.cancel in IE (#11872)
d850db6 Add XML formatting instructions (#11956)
9a3dc4e Formatted XML files using defined rules (#11956)
57b7335 Fixed spelling mistake in API #11741
587e10b Fix stale info in javadoc for accessSynchronously (#11897)
36fd94a Remove IE6/IE7 permutation (#11954)
cccff37 Do not log legacy warnings in JUnit tests (#11963)
0f9b689 Throw exception if VaadinService has not been initialized (#11961)
1ed0980 Move ApplicationConnection.setOverlayContainerLabel to VOverlay (#11965)
0014563 Extracted dialog style to a separate block (#11734)
b82e60b Add missing dialog maximize/restore icons for Runo (#11734)
0d046d6 Add a separate debug window section for profiler output (#11950)
03830ae Ignore style resource that has already been added (#11667)
84bf5a7 Enabled drag & drop to Calendar #11048
6c36784 Merge commit '34e6c60a5a746c0306c3a84ae8d6c21dfd84d878' into 7.1
a82d57e Merge changes from origin/7.0
666dbb5 Use window.console instead of just console in vaadinPush to appease IE (#11980)
93751c1 Use correct day names when formatting dates (#6207)
19d0082 Fixed javadoc references
e6e752d Correctly decode summaries containing quotes (#11769)
54ed269 Log stack trace using fine when logging toString warnings
8d655f6 Move VaadinSession.runPendingAccessTasks to VaadinService (#11964)
b1ab27a Update broadcaster tutorial code
e63edcc Update deprecation javadoc for VaadinSession.getBrowser()
132eee5 Add @VaadinServletConfiguration (#11970)
aa99259 Send connector debug (highlight) using RPC (#11536)
6d4582e Change analyze layouts to use RPC (#11536)
6f912b1 Rename tests so they are run during build (Abstract* is ignored)
ebd4a5c Added missing rpc interface (#11536)
edca409 Allow customizing client-side push config on server side (#11867)
b0574f7 Add transport parameter to @Push (#11966)
Change-Id: I4670c783fec829f81890e2d645d93dd40860b909
Diffstat (limited to 'server/src/com/vaadin/ui/UI.java')
-rw-r--r-- | server/src/com/vaadin/ui/UI.java | 238 |
1 files changed, 166 insertions, 72 deletions
diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 0a4ed7c491..9135151089 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -21,7 +21,10 @@ import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.concurrent.Future; +import java.util.logging.Logger; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; @@ -29,6 +32,10 @@ import com.vaadin.event.ActionManager; import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.MouseEvents.ClickListener; import com.vaadin.navigator.Navigator; +import com.vaadin.server.ClientConnector; +import com.vaadin.server.ComponentSizeValidator; +import com.vaadin.server.ComponentSizeValidator.InvalidLayout; +import com.vaadin.server.LocaleService; import com.vaadin.server.Page; import com.vaadin.server.PaintException; import com.vaadin.server.PaintTarget; @@ -38,15 +45,18 @@ import com.vaadin.server.VaadinService; import com.vaadin.server.VaadinServlet; import com.vaadin.server.VaadinSession; import com.vaadin.server.communication.PushConnection; +import com.vaadin.shared.Connector; import com.vaadin.shared.EventId; import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.DebugWindowClientRpc; +import com.vaadin.shared.ui.ui.DebugWindowServerRpc; import com.vaadin.shared.ui.ui.ScrollClientRpc; import com.vaadin.shared.ui.ui.UIClientRpc; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.shared.ui.ui.UIServerRpc; import com.vaadin.shared.ui.ui.UIState; import com.vaadin.ui.Component.Focusable; +import com.vaadin.util.ConnectorHelper; import com.vaadin.util.CurrentInstance; /** @@ -86,7 +96,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements /** * The application to which this UI belongs */ - private VaadinSession session; + private volatile VaadinSession session; /** * List of windows in this UI. @@ -159,6 +169,40 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ } }; + private DebugWindowServerRpc debugRpc = new DebugWindowServerRpc() { + @Override + public void showServerDebugInfo(Connector connector) { + String info = ConnectorHelper + .getDebugInformation((ClientConnector) connector); + getLogger().info(info); + } + + @Override + public void analyzeLayouts() { + // TODO Move to client side + List<InvalidLayout> invalidSizes = ComponentSizeValidator + .validateLayouts(UI.this); + StringBuilder json = new StringBuilder(); + json.append("{\"invalidLayouts\":"); + json.append("["); + + if (invalidSizes != null) { + boolean first = true; + for (InvalidLayout invalidSize : invalidSizes) { + if (!first) { + json.append(","); + } else { + first = false; + } + invalidSize.reportErrors(json, System.err); + } + } + json.append("]}"); + getRpcProxy(DebugWindowClientRpc.class).reportLayoutProblems( + json.toString()); + } + + }; /** * Timestamp keeping track of the last heartbeat of this UI. Updated to the @@ -171,6 +215,8 @@ public abstract class UI extends AbstractSingleComponentContainer implements private TooltipConfiguration tooltipConfiguration = new TooltipConfigurationImpl( this); + private PushConfiguration pushConfiguration = new PushConfigurationImpl( + this); /** * Creates a new empty UI without a caption. The content of the UI must be @@ -191,6 +237,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ public UI(Component content) { registerRpc(rpc); + registerRpc(debugRpc); setSizeFull(); setContent(content); } @@ -418,7 +465,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements throw new NullPointerException("Argument must not be null"); } - if (window.getUI() != null && window.getUI().getSession() != null) { + if (window.isAttached()) { throw new IllegalArgumentException( "Window is already attached to an application."); } @@ -493,6 +540,9 @@ public abstract class UI extends AbstractSingleComponentContainer implements private boolean hasPendingPush = false; + private LocaleService localeService = new LocaleService(this, + getState(false).localeServiceState); + /** * This method is used by Component.Focusable objects to request focus to * themselves. Focus renders must be handled at window level (instead of @@ -1051,6 +1101,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements @Override public void attach() { super.attach(); + getLocaleService().addLocale(getLocale()); } /** @@ -1098,24 +1149,30 @@ public abstract class UI extends AbstractSingleComponentContainer implements } /** - * Provides exclusive access to this UI from outside a request handling - * thread. - * <p> - * The given runnable is executed while holding the session lock to ensure - * exclusive access to this UI and its session. The UI and related thread - * locals are set properly before executing the runnable. - * </p> + * Locks the session of this UI and runs the provided Runnable right away. * <p> - * RPC handlers for components inside this UI do not need this method as the - * session is automatically locked by the framework during request handling. + * It is generally recommended to use {@link #access(Runnable)} instead of + * this method for accessing a session from a different thread as + * {@link #access(Runnable)} can be used while holding the lock of another + * session. To avoid causing deadlocks, this methods throws an exception if + * it is detected than another session is also locked by the current thread. * </p> * <p> - * Note that calling this method while another session is locked by the - * current thread will cause an exception. This is to prevent deadlock - * situations when two threads have locked one session each and are both - * waiting for the lock for the other session. + * This method behaves differently than {@link #access(Runnable)} in some + * situations: + * <ul> + * <li>If the current thread is currently holding the lock of the session, + * {@link #accessSynchronously(Runnable)} runs the task right away whereas + * {@link #access(Runnable)} defers the task to a later point in time.</li> + * <li>If some other thread is currently holding the lock for the session, + * {@link #accessSynchronously(Runnable)} blocks while waiting for the lock + * to be available whereas {@link #access(Runnable)} defers the task to a + * later point in time.</li> + * </ul> * </p> * + * @since 7.1 + * * @param runnable * the runnable which accesses the UI * @throws UIDetachedException @@ -1124,11 +1181,11 @@ public abstract class UI extends AbstractSingleComponentContainer implements * @throws IllegalStateException * if the current thread holds the lock for another session * - * @see #getCurrent() - * @see VaadinSession#access(Runnable) - * @see VaadinSession#lock() + * @see #access(Runnable) + * @see VaadinSession#accessSynchronously(Runnable) */ - public void access(Runnable runnable) throws UIDetachedException { + public void accessSynchronously(Runnable runnable) + throws UIDetachedException { Map<Class<?>, CurrentInstance> old = null; VaadinSession session = getSession(); @@ -1146,24 +1203,76 @@ public abstract class UI extends AbstractSingleComponentContainer implements // acquired the lock. throw new UIDetachedException(); } - old = CurrentInstance.setThreadLocals(this); + old = CurrentInstance.setCurrent(this); runnable.run(); } finally { session.unlock(); if (old != null) { - CurrentInstance.restoreThreadLocals(old); + CurrentInstance.restoreInstances(old); } } } /** - * @deprecated As of 7.1.0.beta1, use {@link #access(Runnable)} instead. - * This method will be removed before the final 7.1.0 release. + * Provides exclusive access to this UI from outside a request handling + * thread. + * <p> + * The given runnable is executed while holding the session lock to ensure + * exclusive access to this UI. If the session is not locked, the lock will + * be acquired and the runnable is run right away. If the session is + * currently locked, the runnable will be run before that lock is released. + * </p> + * <p> + * RPC handlers for components inside this UI do not need to use this method + * as the session is automatically locked by the framework during RPC + * handling. + * </p> + * <p> + * Please note that the runnable might be invoked on a different thread or + * later on the current thread, which means that custom thread locals might + * not have the expected values when the runnable is executed. Inheritable + * values in {@link CurrentInstance} will have the same values as when this + * method was invoked. {@link UI#getCurrent()}, + * {@link VaadinSession#getCurrent()} and {@link VaadinService#getCurrent()} + * are set according to this UI before executing the runnable. + * Non-inheritable CurrentInstance values including + * {@link VaadinService#getCurrentRequest()} and + * {@link VaadinService#getCurrentResponse()} will not be defined. + * </p> + * <p> + * The returned future can be used to check for task completion and to + * cancel the task. + * </p> + * + * @see #getCurrent() + * @see #accessSynchronously(Runnable) + * @see VaadinSession#access(Runnable) + * @see VaadinSession#lock() + * + * @since 7.1 + * + * @param runnable + * the runnable which accesses the UI + * @throws UIDetachedException + * if the UI is not attached to a session (and locking can + * therefore not be done) + * @return a future that can be used to check for task completion and to + * cancel the task */ - @Deprecated - public void runSafely(Runnable runnable) throws UIDetachedException { - access(runnable); + public Future<Void> access(final Runnable runnable) { + VaadinSession session = getSession(); + + if (session == null) { + throw new UIDetachedException(); + } + + return session.access(new Runnable() { + @Override + public void run() { + accessSynchronously(runnable); + } + }); } /** @@ -1204,12 +1313,20 @@ public abstract class UI extends AbstractSingleComponentContainer implements VaadinSession session = getSession(); if (session != null) { assert session.hasLock(); + + /* + * Purge the pending access queue as it might mark a connector as + * dirty when the push would otherwise be ignored because there are + * no changes to push. + */ + session.getService().runPendingAccessTasks(session); + if (!getConnectorTracker().hasDirtyConnectors()) { // Do not push if there is nothing to push return; } - if (!getPushMode().isEnabled()) { + if (!getPushConfiguration().getPushMode().isEnabled()) { throw new IllegalStateException("Push not enabled"); } @@ -1237,7 +1354,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ public void setPushConnection(PushConnection pushConnection) { // If pushMode is disabled then there should never be a pushConnection - assert (getPushMode().isEnabled() || pushConnection == null); + assert (getPushConfiguration().getPushMode().isEnabled() || pushConnection == null); if (pushConnection == this.pushConnection) { return; @@ -1286,51 +1403,13 @@ public abstract class UI extends AbstractSingleComponentContainer implements } /** - * Returns the mode of bidirectional ("push") communication that is used in - * this UI. - * - * @return The push mode. - */ - public PushMode getPushMode() { - return getState(false).pushMode; - } - - /** - * Sets the mode of bidirectional ("push") communication that should be used - * in this UI. - * <p> - * Add-on developers should note that this method is only meant for the - * application developer. An add-on should not set the push mode directly, - * rather instruct the user to set it. - * </p> - * - * @param pushMode - * The push mode to use. + * Retrieves the object used for configuring the push channel. * - * @throws IllegalArgumentException - * if the argument is null. - * @throws IllegalStateException - * if push support is not available. + * @since 7.1 + * @return The instance used for push configuration */ - public void setPushMode(PushMode pushMode) { - if (pushMode == null) { - throw new IllegalArgumentException("Push mode cannot be null"); - } - - if (pushMode.isEnabled()) { - VaadinSession session = getSession(); - if (session != null && !session.getService().ensurePushAvailable()) { - throw new IllegalStateException( - "Push is not available. See previous log messages for more information."); - } - } - - /* - * Client-side will open a new connection or disconnect the old - * connection, so there's nothing more to do on the server at this - * point. - */ - getState().pushMode = pushMode; + public PushConfiguration getPushConfiguration() { + return pushConfiguration; } /** @@ -1357,4 +1436,19 @@ public abstract class UI extends AbstractSingleComponentContainer implements public void setOverlayContainerLabel(String overlayContainerLabel) { getState().overlayContainerLabel = overlayContainerLabel; } + + /** + * Returns the locale service which handles transmission of Locale data to + * the client. + * + * @since 7.1 + * @return The LocaleService for this UI + */ + public LocaleService getLocaleService() { + return localeService; + } + + private static Logger getLogger() { + return Logger.getLogger(UI.class.getName()); + } } |