diff options
author | Leif Åstrand <leif@vaadin.com> | 2013-04-17 11:20:13 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2013-04-18 10:36:45 +0300 |
commit | 4f7377be467fc099defc1d3dd0cb1eb656152d6f (patch) | |
tree | 998d0274de67b9d9aaac824bd519749727a351f0 /server/src | |
parent | 8fcad2fe496d04b4f4fa6e8eebee673226fe70d4 (diff) | |
download | vaadin-framework-4f7377be467fc099defc1d3dd0cb1eb656152d6f.tar.gz vaadin-framework-4f7377be467fc099defc1d3dd0cb1eb656152d6f.zip |
Move push mode to UI and add @Push annotation (#11506)
Change-Id: Idc0e5e00a8f3ddd3f56d87484089c290d52715c2
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/com/vaadin/annotations/Push.java | 43 | ||||
-rw-r--r-- | server/src/com/vaadin/server/BootstrapHandler.java | 30 | ||||
-rw-r--r-- | server/src/com/vaadin/server/Constants.java | 25 | ||||
-rw-r--r-- | server/src/com/vaadin/server/DefaultDeploymentConfiguration.java | 25 | ||||
-rw-r--r-- | server/src/com/vaadin/server/UIProvider.java | 25 | ||||
-rw-r--r-- | server/src/com/vaadin/server/VaadinService.java | 28 | ||||
-rw-r--r-- | server/src/com/vaadin/server/VaadinServletService.java | 43 | ||||
-rw-r--r-- | server/src/com/vaadin/server/VaadinSession.java | 42 | ||||
-rw-r--r-- | server/src/com/vaadin/server/communication/PushHandler.java | 2 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/UI.java | 50 |
10 files changed, 239 insertions, 74 deletions
diff --git a/server/src/com/vaadin/annotations/Push.java b/server/src/com/vaadin/annotations/Push.java new file mode 100644 index 0000000000..e97a1a34dd --- /dev/null +++ b/server/src/com/vaadin/annotations/Push.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2013 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.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import com.vaadin.shared.communication.PushMode; +import com.vaadin.ui.UI; + +/** + * Defines a specific {@link PushMode} for a {@link UI}. + * + * @author Vaadin Ltd. + * @since 7.1 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Push { + /** + * Returns the {@link PushMode} to use for the annotated UI. + * + * @return the push mode to use + */ + public PushMode value(); + +} diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java index ad491745dd..9d21e19a18 100644 --- a/server/src/com/vaadin/server/BootstrapHandler.java +++ b/server/src/com/vaadin/server/BootstrapHandler.java @@ -41,6 +41,7 @@ import org.jsoup.parser.Tag; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.Version; +import com.vaadin.shared.communication.PushMode; import com.vaadin.ui.UI; /** @@ -68,6 +69,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { private String widgetsetName; private String themeName; private String appId; + private PushMode pushMode; public BootstrapContext(VaadinResponse response, BootstrapFragmentResponse bootstrapResponse) { @@ -105,6 +107,30 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { return themeName; } + public PushMode getPushMode() { + if (pushMode == null) { + UICreateEvent event = new UICreateEvent(getRequest(), + getUIClass()); + + pushMode = getBootstrapResponse().getUIProvider().getPushMode( + event); + if (pushMode == null) { + pushMode = getRequest().getService() + .getDeploymentConfiguration().getPushMode(); + } + + if (pushMode.isEnabled() + && !getRequest().getService().ensurePushAvailable()) { + /* + * Fall back if not supported (ensurePushAvailable will log + * information to the developer the first time this happens) + */ + pushMode = PushMode.DISABLED; + } + } + return pushMode; + } + public String getAppId() { if (appId == null) { appId = getRequest().getService().getMainDivId(getSession(), @@ -355,7 +381,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { "position:absolute;width:0;height:0;border:0;overflow:hidden") .attr("src", "javascript:false")); - if (context.getSession().getPushMode().isEnabled()) { + if (context.getPushMode().isEnabled()) { // Load client-side dependencies for push support fragmentNodes.add(new Element(Tag.valueOf("script"), "").attr( "type", "text/javascript").attr("src", @@ -496,7 +522,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler { appConfig.put("heartbeatInterval", vaadinService .getDeploymentConfiguration().getHeartbeatInterval()); - appConfig.put("pushMode", session.getPushMode().toString()); + appConfig.put("pushMode", context.getPushMode().toString()); String serviceUrl = getServiceUrl(context); if (serviceUrl != null) { diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java index 4880bc84c0..939aba0282 100644 --- a/server/src/com/vaadin/server/Constants.java +++ b/server/src/com/vaadin/server/Constants.java @@ -15,6 +15,8 @@ */ package com.vaadin.server; +import com.vaadin.shared.communication.PushMode; + /** * TODO Document me! * @@ -63,13 +65,12 @@ public interface Constants { + " Widgetset version: %s\n" + "================================================================="; - static final String REQUIRED_ATMOSPHERE_VERSION = "1.0.12"; + static final String REQUIRED_ATMOSPHERE_VERSION = "1.0.13"; static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n" + "=================================================================\n" - + "With push enabled, Vaadin depends on Atomsphere {0} but\n" - + "version {1} was found. This might cause compatibility\n" - + "problems.\n" + + "Vaadin depends on Atomsphere {0} but version {1} was found.\n" + + "This might cause compatibility problems if push is used.\n" + "================================================================="; static final String ATMOSPHERE_MISSING_ERROR = "\n" @@ -81,7 +82,21 @@ public interface Constants { + "If managing dependencies manually, please make sure Atmosphere\n" + REQUIRED_ATMOSPHERE_VERSION + " is included on the classpath.\n" - + "Push will be disabled.\n" + + "Will fall back to using " + + PushMode.class.getSimpleName() + + "." + + PushMode.DISABLED.name() + + ".\n" + + "================================================================="; + + static final String PUSH_NOT_SUPPORTED_ERROR = "\n" + + "=================================================================\n" + + "Push is not supported for {0}\n" + + "Will fall back to using " + + PushMode.class.getSimpleName() + + "." + + PushMode.DISABLED.name() + + ".\n" + "================================================================="; static final String URL_PARAMETER_THEME = "theme"; diff --git a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java index 5cf3898c23..d11bd69997 100644 --- a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java +++ b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java @@ -17,11 +17,8 @@ package com.vaadin.server; import java.util.Properties; -import java.util.logging.Level; import java.util.logging.Logger; -import org.atmosphere.util.Version; - import com.vaadin.shared.communication.PushMode; /** @@ -268,28 +265,6 @@ public class DefaultDeploymentConfiguration implements DeploymentConfiguration { getLogger().warning(Constants.WARNING_PUSH_MODE_NOT_RECOGNIZED); pushMode = PushMode.DISABLED; } - - if (pushMode.isEnabled() && !checkAtomsphereVersion()) { - pushMode = PushMode.DISABLED; - } - } - - private boolean checkAtomsphereVersion() { - try { - String rawVersion = Version.getRawVersion(); - if (!Constants.REQUIRED_ATMOSPHERE_VERSION.equals(rawVersion)) { - getLogger().log( - Level.WARNING, - Constants.INVALID_ATMOSPHERE_VERSION_WARNING, - new Object[] { Constants.REQUIRED_ATMOSPHERE_VERSION, - rawVersion }); - } - return true; - } catch (NoClassDefFoundError e) { - getLogger() - .log(Level.SEVERE, Constants.ATMOSPHERE_MISSING_ERROR, e); - return false; - } } private Logger getLogger() { diff --git a/server/src/com/vaadin/server/UIProvider.java b/server/src/com/vaadin/server/UIProvider.java index a91db6b88d..0305b907e6 100644 --- a/server/src/com/vaadin/server/UIProvider.java +++ b/server/src/com/vaadin/server/UIProvider.java @@ -20,9 +20,11 @@ import java.io.Serializable; import java.lang.annotation.Annotation; import com.vaadin.annotations.PreserveOnRefresh; +import com.vaadin.annotations.Push; import com.vaadin.annotations.Theme; import com.vaadin.annotations.Title; import com.vaadin.annotations.Widgetset; +import com.vaadin.shared.communication.PushMode; import com.vaadin.ui.UI; public abstract class UIProvider implements Serializable { @@ -149,4 +151,27 @@ public abstract class UIProvider implements Serializable { return titleAnnotation.value(); } } + + /** + * Finds the {@link PushMode} to use for a specific UI. If no specific push + * mode is required, <code>null</code> is returned. + * <p> + * The default implementation uses the @{@link Push} annotation if it's + * defined for the UI class. + * + * @param event + * the UI create event with information about the UI and the + * current request. + * @return the push mode to use, or <code>null</code> if the default push + * mode should be used + * + */ + public PushMode getPushMode(UICreateEvent event) { + Push push = getAnnotationFor(event.getUIClass(), Push.class); + if (push == null) { + return null; + } else { + return push.value(); + } + } } diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 43d37a72b3..6088fa55ca 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -103,6 +103,13 @@ public abstract class VaadinService implements Serializable { private final Iterable<RequestHandler> requestHandlers; /** + * Keeps track of whether a warning about missing push support has already + * been logged. This is used to avoid spamming the log with the same message + * every time a new UI is bootstrapped. + */ + private boolean pushWarningEmitted = false; + + /** * Creates a new vaadin service based on a deployment configuration * * @param deploymentConfiguration @@ -664,7 +671,6 @@ public abstract class VaadinService implements Serializable { session.setLocale(locale); session.setConfiguration(getDeploymentConfiguration()); session.setCommunicationManager(new LegacyCommunicationManager(session)); - session.setPushMode(getDeploymentConfiguration().getPushMode()); ServletPortletHelper.initDefaultUIProvider(session, this); onVaadinSessionStarted(request, session); @@ -1455,4 +1461,24 @@ public abstract class VaadinService implements Serializable { createCriticalNotificationJSON(caption, message, details, url)); } + /** + * Enables push if push support is available and push has not yet been + * enabled. + * + * If push support is not available, a warning explaining the situation will + * be logged at least the first time this method is invoked. + * + * @return <code>true</code> if push can be used; <code>false</code> if push + * is not available. + */ + public boolean ensurePushAvailable() { + if (!pushWarningEmitted) { + pushWarningEmitted = true; + getLogger().log(Level.WARNING, Constants.PUSH_NOT_SUPPORTED_ERROR, + getClass().getSimpleName()); + } + // Not supported by default for now, sublcasses may override + return false; + } + } diff --git a/server/src/com/vaadin/server/VaadinServletService.java b/server/src/com/vaadin/server/VaadinServletService.java index f513ef1b15..088bb6d640 100644 --- a/server/src/com/vaadin/server/VaadinServletService.java +++ b/server/src/com/vaadin/server/VaadinServletService.java @@ -22,12 +22,15 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.List; +import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.atmosphere.util.Version; + import com.vaadin.server.communication.PushRequestHandler; import com.vaadin.server.communication.ServletBootstrapHandler; import com.vaadin.server.communication.ServletUIInitHandler; @@ -37,6 +40,15 @@ import com.vaadin.ui.UI; public class VaadinServletService extends VaadinService { private final VaadinServlet servlet; + private final static boolean atmosphereAvailable = checkAtmosphereSupport(); + + /** + * Keeps track of whether a warning about missing push support has already + * been logged. This is used to avoid spamming the log with the same message + * every time a new UI is bootstrapped. + */ + private boolean pushWarningLogged = false; + public VaadinServletService(VaadinServlet servlet, DeploymentConfiguration deploymentConfiguration) { super(deploymentConfiguration); @@ -53,12 +65,28 @@ public class VaadinServletService extends VaadinService { } } + private static boolean checkAtmosphereSupport() { + try { + String rawVersion = Version.getRawVersion(); + if (!Constants.REQUIRED_ATMOSPHERE_VERSION.equals(rawVersion)) { + getLogger().log( + Level.WARNING, + Constants.INVALID_ATMOSPHERE_VERSION_WARNING, + new Object[] { Constants.REQUIRED_ATMOSPHERE_VERSION, + rawVersion }); + } + return true; + } catch (NoClassDefFoundError e) { + return false; + } + } + @Override protected List<RequestHandler> createRequestHandlers() { List<RequestHandler> handlers = super.createRequestHandlers(); handlers.add(0, new ServletBootstrapHandler()); handlers.add(new ServletUIInitHandler()); - if (getDeploymentConfiguration().getPushMode().isEnabled()) { + if (atmosphereAvailable) { handlers.add(new PushRequestHandler(this)); } return handlers; @@ -312,4 +340,17 @@ public class VaadinServletService extends VaadinService { return Logger.getLogger(VaadinServletService.class.getName()); } + @Override + public boolean ensurePushAvailable() { + if (atmosphereAvailable) { + return true; + } else { + if (!pushWarningLogged) { + pushWarningLogged = true; + getLogger().log(Level.WARNING, + Constants.ATMOSPHERE_MISSING_ERROR); + } + return false; + } + } } diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index 029a384e70..e9b3eb6ada 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -129,8 +129,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { private transient Lock lock; - private PushMode pushMode; - /** * Create a new service session tied to a Vaadin service * @@ -820,12 +818,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { public void unlock() { assert hasLock(); try { - if (getPushMode() == PushMode.AUTOMATIC - && ((ReentrantLock) getLockInstance()).getHoldCount() == 1) { + if (((ReentrantLock) getLockInstance()).getHoldCount() == 1) { // Only push if the reentrant lock will actually be released by // this unlock() invocation. for (UI ui : getUIs()) { - ui.push(); + if (ui.getPushMode() == PushMode.AUTOMATIC) { + ui.push(); + } } } } finally { @@ -1025,39 +1024,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { } /** - * Returns the mode of bidirectional ("push") communication that is used in - * this session. - * - * @return The push mode. - */ - public PushMode getPushMode() { - return pushMode; - } - - /** - * Sets the mode of bidirectional ("push") communication that should be used - * in this session. Set once on session creation and cannot be changed - * afterwards. - * - * @param pushMode - * The push mode to use. - * - * @throws IllegalArgumentException - * if the argument is null. - * @throws IllegalStateException - * if the mode is already set. - */ - public void setPushMode(PushMode pushMode) { - if (pushMode == null) { - throw new IllegalArgumentException("Push mode cannot be null"); - } - if (this.pushMode != null) { - throw new IllegalStateException("Push mode already set"); - } - this.pushMode = pushMode; - } - - /** * Sets this session to be closed and all UI state to be discarded at the * end of the current request, or at the end of the next request if there is * no ongoing one. diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java index f65a0cba10..bfa1067aa8 100644 --- a/server/src/com/vaadin/server/communication/PushHandler.java +++ b/server/src/com/vaadin/server/communication/PushHandler.java @@ -89,7 +89,7 @@ public class PushHandler implements AtmosphereHandler { "Could not find the requested UI in session"); return; } - assert session.getPushMode().isEnabled(); + assert ui.getPushMode().isEnabled(); if (req.getMethod().equalsIgnoreCase("GET")) { /* diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index 70ecc1f1fa..4eff7645e2 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -40,6 +40,7 @@ import com.vaadin.server.VaadinSession; import com.vaadin.server.communication.PushConnection; import com.vaadin.shared.EventId; import com.vaadin.shared.MouseEventDetails; +import com.vaadin.shared.communication.PushMode; import com.vaadin.shared.ui.ui.ScrollClientRpc; import com.vaadin.shared.ui.ui.UIConstants; import com.vaadin.shared.ui.ui.UIServerRpc; @@ -129,6 +130,8 @@ public abstract class UI extends AbstractSingleComponentContainer implements */ private int scrollLeft = 0; + private PushMode pushMode; + private UIServerRpc rpc = new UIServerRpc() { @Override public void click(MouseEventDetails mouseDetails) { @@ -540,6 +543,10 @@ public abstract class UI extends AbstractSingleComponentContainer implements // Actual theme - used for finding CustomLayout templates theme = request.getParameter("theme"); + PushMode pushMode = PushMode.valueOf(request.getParameter("v-pushMode") + .toUpperCase()); + setPushMode(pushMode); + getPage().init(request); // Call the init overridden by the application developer @@ -1156,7 +1163,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements return; } - if (!session.getPushMode().isEnabled()) { + if (!getPushMode().isEnabled()) { throw new IllegalStateException("Push not enabled"); } @@ -1217,4 +1224,45 @@ public abstract class UI extends AbstractSingleComponentContainer implements public int getPollInterval() { return getState(false).pollInterval; } + + /** + * Returns the mode of bidirectional ("push") communication that is used in + * this UI. + * + * @return The push mode. + */ + public PushMode getPushMode() { + return pushMode; + } + + /** + * Sets the mode of bidirectional ("push") communication that should be used + * in this UI. Set once on UI creation and cannot be changed afterwards. + * + * @param pushMode + * The push mode to use. + * + * @throws IllegalArgumentException + * if the argument is null. + * @throws IllegalStateException + * if the mode is already set or if push support is not + * available. + */ + public void setPushMode(PushMode pushMode) { + if (pushMode == null) { + throw new IllegalArgumentException("Push mode cannot be null"); + } + if (this.pushMode != null) { + throw new IllegalStateException("Push mode already set"); + } + 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."); + } + } + this.pushMode = pushMode; + } + } |