summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui/UI.java
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2013-06-07 14:12:41 +0300
committerLeif Åstrand <leif@vaadin.com>2013-06-07 14:12:41 +0300
commit808b65581554dad8b670538b1830a8f90b3db5db (patch)
treef2323317e420e7c76b17994660cdbbd0f78145b4 /server/src/com/vaadin/ui/UI.java
parentfe8d330c3c9f2ae2c0ace28fa5c34e5b2b131112 (diff)
parentb0574f7b33c4d3d437c8c11cd53389e5522f6999 (diff)
downloadvaadin-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.java238
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());
+ }
}