summaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2013-04-17 11:20:13 +0300
committerLeif Åstrand <leif@vaadin.com>2013-04-18 10:36:45 +0300
commit4f7377be467fc099defc1d3dd0cb1eb656152d6f (patch)
tree998d0274de67b9d9aaac824bd519749727a351f0 /server/src
parent8fcad2fe496d04b4f4fa6e8eebee673226fe70d4 (diff)
downloadvaadin-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.java43
-rw-r--r--server/src/com/vaadin/server/BootstrapHandler.java30
-rw-r--r--server/src/com/vaadin/server/Constants.java25
-rw-r--r--server/src/com/vaadin/server/DefaultDeploymentConfiguration.java25
-rw-r--r--server/src/com/vaadin/server/UIProvider.java25
-rw-r--r--server/src/com/vaadin/server/VaadinService.java28
-rw-r--r--server/src/com/vaadin/server/VaadinServletService.java43
-rw-r--r--server/src/com/vaadin/server/VaadinSession.java42
-rw-r--r--server/src/com/vaadin/server/communication/PushHandler.java2
-rw-r--r--server/src/com/vaadin/ui/UI.java50
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;
+ }
+
}