summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Koivisto <markus@vaadin.com>2015-04-08 14:53:27 +0300
committerMarkus Koivisto <markus@vaadin.com>2015-04-08 14:53:27 +0300
commit2478267d11fddfd798fee89227b5f258441e1331 (patch)
treead41582f60af26d2b47959f00130f48a0a510919
parenta1aa700db37f727bb6a3690f1704d3ec512ee468 (diff)
parent6abcbdf1eeb8f23ebda97df3ffad7b0abdee37ea (diff)
downloadvaadin-framework-2478267d11fddfd798fee89227b5f258441e1331.tar.gz
vaadin-framework-2478267d11fddfd798fee89227b5f258441e1331.zip
Merge branch 'master' into grid-7.5
Conflicts: WebContent/release-notes.html Change-Id: I3906caeb01d1991dc9cb927b3d9ce0fb21c77e04
-rw-r--r--WebContent/WEB-INF/web.xml16
-rw-r--r--WebContent/release-notes.html2
-rw-r--r--client/src/com/vaadin/client/communication/AtmospherePushConnection.java2
-rw-r--r--push/ivy.xml6
-rw-r--r--server/ivy.xml6
-rw-r--r--server/src/com/vaadin/server/ServletPortletHelper.java20
-rw-r--r--server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java203
-rw-r--r--server/src/com/vaadin/server/communication/PushAtmosphereHandler.java120
-rw-r--r--server/src/com/vaadin/server/communication/PushHandler.java75
-rw-r--r--server/src/com/vaadin/server/communication/PushRequestHandler.java102
-rw-r--r--server/src/com/vaadin/ui/AbstractColorPicker.java111
-rw-r--r--server/src/com/vaadin/ui/AbstractComponent.java21
-rw-r--r--server/src/com/vaadin/ui/AbstractSelect.java26
-rw-r--r--server/src/com/vaadin/ui/AbstractSingleComponentContainer.java33
-rw-r--r--server/src/com/vaadin/ui/Component.java13
-rw-r--r--server/src/com/vaadin/ui/PopupView.java88
-rw-r--r--server/src/com/vaadin/ui/Table.java38
-rw-r--r--server/src/com/vaadin/ui/Window.java122
-rw-r--r--server/src/com/vaadin/ui/declarative/DesignContext.java64
-rw-r--r--server/src/com/vaadin/ui/declarative/ShouldWriteDataDelegate.java55
-rw-r--r--server/src/com/vaadin/ui/declarative/converters/DesignShortcutActionConverter.java49
-rw-r--r--server/tests/src/com/vaadin/server/MockServletContext.java327
-rw-r--r--server/tests/src/com/vaadin/tests/design/AbstractComponentSetResponsiveTest.java37
-rw-r--r--server/tests/src/com/vaadin/tests/design/DeclarativeTestBase.java8
-rw-r--r--server/tests/src/com/vaadin/tests/design/DeclarativeTestBaseBase.java46
-rw-r--r--server/tests/src/com/vaadin/tests/design/DesignContextLocalIdTest.java60
-rw-r--r--server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java46
-rw-r--r--server/tests/src/com/vaadin/tests/design/local-ids.html4
-rw-r--r--server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java2
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/abstractselect/AbstractSelectDeclarativeTest.java8
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/colorpicker/AbstractColorPickerDeclarativeTest.java87
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/popupview/PopupViewDeclarativeTest.java74
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/window/WindowDeclarativeTest.java153
-rw-r--r--uitest/src/com/vaadin/tests/integration/ServletIntegrationJSR356WebsocketUITest.java32
-rw-r--r--uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java65
35 files changed, 1945 insertions, 176 deletions
diff --git a/WebContent/WEB-INF/web.xml b/WebContent/WEB-INF/web.xml
index ef60364202..51ac907843 100644
--- a/WebContent/WEB-INF/web.xml
+++ b/WebContent/WEB-INF/web.xml
@@ -87,6 +87,17 @@
</servlet>
<servlet>
+ <servlet-name>VaadinApplicationRunnerWithJSR356</servlet-name>
+ <servlet-class>com.vaadin.launcher.ApplicationRunnerServlet</servlet-class>
+ <!-- Force web sockets to use JSR 356 standard -->
+ <init-param>
+ <param-name>org.atmosphere.cpr.asyncSupport</param-name>
+ <param-value>org.atmosphere.container.JSR356AsyncSupport</param-value>
+ </init-param>
+ <async-supported>true</async-supported>
+ </servlet>
+
+ <servlet>
<!-- This servlet is a separate instance for the sole purpose of
testing #12446 (com.vaadin.tests.components.ui.TimeoutRedirectResetsOnActivity)
because it modifies the VaadinService timeout parameters -->
@@ -149,6 +160,11 @@
</servlet-mapping>
<servlet-mapping>
+ <servlet-name>VaadinApplicationRunnerWithJSR356</servlet-name>
+ <url-pattern>/run-jsr356/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
<servlet-name>IntegrationTest</servlet-name>
<url-pattern>/integration/*</url-pattern>
</servlet-mapping>
diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html
index e810285d83..97730cc292 100644
--- a/WebContent/release-notes.html
+++ b/WebContent/release-notes.html
@@ -108,7 +108,7 @@
<h3 id="incompatible">Incompatible or Behavior-altering Changes in @version-minor@</h3>
<ul>
-
+ <li>Push path has been changed from /PUSH/ to /PUSH to be compatible with JSR 356.</li>
</ul>
<h3 id="knownissues">Known Issues and Limitations</h3>
<ul>
diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java
index e544c91d0f..cd989d7ea4 100644
--- a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java
+++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java
@@ -197,7 +197,7 @@ public class AtmospherePushConnection implements PushConnection {
private void connect() {
String baseUrl = connection
.translateVaadinUri(ApplicationConstants.APP_PROTOCOL_PREFIX
- + ApplicationConstants.PUSH_PATH + '/');
+ + ApplicationConstants.PUSH_PATH);
String extraParams = UIConstants.UI_ID_PARAMETER + "="
+ connection.getConfiguration().getUIId();
diff --git a/push/ivy.xml b/push/ivy.xml
index 605f5d1a05..8827d92bc0 100644
--- a/push/ivy.xml
+++ b/push/ivy.xml
@@ -29,9 +29,9 @@
<dependencies>
<!-- API DEPENDENCIES -->
- <!--Servlet API version 2.4 -->
- <dependency org="javax.servlet" name="servlet-api"
- rev="2.4" conf="build-provided,ide,test -> default" />
+ <!-- @WebListener is used for JSR356 websockets so we need to compile with servlet 3 API -->
+ <dependency org="javax.servlet" name="javax.servlet-api"
+ rev="3.0.1" conf="build-provided,ide,test -> default" />
<!-- Atmosphere -->
<dependency org="com.vaadin.external.atmosphere"
diff --git a/server/ivy.xml b/server/ivy.xml
index b30e6a72ef..e9bc8b818d 100644
--- a/server/ivy.xml
+++ b/server/ivy.xml
@@ -26,9 +26,9 @@
<dependency org="com.liferay.portal" name="portal-service"
rev="6.0.2" conf="build-provided,ide -> default" />
- <!--Servlet API version 2.4 -->
- <dependency org="javax.servlet" name="servlet-api"
- rev="2.4" conf="build-provided,ide,test -> default" />
+ <!--Servlet API version 3.0 -->
+ <dependency org="javax.servlet" name="javax.servlet-api"
+ rev="3.0.1" conf="build-provided,ide,test -> default" />
<!--Portlet API version 2.0 (JSR-286) -->
<dependency org="javax.portlet" name="portlet-api"
diff --git a/server/src/com/vaadin/server/ServletPortletHelper.java b/server/src/com/vaadin/server/ServletPortletHelper.java
index 197d9fe416..33ecf16e17 100644
--- a/server/src/com/vaadin/server/ServletPortletHelper.java
+++ b/server/src/com/vaadin/server/ServletPortletHelper.java
@@ -102,6 +102,24 @@ public class ServletPortletHelper implements Serializable {
return false;
}
+ private static boolean isPathInfo(VaadinRequest request, String string) {
+ String pathInfo = request.getPathInfo();
+
+ if (pathInfo == null) {
+ return false;
+ }
+
+ if (!string.startsWith("/")) {
+ string = '/' + string;
+ }
+
+ if (pathInfo.equals(string)) {
+ return true;
+ }
+
+ return false;
+ }
+
public static boolean isFileUploadRequest(VaadinRequest request) {
return hasPathPrefix(request, UPLOAD_URL_PREFIX);
}
@@ -124,7 +142,7 @@ public class ServletPortletHelper implements Serializable {
}
public static boolean isPushRequest(VaadinRequest request) {
- return hasPathPrefix(request, ApplicationConstants.PUSH_PATH + '/');
+ return isPathInfo(request, ApplicationConstants.PUSH_PATH);
}
public static void initDefaultUIProvider(VaadinSession session,
diff --git a/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java b/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java
new file mode 100644
index 0000000000..fd61f6180f
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2000-2014 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.server.communication;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletRegistration;
+import javax.servlet.annotation.WebListener;
+
+import org.atmosphere.cpr.AtmosphereFramework;
+
+import com.vaadin.server.VaadinServlet;
+
+/**
+ * Initializer class for JSR 356 websockets.
+ * <p>
+ * Websocket specification says that initialization of websocket end points
+ * should be done in the servlet context initialization phase. Some servers
+ * implement this strictly so that end points cannot be registered after the
+ * context initialization phase.
+ * <p>
+ * Note that {@link WebListener} is Servlet 3.0 API so this will not be run for
+ * older servers (unless added to web.xml), but these servers do not support JSR
+ * 356 websockets either.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@WebListener
+public class JSR356WebsocketInitializer implements ServletContextListener {
+
+ private static boolean atmosphereAvailable = false;
+ static {
+ try {
+ org.atmosphere.util.Version.getRawVersion();
+ atmosphereAvailable = true;
+ } catch (NoClassDefFoundError e) {
+ }
+ }
+
+ /**
+ * "ServletConfig" which only provides information from a
+ * {@link ServletRegistration} and its {@link ServletContext}
+ */
+ public static class FakeServletConfig implements ServletConfig {
+
+ private ServletRegistration servletRegistration;
+ private ServletContext servletContext;
+
+ public FakeServletConfig(ServletRegistration servletRegistration,
+ ServletContext servletContext) {
+ this.servletContext = servletContext;
+ this.servletRegistration = servletRegistration;
+ }
+
+ @Override
+ public String getServletName() {
+ return servletRegistration.getName();
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return servletContext;
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ return servletRegistration.getInitParameter(name);
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return Collections.enumeration(servletRegistration
+ .getInitParameters().keySet());
+ }
+
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ ServletContext servletContext = sce.getServletContext();
+ if (servletContext.getMajorVersion() < 3) {
+ return;
+ }
+
+ if (!atmosphereAvailable) {
+ return;
+ }
+
+ Map<String, ? extends ServletRegistration> regs = servletContext
+ .getServletRegistrations();
+ for (String servletName : regs.keySet()) {
+ ServletRegistration servletRegistration = regs.get(servletName);
+
+ if (isVaadinServlet(servletRegistration)) {
+ try {
+ initAtmosphereForVaadinServlet(servletRegistration,
+ servletContext);
+ } catch (Exception e) {
+ getLogger().log(
+ Level.WARNING,
+ "Failed to initialize Atmosphere for "
+ + servletName, e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Initializes Atmosphere for use with the given Vaadin servlet
+ * <p>
+ * For JSR 356 websockets to work properly, the initialization must be done
+ * in the servlet context initialization phase.
+ *
+ * @param servletRegistration
+ * The servlet registration info for the servlet
+ * @param servletContext
+ */
+ public static void initAtmosphereForVaadinServlet(
+ ServletRegistration servletRegistration,
+ ServletContext servletContext) {
+ String servletName = servletRegistration.getName();
+ String attributeName = getAttributeName(servletName);
+
+ if (servletContext.getAttribute(attributeName) != null) {
+ // Already initialized
+ getLogger().warning("Atmosphere already initialized");
+ return;
+ }
+ getLogger().finer("Creating AtmosphereFramework for " + servletName);
+ AtmosphereFramework framework = PushRequestHandler
+ .initAtmosphere(new FakeServletConfig(servletRegistration,
+ servletContext));
+ servletContext.setAttribute(attributeName, framework);
+ getLogger().finer("Created AtmosphereFramework for " + servletName);
+
+ }
+
+ /**
+ * Returns the name of the attribute in the servlet context where the
+ * pre-initialized Atmosphere object is stored
+ *
+ * @param servletName
+ * The name of the servlet
+ * @return The attribute name which contains the initialized Atmosphere
+ * object
+ */
+ public static String getAttributeName(String servletName) {
+ return JSR356WebsocketInitializer.class.getName() + "." + servletName;
+ }
+
+ /**
+ * Tries to determine if the given servlet registration refers to a Vaadin
+ * servlet.
+ *
+ * @param servletRegistration
+ * The servlet registration info for the servlet
+ * @return false if the servlet is definitely not a Vaadin servlet, true
+ * otherwise
+ */
+ protected boolean isVaadinServlet(ServletRegistration servletRegistration) {
+ try {
+ Class<?> servletClass = Class.forName(servletRegistration
+ .getClassName());
+ return VaadinServlet.class.isAssignableFrom(servletClass);
+ } catch (Exception e) {
+ // This will fail in OSGi environments, assume everything is a
+ // VaadinServlet
+ return true;
+ }
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(JSR356WebsocketInitializer.class.getName());
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ // Nothing to do here
+ }
+
+}
diff --git a/server/src/com/vaadin/server/communication/PushAtmosphereHandler.java b/server/src/com/vaadin/server/communication/PushAtmosphereHandler.java
new file mode 100644
index 0000000000..0e94eaa75f
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/PushAtmosphereHandler.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2000-2014 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.server.communication;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.atmosphere.cpr.AtmosphereRequest;
+import org.atmosphere.cpr.AtmosphereResource;
+import org.atmosphere.cpr.AtmosphereResourceEvent;
+import org.atmosphere.cpr.AtmosphereResourceEventListenerAdapter;
+import org.atmosphere.handler.AbstractReflectorAtmosphereHandler;
+
+/**
+ * Handles Atmosphere requests and forwards them to logical methods in
+ * {@link PushHandler}
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class PushAtmosphereHandler extends AbstractReflectorAtmosphereHandler
+ implements Serializable {
+
+ private PushHandler pushHandler = null;
+
+ public void setPushHandler(PushHandler pushHandler) {
+ this.pushHandler = pushHandler;
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(PushAtmosphereHandler.class.getName());
+ }
+
+ @Override
+ public void onStateChange(AtmosphereResourceEvent event) throws IOException {
+ super.onStateChange(event);
+ if (pushHandler == null) {
+ getLogger()
+ .warning(
+ "AtmosphereHandler.onStateChange called before PushHandler has been set. This should really not happen");
+ return;
+ }
+
+ if (event.isCancelled() || event.isResumedOnTimeout()) {
+ pushHandler.connectionLost(event);
+ }
+ }
+
+ @Override
+ public void onRequest(AtmosphereResource resource) {
+ if (pushHandler == null) {
+ getLogger()
+ .warning(
+ "AtmosphereHandler.onRequest called before PushHandler has been set. This should really not happen");
+ return;
+ }
+
+ AtmosphereRequest req = resource.getRequest();
+
+ if (req.getMethod().equalsIgnoreCase("GET")) {
+ onConnect(resource);
+ } else if (req.getMethod().equalsIgnoreCase("POST")) {
+ onMessage(resource);
+ }
+ }
+
+ /**
+ * Called when the client sends a message through the push channel
+ *
+ * @param resource
+ */
+ private void onMessage(AtmosphereResource resource) {
+ pushHandler.onMessage(resource);
+ }
+
+ /**
+ * Called when the client sends the first request (to establish a push
+ * connection)
+ *
+ * @param resource
+ */
+ private void onConnect(AtmosphereResource resource) {
+ resource.addEventListener(new AtmosphereResourceListener());
+
+ pushHandler.onConnect(resource);
+ }
+
+ private class AtmosphereResourceListener extends
+ AtmosphereResourceEventListenerAdapter implements Serializable {
+
+ @Override
+ public void onDisconnect(AtmosphereResourceEvent event) {
+ // Log event on trace level
+ super.onDisconnect(event);
+ pushHandler.connectionLost(event);
+ }
+
+ @Override
+ public void onThrowable(AtmosphereResourceEvent event) {
+ getLogger().log(Level.SEVERE, "Exception in push connection",
+ event.throwable());
+ pushHandler.connectionLost(event);
+ }
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java
index ea937d279e..552f2e9e03 100644
--- a/server/src/com/vaadin/server/communication/PushHandler.java
+++ b/server/src/com/vaadin/server/communication/PushHandler.java
@@ -22,14 +22,11 @@ import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.atmosphere.cpr.AtmosphereHandler;
import org.atmosphere.cpr.AtmosphereRequest;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResource.TRANSPORT;
import org.atmosphere.cpr.AtmosphereResourceEvent;
-import org.atmosphere.cpr.AtmosphereResourceEventListenerAdapter;
import org.atmosphere.cpr.AtmosphereResourceImpl;
-import org.atmosphere.handler.AbstractReflectorAtmosphereHandler;
import com.vaadin.server.ErrorEvent;
import com.vaadin.server.ErrorHandler;
@@ -50,37 +47,13 @@ import com.vaadin.ui.UI;
import elemental.json.JsonException;
/**
- * Establishes bidirectional ("push") communication channels
+ * Handles incoming push connections and messages and dispatches them to the
+ * correct {@link UI}/ {@link AtmospherePushConnection}
*
* @author Vaadin Ltd
* @since 7.1
*/
-public class PushHandler extends AtmosphereResourceEventListenerAdapter {
-
- AtmosphereHandler handler = new AbstractReflectorAtmosphereHandler() {
-
- @Override
- public void onStateChange(AtmosphereResourceEvent event)
- throws IOException {
- super.onStateChange(event);
- if (event.isCancelled() || event.isResumedOnTimeout()) {
- connectionLost(event);
- }
- }
-
- @Override
- public void onRequest(AtmosphereResource resource) {
- AtmosphereRequest req = resource.getRequest();
-
- if (req.getMethod().equalsIgnoreCase("GET")) {
- callWithUi(resource, establishCallback, false);
- } else if (req.getMethod().equalsIgnoreCase("POST")) {
- callWithUi(resource, receiveCallback,
- resource.transport() == TRANSPORT.WEBSOCKET);
- }
- }
-
- };
+public class PushHandler {
/**
* Callback interface used internally to process an event with the
@@ -103,8 +76,6 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter {
"New push connection for resource {0} with transport {1}",
new Object[] { resource.uuid(), resource.transport() });
- resource.addEventListener(PushHandler.this);
-
resource.getResponse().setContentType("text/plain; charset=UTF-8");
VaadinSession session = ui.getSession();
@@ -325,21 +296,7 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter {
}
}
- @Override
- public void onDisconnect(AtmosphereResourceEvent event) {
- // Log event on trace level
- super.onDisconnect(event);
- connectionLost(event);
- }
-
- @Override
- public void onThrowable(AtmosphereResourceEvent event) {
- getLogger().log(Level.SEVERE, "Exception in push connection",
- event.throwable());
- connectionLost(event);
- }
-
- private void connectionLost(AtmosphereResourceEvent event) {
+ void connectionLost(AtmosphereResourceEvent event) {
// We don't want to use callWithUi here, as it assumes there's a client
// request active and does requestStart and requestEnd among other
// things.
@@ -506,4 +463,28 @@ public class PushHandler extends AtmosphereResourceEventListenerAdapter {
private static final Logger getLogger() {
return Logger.getLogger(PushHandler.class.getName());
}
+
+ /**
+ * Called when a new push connection is requested to be opened by the client
+ *
+ * @since
+ * @param resource
+ * The related atmosphere resources
+ */
+ void onConnect(AtmosphereResource resource) {
+ callWithUi(resource, establishCallback, false);
+ }
+
+ /**
+ * Called when a message is received through the push connection
+ *
+ * @since
+ * @param resource
+ * The related atmosphere resources
+ */
+ void onMessage(AtmosphereResource resource) {
+ callWithUi(resource, receiveCallback,
+ resource.transport() == TRANSPORT.WEBSOCKET);
+ }
+
}
diff --git a/server/src/com/vaadin/server/communication/PushRequestHandler.java b/server/src/com/vaadin/server/communication/PushRequestHandler.java
index 74165a4988..0e3ec300b4 100644
--- a/server/src/com/vaadin/server/communication/PushRequestHandler.java
+++ b/server/src/com/vaadin/server/communication/PushRequestHandler.java
@@ -17,6 +17,8 @@
package com.vaadin.server.communication;
import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
@@ -25,6 +27,8 @@ import org.atmosphere.cache.UUIDBroadcasterCache;
import org.atmosphere.client.TrackMessageSizeInterceptor;
import org.atmosphere.cpr.ApplicationConfig;
import org.atmosphere.cpr.AtmosphereFramework;
+import org.atmosphere.cpr.AtmosphereFramework.AtmosphereHandlerWrapper;
+import org.atmosphere.cpr.AtmosphereHandler;
import org.atmosphere.cpr.AtmosphereInterceptor;
import org.atmosphere.cpr.AtmosphereRequest;
import org.atmosphere.cpr.AtmosphereResponse;
@@ -48,7 +52,8 @@ import com.vaadin.shared.communication.PushConstants;
/**
* Handles requests to open a push (bidirectional) communication channel between
* the client and the server. After the initial request, communication through
- * the push channel is managed by {@link PushHandler}.
+ * the push channel is managed by {@link PushAtmosphereHandler} and
+ * {@link PushHandler}
*
* @author Vaadin Ltd
* @since 7.1
@@ -62,10 +67,85 @@ public class PushRequestHandler implements RequestHandler,
public PushRequestHandler(VaadinServletService service)
throws ServiceException {
+ service.addServiceDestroyListener(new ServiceDestroyListener() {
+ @Override
+ public void serviceDestroy(ServiceDestroyEvent event) {
+ destroy();
+ }
+ });
+
final ServletConfig vaadinServletConfig = service.getServlet()
.getServletConfig();
- atmosphere = new AtmosphereFramework() {
+ pushHandler = new PushHandler(service);
+
+ atmosphere = getPreInitializedAtmosphere(vaadinServletConfig);
+ if (atmosphere == null) {
+ // Not initialized by JSR356WebsocketInitializer
+ getLogger().fine(
+ "Initializing Atmosphere for servlet "
+ + vaadinServletConfig.getServletName());
+ try {
+ atmosphere = initAtmosphere(vaadinServletConfig);
+ } catch (Exception e) {
+ getLogger().log(
+ Level.WARNING,
+ "Failed to initialize Atmosphere for "
+ + service.getServlet().getServletName()
+ + ". Push will not work.", e);
+ return;
+ }
+ } else {
+ getLogger().fine(
+ "Using pre-initialized Atmosphere for servlet "
+ + vaadinServletConfig.getServletName());
+ }
+
+ for (AtmosphereHandlerWrapper handlerWrapper : atmosphere
+ .getAtmosphereHandlers().values()) {
+ AtmosphereHandler handler = handlerWrapper.atmosphereHandler;
+ if (handler instanceof PushAtmosphereHandler) {
+ // Map the (possibly pre-initialized) handler to the actual push
+ // handler
+ ((PushAtmosphereHandler) handler).setPushHandler(pushHandler);
+ }
+
+ }
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(PushRequestHandler.class.getName());
+ }
+
+ /**
+ * Returns an AtmosphereFramework instance which was initialized in the
+ * servlet context init phase by {@link JSR356WebsocketInitializer}, if such
+ * exists
+ */
+ private AtmosphereFramework getPreInitializedAtmosphere(
+ ServletConfig vaadinServletConfig) {
+ String attributeName = JSR356WebsocketInitializer
+ .getAttributeName(vaadinServletConfig.getServletName());
+ Object framework = vaadinServletConfig.getServletContext()
+ .getAttribute(attributeName);
+ if (framework != null && framework instanceof AtmosphereFramework) {
+ return (AtmosphereFramework) framework;
+ }
+
+ return null;
+ }
+
+ /**
+ * Initializes Atmosphere for the given ServletConfiguration
+ *
+ * @since
+ * @param vaadinServletConfig
+ * The servlet configuration for the servlet which should have
+ * Atmosphere support
+ */
+ static AtmosphereFramework initAtmosphere(
+ final ServletConfig vaadinServletConfig) {
+ AtmosphereFramework atmosphere = new AtmosphereFramework() {
@Override
protected void analytics() {
// Overridden to disable version number check
@@ -81,15 +161,7 @@ public class PushRequestHandler implements RequestHandler,
}
};
- service.addServiceDestroyListener(new ServiceDestroyListener() {
- @Override
- public void serviceDestroy(ServiceDestroyEvent event) {
- destroy();
- }
- });
-
- pushHandler = new PushHandler(service);
- atmosphere.addAtmosphereHandler("/*", pushHandler.handler);
+ atmosphere.addAtmosphereHandler("/*", new PushAtmosphereHandler());
atmosphere.addInitParameter(ApplicationConfig.BROADCASTER_CACHE,
UUIDBroadcasterCache.class.getName());
atmosphere.addInitParameter(ApplicationConfig.ANNOTATION_PROCESSOR,
@@ -131,8 +203,9 @@ public class PushRequestHandler implements RequestHandler,
trackMessageSize.configure(atmosphere.getAtmosphereConfig());
atmosphere.interceptor(trackMessageSize);
} catch (ServletException e) {
- throw new ServiceException("Atmosphere init failed", e);
+ throw new RuntimeException("Atmosphere init failed", e);
}
+ return atmosphere;
}
@Override
@@ -144,6 +217,11 @@ public class PushRequestHandler implements RequestHandler,
}
if (request instanceof VaadinServletRequest) {
+ if (atmosphere == null) {
+ response.sendError(500,
+ "Atmosphere initialization failed. No push available.");
+ return true;
+ }
try {
atmosphere.doCometSupport(AtmosphereRequest
.wrap((VaadinServletRequest) request),
diff --git a/server/src/com/vaadin/ui/AbstractColorPicker.java b/server/src/com/vaadin/ui/AbstractColorPicker.java
index 608a42d33b..3212d1b23f 100644
--- a/server/src/com/vaadin/ui/AbstractColorPicker.java
+++ b/server/src/com/vaadin/ui/AbstractColorPicker.java
@@ -17,6 +17,10 @@ package com.vaadin.ui;
import java.io.Serializable;
import java.lang.reflect.Method;
+import java.util.Collection;
+
+import org.jsoup.nodes.Attributes;
+import org.jsoup.nodes.Element;
import com.vaadin.shared.ui.colorpicker.Color;
import com.vaadin.shared.ui.colorpicker.ColorPickerServerRpc;
@@ -27,6 +31,8 @@ import com.vaadin.ui.components.colorpicker.ColorChangeEvent;
import com.vaadin.ui.components.colorpicker.ColorChangeListener;
import com.vaadin.ui.components.colorpicker.ColorPickerPopup;
import com.vaadin.ui.components.colorpicker.ColorSelector;
+import com.vaadin.ui.declarative.DesignAttributeHandler;
+import com.vaadin.ui.declarative.DesignContext;
/**
* An abstract class that defines default implementation for a color picker
@@ -276,6 +282,16 @@ public abstract class AbstractColorPicker extends AbstractComponent implements
}
/**
+ * Gets the style for the popup window
+ *
+ * @since
+ * @return popup window style
+ */
+ public PopupStyle getPopupStyle() {
+ return popupStyle;
+ }
+
+ /**
* Set the visibility of the RGB Tab
*
* @param visible
@@ -294,6 +310,16 @@ public abstract class AbstractColorPicker extends AbstractComponent implements
}
/**
+ * Gets the visibility of the RGB Tab
+ *
+ * @since
+ * @return visibility of the RGB tab
+ */
+ public boolean getRGBVisibility() {
+ return rgbVisible;
+ }
+
+ /**
* Set the visibility of the HSV Tab
*
* @param visible
@@ -311,6 +337,16 @@ public abstract class AbstractColorPicker extends AbstractComponent implements
}
/**
+ * Gets the visibility of the HSV Tab
+ *
+ * @since
+ * @return visibility of the HSV tab
+ */
+ public boolean getHSVVisibility() {
+ return hsvVisible;
+ }
+
+ /**
* Set the visibility of the Swatches Tab
*
* @param visible
@@ -328,6 +364,16 @@ public abstract class AbstractColorPicker extends AbstractComponent implements
}
/**
+ * Gets the visibility of the Swatches Tab
+ *
+ * @since
+ * @return visibility of the swatches tab
+ */
+ public boolean getSwatchesVisibility() {
+ return swatchesVisible;
+ }
+
+ /**
* Sets the visibility of the Color History
*
* @param visible
@@ -341,6 +387,16 @@ public abstract class AbstractColorPicker extends AbstractComponent implements
}
/**
+ * Gets the visibility of the Color History
+ *
+ * @since
+ * @return visibility of color history
+ */
+ public boolean getHistoryVisibility() {
+ return historyVisible;
+ }
+
+ /**
* Sets the visibility of the CSS color code text field
*
* @param visible
@@ -353,6 +409,16 @@ public abstract class AbstractColorPicker extends AbstractComponent implements
}
}
+ /**
+ * Gets the visibility of CSS color code text field
+ *
+ * @since
+ * @return visibility of css color code text field
+ */
+ public boolean getTextfieldVisibility() {
+ return textfieldVisible;
+ }
+
@Override
protected ColorPickerState getState() {
return (ColorPickerState) super.getState();
@@ -473,4 +539,49 @@ public abstract class AbstractColorPicker extends AbstractComponent implements
public boolean isHtmlContentAllowed() {
return isCaptionAsHtml();
}
+
+ @Override
+ public void readDesign(Element design, DesignContext designContext) {
+ super.readDesign(design, designContext);
+
+ Attributes attributes = design.attributes();
+ if (design.hasAttr("color")) {
+ // Ignore the # character
+ String hexColor = DesignAttributeHandler.readAttribute("color",
+ attributes, String.class).substring(1);
+ setColor(new Color(Integer.parseInt(hexColor, 16)));
+ }
+ if (design.hasAttr("popup-style")) {
+ setPopupStyle(PopupStyle.valueOf("POPUP_"
+ + attributes.get("popup-style").toUpperCase()));
+ }
+ if (design.hasAttr("position")) {
+ String[] position = attributes.get("position").split(",");
+ setPosition(Integer.parseInt(position[0]),
+ Integer.parseInt(position[1]));
+ }
+ }
+
+ @Override
+ public void writeDesign(Element design, DesignContext designContext) {
+ super.writeDesign(design, designContext);
+
+ Attributes attribute = design.attributes();
+ DesignAttributeHandler.writeAttribute("color", attribute,
+ color.getCSS(), Color.WHITE.getCSS(), String.class);
+ DesignAttributeHandler.writeAttribute("popup-style", attribute,
+ (popupStyle == PopupStyle.POPUP_NORMAL ? "normal" : "simple"),
+ "normal", String.class);
+ DesignAttributeHandler.writeAttribute("position", attribute, positionX
+ + "," + positionY, "0,0", String.class);
+ }
+
+ @Override
+ protected Collection<String> getCustomAttributes() {
+ Collection<String> result = super.getCustomAttributes();
+ result.add("color");
+ result.add("position");
+ result.add("popup-style");
+ return result;
+ }
}
diff --git a/server/src/com/vaadin/ui/AbstractComponent.java b/server/src/com/vaadin/ui/AbstractComponent.java
index ebe438b908..dae073904b 100644
--- a/server/src/com/vaadin/ui/AbstractComponent.java
+++ b/server/src/com/vaadin/ui/AbstractComponent.java
@@ -982,11 +982,6 @@ public abstract class AbstractComponent extends AbstractClientConnector
Integer.class));
}
- // handle responsive
- if (attr.hasKey("responsive")) {
- setResponsive(DesignAttributeHandler.getFormatter().parse(
- attr.get("responsive"), Boolean.class));
- }
// check for unsupported attributes
Set<String> supported = new HashSet<String>();
supported.addAll(getDefaultAttributes());
@@ -1032,11 +1027,11 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Toggles responsiveness of this component.
*
- * @since 7.4
+ * @since
* @param responsive
* boolean enables responsiveness, false disables
*/
- private void setResponsive(boolean responsive) {
+ public void setResponsive(boolean responsive) {
if (responsive) {
// make responsive if necessary
if (!isResponsive()) {
@@ -1057,10 +1052,10 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Returns true if the component is responsive
*
- * @since 7.4
+ * @since
* @return true if the component is responsive
*/
- private boolean isResponsive() {
+ public boolean isResponsive() {
for (Extension e : getExtensions()) {
if (e instanceof Responsive) {
return true;
@@ -1233,8 +1228,8 @@ public abstract class AbstractComponent extends AbstractClientConnector
private static final String[] customAttributes = new String[] { "width",
"height", "debug-id", "error", "width-auto", "height-auto",
- "width-full", "height-full", "size-auto", "size-full",
- "responsive", "immediate", "locale", "read-only", "_id" };
+ "width-full", "height-full", "size-auto", "size-full", "immediate",
+ "locale", "read-only", "_id" };
/*
* (non-Javadoc)
@@ -1280,10 +1275,6 @@ public abstract class AbstractComponent extends AbstractClientConnector
((Focusable) def).getTabIndex(), Integer.class);
}
- // handle responsive
- if (isResponsive()) {
- attr.put("responsive", "");
- }
}
/*
diff --git a/server/src/com/vaadin/ui/AbstractSelect.java b/server/src/com/vaadin/ui/AbstractSelect.java
index 06790ca78d..4c5e6b6ea3 100644
--- a/server/src/com/vaadin/ui/AbstractSelect.java
+++ b/server/src/com/vaadin/ui/AbstractSelect.java
@@ -2222,4 +2222,30 @@ public abstract class AbstractSelect extends AbstractField<Object> implements
}
}
}
+
+ @Override
+ public void writeDesign(Element design, DesignContext designContext) {
+ // Write default attributes
+ super.writeDesign(design, designContext);
+
+ // Write options if warranted
+ if (designContext.shouldWriteData(this)) {
+ for (Object itemId : getItemIds()) {
+ Element optionElement = design.appendElement("option");
+
+ optionElement.html(getItemCaption(itemId));
+
+ Resource icon = getItemIcon(itemId);
+ if (icon != null) {
+ DesignAttributeHandler.writeAttribute("icon",
+ optionElement.attributes(), icon, null,
+ Resource.class);
+ }
+
+ if (isSelected(itemId)) {
+ optionElement.attr("selected", "");
+ }
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java b/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java
index 244feb3bb9..767ae66515 100644
--- a/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java
+++ b/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java
@@ -19,6 +19,7 @@ import java.util.Collections;
import java.util.Iterator;
import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
import com.vaadin.server.ComponentSizeValidator;
import com.vaadin.server.VaadinService;
@@ -288,17 +289,33 @@ public abstract class AbstractSingleComponentContainer extends
public void readDesign(Element design, DesignContext designContext) {
// process default attributes
super.readDesign(design, designContext);
- // handle child element, checking that the design specifies at most one
- // child
- int childCount = design.children().size();
- if (childCount > 1) {
+ readDesignChildren(design.children(), designContext);
+ }
+
+ /**
+ * Reads the content component from the list of child elements of a design.
+ * The list must be empty or contain a single element; if the design
+ * contains multiple child elements, a DesignException is thrown. This
+ * method should be overridden by subclasses whose design may contain
+ * non-content child elements.
+ *
+ * @param children
+ * the child elements of the design that is being read
+ * @param context
+ * the DesignContext instance used to parse the design
+ *
+ * @throws DesignException
+ * if there are multiple child elements
+ * @throws DesignException
+ * if a child element could not be parsed as a Component
+ */
+ protected void readDesignChildren(Elements children, DesignContext context) {
+ if (children.size() > 1) {
throw new DesignException("The container of type "
+ getClass().toString()
+ " can have only one child component.");
- } else if (childCount == 1) {
- Element childElement = design.children().get(0);
- Component newChild = designContext.readDesign(childElement);
- setContent(newChild);
+ } else if (children.size() == 1) {
+ setContent(context.readDesign(children.first()));
}
}
diff --git a/server/src/com/vaadin/ui/Component.java b/server/src/com/vaadin/ui/Component.java
index 9e0816a398..adef4b69c5 100644
--- a/server/src/com/vaadin/ui/Component.java
+++ b/server/src/com/vaadin/ui/Component.java
@@ -149,8 +149,8 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
*
* <p>
* Each style name will occur in two versions: one as specified and one that
- * is prefixed wil the style name of the component. For example, if you have
- * a {@code Button} component and give it "{@code mystyle}" style, the
+ * is prefixed with the style name of the component. For example, if you
+ * have a {@code Button} component and give it "{@code mystyle}" style, the
* component will have both "{@code mystyle}" and "{@code v-button-mystyle}"
* styles. You could then style the component either with:
* </p>
@@ -253,9 +253,10 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
public boolean isEnabled();
/**
- * Enables or disables the component. The user can not interact disabled
- * components, which are shown with a style that indicates the status,
- * usually shaded in light gray color. Components are enabled by default.
+ * Enables or disables the component. The user can not interact with
+ * disabled components, which are shown with a style that indicates the
+ * status, usually shaded in light gray color. Components are enabled by
+ * default.
*
* <pre>
* Button enabled = new Button(&quot;Enabled&quot;);
@@ -909,7 +910,7 @@ public interface Component extends ClientConnector, Sizeable, Serializable {
* </pre>
*
* @param event
- * the event that has occured.
+ * the event that has occurred.
*/
public void componentEvent(Component.Event event);
}
diff --git a/server/src/com/vaadin/ui/PopupView.java b/server/src/com/vaadin/ui/PopupView.java
index 2a2da26b62..12034cb56c 100644
--- a/server/src/com/vaadin/ui/PopupView.java
+++ b/server/src/com/vaadin/ui/PopupView.java
@@ -20,8 +20,13 @@ import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Iterator;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.parser.Tag;
+
import com.vaadin.shared.ui.popupview.PopupViewServerRpc;
import com.vaadin.shared.ui.popupview.PopupViewState;
+import com.vaadin.ui.declarative.DesignContext;
/**
*
@@ -61,9 +66,15 @@ public class PopupView extends AbstractComponent implements HasComponents {
/* Constructors */
- private PopupView() {
+ /**
+ * This is an internal constructor. Use
+ * {@link PopupView#PopupView(String, Component)} instead.
+ */
+ @Deprecated
+ public PopupView() {
registerRpc(rpc);
setHideOnMouseOut(true);
+ setContent(createContent("", new Label("")));
}
/**
@@ -77,18 +88,7 @@ public class PopupView extends AbstractComponent implements HasComponents {
* the full, Component-type representation
*/
public PopupView(final java.lang.String small, final Component large) {
- this(new PopupView.Content() {
- @Override
- public java.lang.String getMinimizedValueAsHTML() {
- return small;
- }
-
- @Override
- public Component getPopupComponent() {
- return large;
- }
- });
-
+ this(createContent(small, large));
}
/**
@@ -104,6 +104,30 @@ public class PopupView extends AbstractComponent implements HasComponents {
}
/**
+ * Creates a Content from given text representation and popup content.
+ *
+ * @param minimizedValue
+ * text representation when popup is hidden
+ * @param popupContent
+ * popup content
+ * @return content with given data
+ */
+ protected static Content createContent(final String minimizedValue,
+ final Component popupContent) {
+ return new Content() {
+ @Override
+ public String getMinimizedValueAsHTML() {
+ return minimizedValue;
+ }
+
+ @Override
+ public Component getPopupComponent() {
+ return popupContent;
+ }
+ };
+ }
+
+ /**
* This method will replace the current content of the panel with a new one.
*
* @param newContent
@@ -233,6 +257,44 @@ public class PopupView extends AbstractComponent implements HasComponents {
}
@Override
+ public void readDesign(Element design, DesignContext designContext) {
+
+ // Read content first to avoid NPE when setting popup visible
+ Component popupContent = null;
+ String minimizedValue = "";
+ for (Node childNode : design.childNodes()) {
+ if (childNode instanceof Element) {
+ Element child = (Element) childNode;
+ if (child.tagName().equals("popup-content")) {
+ popupContent = designContext.readDesign(child.child(0));
+ } else {
+ minimizedValue += child.toString();
+ }
+ } else {
+ minimizedValue += childNode.toString();
+ }
+ }
+ setContent(createContent(minimizedValue.trim(), popupContent));
+
+ super.readDesign(design, designContext);
+ }
+
+ @Override
+ public void writeDesign(Element design, DesignContext designContext) {
+ super.writeDesign(design, designContext);
+
+ Element popupContent = new Element(Tag.valueOf("popup-content"), "");
+ popupContent.appendChild(designContext.createElement(content
+ .getPopupComponent()));
+
+ String minimizedHTML = content.getMinimizedValueAsHTML();
+ if (minimizedHTML != null && !minimizedHTML.isEmpty()) {
+ design.append(minimizedHTML);
+ }
+ design.appendChild(popupContent);
+ }
+
+ @Override
protected PopupViewState getState() {
return (PopupViewState) super.getState();
}
diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java
index 316564c7e3..347bb8fbff 100644
--- a/server/src/com/vaadin/ui/Table.java
+++ b/server/src/com/vaadin/ui/Table.java
@@ -700,7 +700,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Gets the headers of the columns.
*
* <p>
- * The headers match the property id:s given my the set visible column
+ * The headers match the property id:s given by the set visible column
* headers. The table must be set in either
* {@link #COLUMN_HEADER_MODE_EXPLICIT} or
* {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the
@@ -727,7 +727,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Sets the headers of the columns.
*
* <p>
- * The headers match the property id:s given my the set visible column
+ * The headers match the property id:s given by the set visible column
* headers. The table must be set in either
* {@link #COLUMN_HEADER_MODE_EXPLICIT} or
* {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the
@@ -760,7 +760,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Gets the icons of the columns.
*
* <p>
- * The icons in headers match the property id:s given my the set visible
+ * The icons in headers match the property id:s given by the set visible
* column headers. The table must be set in either
* {@link #COLUMN_HEADER_MODE_EXPLICIT} or
* {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the headers
@@ -787,7 +787,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Sets the icons of the columns.
*
* <p>
- * The icons in headers match the property id:s given my the set visible
+ * The icons in headers match the property id:s given by the set visible
* column headers. The table must be set in either
* {@link #COLUMN_HEADER_MODE_EXPLICIT} or
* {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the headers
@@ -887,7 +887,7 @@ public class Table extends AbstractSelect implements Action.Container,
}
/**
- * Sets columns width (in pixels). Theme may not necessary respect very
+ * Sets columns width (in pixels). Theme may not necessarily respect very
* small or very big values. Setting width to -1 (default) means that theme
* will make decision of width.
*
@@ -896,9 +896,9 @@ public class Table extends AbstractSelect implements Action.Container,
* is used. See @link {@link #setColumnExpandRatio(Object, float)}.
*
* @param propertyId
- * colunmns property id
+ * columns property id
* @param width
- * width to be reserved for colunmns content
+ * width to be reserved for columns content
* @since 4.0.3
*/
public void setColumnWidth(Object propertyId, int width) {
@@ -975,7 +975,7 @@ public class Table extends AbstractSelect implements Action.Container,
}
/**
- * Gets the column expand ratio for a columnd. See
+ * Gets the column expand ratio for a column. See
* {@link #setColumnExpandRatio(Object, float)}
*
* @param propertyId
@@ -1091,7 +1091,7 @@ public class Table extends AbstractSelect implements Action.Container,
*/
public Object getCurrentPageFirstItemId() {
- // Priorise index over id if indexes are supported
+ // Prioritise index over id if indexes are supported
if (items instanceof Container.Indexed) {
final int index = getCurrentPageFirstItemIndex();
Object id = null;
@@ -1193,7 +1193,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Gets the icon Resource for the specified column.
*
* @param propertyId
- * the propertyId indentifying the column.
+ * the propertyId identifying the column.
* @return the icon for the specified column; null if the column has no icon
* set, or if the column is not visible.
*/
@@ -2598,7 +2598,7 @@ public class Table extends AbstractSelect implements Action.Container,
* types.
* @param itemId
* the Id the new row. If null, a new id is automatically
- * assigned. If given, the table cant already have a item with
+ * assigned. If given, the table cannot already have a item with
* given id.
* @return Returns item id for the new row. Returns null if operation fails.
*/
@@ -4326,7 +4326,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Adds a new property to the table and show it as a visible column.
*
* @param propertyId
- * the Id of the proprty.
+ * the Id of the property.
* @param type
* the class of the property.
* @param defaultValue
@@ -4361,7 +4361,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Adds a new property to the table and show it as a visible column.
*
* @param propertyId
- * the Id of the proprty
+ * the Id of the property
* @param type
* the class of the property
* @param defaultValue
@@ -4571,7 +4571,7 @@ public class Table extends AbstractSelect implements Action.Container,
disableContentRefreshing();
super.containerPropertySetChange(event);
- // sanitetize visibleColumns. note that we are not adding previously
+ // sanitize visibleColumns. note that we are not adding previously
// non-existing properties as columns
Collection<?> containerPropertyIds = getContainerDataSource()
.getContainerPropertyIds();
@@ -4757,11 +4757,11 @@ public class Table extends AbstractSelect implements Action.Container,
* If table is editable a editor of type Field is created for each table
* cell. The assigned FieldFactory is used to create the instances.
*
- * To provide custom editors for table cells create a class implementins the
+ * To provide custom editors for table cells create a class implementing the
* FieldFactory interface, and assign it to table, and set the editable
* property to true.
*
- * @return true if table is editable, false oterwise.
+ * @return true if table is editable, false otherwise.
* @see Field
* @see FieldFactory
*
@@ -4776,7 +4776,7 @@ public class Table extends AbstractSelect implements Action.Container,
* If table is editable a editor of type Field is created for each table
* cell. The assigned FieldFactory is used to create the instances.
*
- * To provide custom editors for table cells create a class implementins the
+ * To provide custom editors for table cells create a class implementing the
* FieldFactory interface, and assign it to table, and set the editable
* property to true.
*
@@ -5346,7 +5346,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the property id of the column which header was pressed
*
- * @return The column propety id
+ * @return The column property id
*/
public Object getPropertyId() {
return columnPropertyId;
@@ -5396,7 +5396,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the property id of the column which header was pressed
*
- * @return The column propety id
+ * @return The column property id
*/
public Object getPropertyId() {
return columnPropertyId;
diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java
index 653b620746..e7764ffd8d 100644
--- a/server/src/com/vaadin/ui/Window.java
+++ b/server/src/com/vaadin/ui/Window.java
@@ -18,11 +18,18 @@ package com.vaadin.ui;
import java.io.Serializable;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
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 org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.BlurNotifier;
@@ -42,6 +49,9 @@ import com.vaadin.shared.ui.window.WindowMode;
import com.vaadin.shared.ui.window.WindowRole;
import com.vaadin.shared.ui.window.WindowServerRpc;
import com.vaadin.shared.ui.window.WindowState;
+import com.vaadin.ui.declarative.DesignAttributeHandler;
+import com.vaadin.ui.declarative.DesignContext;
+import com.vaadin.ui.declarative.DesignException;
import com.vaadin.util.ReflectTools;
/**
@@ -1283,4 +1293,116 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
public String getTabStopBottomAssistiveText() {
return getState(false).assistiveTabStopBottomText;
}
+
+ @Override
+ public void readDesign(Element design, DesignContext context) {
+ super.readDesign(design, context);
+
+ if (design.hasAttr("center")) {
+ center();
+ }
+ if (design.hasAttr("position")) {
+ String[] position = design.attr("position").split(",");
+ setPositionX(Integer.parseInt(position[0]));
+ setPositionY(Integer.parseInt(position[1]));
+ }
+ if (design.hasAttr("close-shortcut")) {
+ ShortcutAction shortcut = DesignAttributeHandler
+ .readAttribute("close-shortcut", design.attributes(),
+ ShortcutAction.class);
+ setCloseShortcut(shortcut.getKeyCode(), shortcut.getModifiers());
+ }
+ }
+
+ /**
+ * Reads the content and possible assistive descriptions from the list of
+ * child elements of a design. If an element has an
+ * {@code :assistive-description} attribute, adds the parsed component to
+ * the list of components used as the assistive description of this Window.
+ * Otherwise, sets the component as the content of this Window. If there are
+ * multiple non-description elements, throws a DesignException.
+ *
+ * @param children
+ * child elements in a design
+ * @param context
+ * the DesignContext instance used to parse the design
+ *
+ * @throws DesignException
+ * if there are multiple non-description child elements
+ * @throws DesignException
+ * if a child element could not be parsed as a Component
+ *
+ * @see #setContent(Component)
+ * @see #setAssistiveDescription(Component...)
+ */
+ @Override
+ protected void readDesignChildren(Elements children, DesignContext context) {
+ List<Component> descriptions = new ArrayList<Component>();
+ Elements content = new Elements();
+
+ for (Element child : children) {
+ if (child.hasAttr(":assistive-description")) {
+ descriptions.add(context.readDesign(child));
+ } else {
+ content.add(child);
+ }
+ }
+ super.readDesignChildren(content, context);
+ setAssistiveDescription(descriptions.toArray(new Component[0]));
+ }
+
+ @Override
+ public void writeDesign(Element design, DesignContext context) {
+ super.writeDesign(design, context);
+
+ Window def = context.getDefaultInstance(this);
+
+ if (getState().centered) {
+ design.attr("center", "");
+ }
+
+ DesignAttributeHandler.writeAttribute("position", design.attributes(),
+ getPosition(), def.getPosition(), String.class);
+
+ CloseShortcut shortcut = getCloseShortcut();
+ if (shortcut != null) {
+ // TODO What if several close shortcuts??
+
+ CloseShortcut defShortcut = def.getCloseShortcut();
+ if (defShortcut == null
+ || shortcut.getKeyCode() != defShortcut.getKeyCode()
+ || !Arrays.equals(shortcut.getModifiers(),
+ defShortcut.getModifiers())) {
+ DesignAttributeHandler.writeAttribute("close-shortcut",
+ design.attributes(), shortcut, null,
+ CloseShortcut.class);
+ }
+ }
+
+ for (Component c : getAssistiveDescription()) {
+ Element child = context.createElement(c).attr(
+ ":assistive-description", "");
+ design.appendChild(child);
+ }
+ }
+
+ private String getPosition() {
+ return getPositionX() + "," + getPositionY();
+ }
+
+ private CloseShortcut getCloseShortcut() {
+ Iterator<CloseShortcut> i = getCloseShortcuts().iterator();
+ return i.hasNext() ? i.next() : null;
+ }
+
+ @Override
+ protected Collection<String> getCustomAttributes() {
+ Collection<String> result = super.getCustomAttributes();
+ result.add("center");
+ result.add("position");
+ result.add("position-y");
+ result.add("position-x");
+ result.add("close-shortcut");
+ return result;
+ }
}
diff --git a/server/src/com/vaadin/ui/declarative/DesignContext.java b/server/src/com/vaadin/ui/declarative/DesignContext.java
index f991b3013a..fe3abcfb77 100644
--- a/server/src/com/vaadin/ui/declarative/DesignContext.java
+++ b/server/src/com/vaadin/ui/declarative/DesignContext.java
@@ -75,6 +75,8 @@ public class DesignContext implements Serializable {
// component creation listeners
private List<ComponentCreationListener> listeners = new ArrayList<ComponentCreationListener>();
+ private ShouldWriteDataDelegate shouldWriteDataDelegate = ShouldWriteDataDelegate.DEFAULT;
+
public DesignContext(Document doc) {
this.doc = doc;
// Initialize the mapping between prefixes and package names.
@@ -168,16 +170,16 @@ public class DesignContext implements Serializable {
* component, the mapping from c to the string is removed. Similarly, if
* component was mapped to some string s different from localId, the mapping
* from s to component is removed.
- *
- * @param localId
- * The new local id of the component.
* @param component
* The component whose local id is to be set.
+ * @param localId
+ * The new local id of the component.
+ *
* @return true, if there already was a local id mapping from the string to
* some component or from the component to some string. Otherwise
* returns false.
*/
- private boolean mapLocalId(String localId, Component component) {
+ public boolean setComponentLocalId(Component component, String localId) {
return twoWayMap(localId, component, localIdToComponent,
componentToLocalId);
}
@@ -464,7 +466,7 @@ public class DesignContext implements Serializable {
// from the attributes of componentDesign
if (attributes.hasKey(LOCAL_ID_ATTRIBUTE)) {
String localId = attributes.get(LOCAL_ID_ATTRIBUTE);
- boolean mappingExists = mapLocalId(localId, component);
+ boolean mappingExists = setComponentLocalId(component, localId);
if (mappingExists) {
throw new DesignException(
"the following local id is not unique: " + localId);
@@ -661,4 +663,56 @@ public class DesignContext implements Serializable {
return true;
}
+
+ /**
+ * Determines whether the container data of a component should be written
+ * out by delegating to a {@link ShouldWriteDataDelegate}. The default
+ * delegate assumes that all component data is provided by a data source
+ * connected to a back end system and that the data should thus not be
+ * written.
+ *
+ * @since
+ * @see #setShouldWriteDataDelegate(ShouldWriteDataDelegate)
+ * @param component
+ * the component to check
+ * @return <code>true</code> if container data should be written out for the
+ * provided component; otherwise <code>false</code>.
+ */
+ public boolean shouldWriteData(Component component) {
+ return getShouldWriteDataDelegate().shouldWriteData(component);
+ }
+
+ /**
+ * Sets the delegate that determines whether the container data of a
+ * component should be written out.
+ *
+ * @since
+ * @see #shouldWriteChildren(Component, Component)
+ * @see #getShouldWriteDataDelegate()
+ * @param shouldWriteDataDelegate
+ * the delegate to set, not <code>null</code>
+ * @throws IllegalArgumentException
+ * if the provided delegate is <code>null</code>
+ */
+ public void setShouldWriteDataDelegate(
+ ShouldWriteDataDelegate shouldWriteDataDelegate) {
+ if (shouldWriteDataDelegate == null) {
+ throw new IllegalArgumentException("Delegate cannot be null");
+ }
+ this.shouldWriteDataDelegate = shouldWriteDataDelegate;
+ }
+
+ /**
+ * Gets the delegate that determines whether the container data of a
+ * component should be written out.
+ *
+ * @since
+ * @see #setShouldWriteDataDelegate(ShouldWriteDataDelegate)
+ * @see #shouldWriteChildren(Component, Component)
+ * @return the shouldWriteDataDelegate the currently use delegate
+ */
+ public ShouldWriteDataDelegate getShouldWriteDataDelegate() {
+ return shouldWriteDataDelegate;
+ }
+
}
diff --git a/server/src/com/vaadin/ui/declarative/ShouldWriteDataDelegate.java b/server/src/com/vaadin/ui/declarative/ShouldWriteDataDelegate.java
new file mode 100644
index 0000000000..29a78e1db6
--- /dev/null
+++ b/server/src/com/vaadin/ui/declarative/ShouldWriteDataDelegate.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2014 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.ui.declarative;
+
+import java.io.Serializable;
+
+import com.vaadin.ui.Component;
+
+/**
+ * Delegate used by {@link DesignContext} to determine whether container data
+ * should be written out for a component.
+ *
+ * @see DesignContext#shouldWriteData(Component)
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public interface ShouldWriteDataDelegate extends Serializable {
+
+ /**
+ * The default delegate implementation that assumes that all component data
+ * is provided by a data source connected to a back end system and that the
+ * data should thus not be written.
+ */
+ public static final ShouldWriteDataDelegate DEFAULT = new ShouldWriteDataDelegate() {
+ @Override
+ public boolean shouldWriteData(Component component) {
+ return false;
+ }
+ };
+
+ /**
+ * Determines whether the container data of a component should be written
+ * out.
+ *
+ * @param component
+ * the component to check
+ * @return <code>true</code> if container data should be written out for the
+ * provided component; otherwise <code>false</code>.
+ */
+ boolean shouldWriteData(Component component);
+}
diff --git a/server/src/com/vaadin/ui/declarative/converters/DesignShortcutActionConverter.java b/server/src/com/vaadin/ui/declarative/converters/DesignShortcutActionConverter.java
index e2b6ed8e14..d6f2f65938 100644
--- a/server/src/com/vaadin/ui/declarative/converters/DesignShortcutActionConverter.java
+++ b/server/src/com/vaadin/ui/declarative/converters/DesignShortcutActionConverter.java
@@ -126,32 +126,37 @@ public class DesignShortcutActionConverter implements
if (value.length() == 0) {
return null;
}
- String[] data = value.split(" ", 2);
+ String[] data = value.split(" ", 2);
String[] parts = data[0].split("-");
- // handle keycode
- String keyCodePart = parts[parts.length - 1];
- int keyCode = getKeycodeForString(keyCodePart);
- if (keyCode < 0) {
- throw new IllegalArgumentException("Invalid shortcut definition "
- + value);
- }
- // handle modifiers
- int[] modifiers = null;
- if (parts.length > 1) {
- modifiers = new int[parts.length - 1];
- }
- for (int i = 0; i < parts.length - 1; i++) {
- int modifier = getKeycodeForString(parts[i]);
- if (modifier > 0) {
- modifiers[i] = modifier;
- } else {
- throw new IllegalArgumentException(
- "Invalid shortcut definition " + value);
+
+ try {
+ // handle keycode
+ String keyCodePart = parts[parts.length - 1];
+ int keyCode = getKeycodeForString(keyCodePart);
+ if (keyCode < 0) {
+ throw new IllegalArgumentException("Invalid key '"
+ + keyCodePart + "'");
+ }
+ // handle modifiers
+ int[] modifiers = null;
+ if (parts.length > 1) {
+ modifiers = new int[parts.length - 1];
+ }
+ for (int i = 0; i < parts.length - 1; i++) {
+ int modifier = getKeycodeForString(parts[i]);
+ if (modifier > 0) {
+ modifiers[i] = modifier;
+ } else {
+ throw new IllegalArgumentException("Invalid modifier '"
+ + parts[i] + "'");
+ }
}
+ return new ShortcutAction(data.length == 2 ? data[1] : null,
+ keyCode, modifiers);
+ } catch (Exception e) {
+ throw new ConversionException("Invalid shortcut '" + value + "'", e);
}
- return new ShortcutAction(data.length == 2 ? data[1] : null, keyCode,
- modifiers);
}
@Override
diff --git a/server/tests/src/com/vaadin/server/MockServletContext.java b/server/tests/src/com/vaadin/server/MockServletContext.java
index 031c83ae90..45ec700c40 100644
--- a/server/tests/src/com/vaadin/server/MockServletContext.java
+++ b/server/tests/src/com/vaadin/server/MockServletContext.java
@@ -24,12 +24,21 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.Map;
import java.util.Set;
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletRegistration.Dynamic;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.descriptor.JspConfigDescriptor;
/**
*
@@ -56,7 +65,7 @@ public class MockServletContext implements ServletContext {
*/
@Override
public int getMajorVersion() {
- return 2;
+ return 3;
}
/*
@@ -66,7 +75,7 @@ public class MockServletContext implements ServletContext {
*/
@Override
public int getMinorVersion() {
- return 4;
+ return 0;
}
/*
@@ -153,8 +162,7 @@ public class MockServletContext implements ServletContext {
*/
@Override
public Enumeration getServlets() {
- // TODO Auto-generated method stub
- return null;
+ return Collections.enumeration(Collections.EMPTY_SET);
}
/*
@@ -301,4 +309,315 @@ public class MockServletContext implements ServletContext {
return null;
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getContextPath()
+ */
+ @Override
+ public String getContextPath() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getEffectiveMajorVersion()
+ */
+ @Override
+ public int getEffectiveMajorVersion() {
+ return 3;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getEffectiveMinorVersion()
+ */
+ @Override
+ public int getEffectiveMinorVersion() {
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#setInitParameter(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public boolean setInitParameter(String name, String value) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#addServlet(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public Dynamic addServlet(String servletName, String className) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#addServlet(java.lang.String,
+ * javax.servlet.Servlet)
+ */
+ @Override
+ public Dynamic addServlet(String servletName, Servlet servlet) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#addServlet(java.lang.String,
+ * java.lang.Class)
+ */
+ @Override
+ public Dynamic addServlet(String servletName,
+ Class<? extends Servlet> servletClass) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#createServlet(java.lang.Class)
+ */
+ @Override
+ public <T extends Servlet> T createServlet(Class<T> clazz)
+ throws ServletException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * javax.servlet.ServletContext#getServletRegistration(java.lang.String)
+ */
+ @Override
+ public ServletRegistration getServletRegistration(String servletName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getServletRegistrations()
+ */
+ @Override
+ public Map<String, ? extends ServletRegistration> getServletRegistrations() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#addFilter(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public javax.servlet.FilterRegistration.Dynamic addFilter(
+ String filterName, String className) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#addFilter(java.lang.String,
+ * javax.servlet.Filter)
+ */
+ @Override
+ public javax.servlet.FilterRegistration.Dynamic addFilter(
+ String filterName, Filter filter) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#addFilter(java.lang.String,
+ * java.lang.Class)
+ */
+ @Override
+ public javax.servlet.FilterRegistration.Dynamic addFilter(
+ String filterName, Class<? extends Filter> filterClass) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#createFilter(java.lang.Class)
+ */
+ @Override
+ public <T extends Filter> T createFilter(Class<T> clazz)
+ throws ServletException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getFilterRegistration(java.lang.String)
+ */
+ @Override
+ public FilterRegistration getFilterRegistration(String filterName) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getFilterRegistrations()
+ */
+ @Override
+ public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getSessionCookieConfig()
+ */
+ @Override
+ public SessionCookieConfig getSessionCookieConfig() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#setSessionTrackingModes(java.util.Set)
+ */
+ @Override
+ public void setSessionTrackingModes(
+ Set<SessionTrackingMode> sessionTrackingModes) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getDefaultSessionTrackingModes()
+ */
+ @Override
+ public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getEffectiveSessionTrackingModes()
+ */
+ @Override
+ public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#addListener(java.lang.String)
+ */
+ @Override
+ public void addListener(String className) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#addListener(java.util.EventListener)
+ */
+ @Override
+ public <T extends EventListener> void addListener(T t) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#addListener(java.lang.Class)
+ */
+ @Override
+ public void addListener(Class<? extends EventListener> listenerClass) {
+ // TODO Auto-generated method stub
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#createListener(java.lang.Class)
+ */
+ @Override
+ public <T extends EventListener> T createListener(Class<T> clazz)
+ throws ServletException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getJspConfigDescriptor()
+ */
+ @Override
+ public JspConfigDescriptor getJspConfigDescriptor() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#getClassLoader()
+ */
+ @Override
+ public ClassLoader getClassLoader() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.ServletContext#declareRoles(java.lang.String[])
+ */
+ @Override
+ public void declareRoles(String... roleNames) {
+ // TODO Auto-generated method stub
+
+ }
+
}
diff --git a/server/tests/src/com/vaadin/tests/design/AbstractComponentSetResponsiveTest.java b/server/tests/src/com/vaadin/tests/design/AbstractComponentSetResponsiveTest.java
new file mode 100644
index 0000000000..f7dbd0c97e
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/design/AbstractComponentSetResponsiveTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2014 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.tests.design;
+
+import org.junit.Test;
+
+import com.vaadin.tests.design.DeclarativeTestBase;
+import com.vaadin.ui.GridLayout;
+
+public class AbstractComponentSetResponsiveTest extends
+ DeclarativeTestBase<GridLayout> {
+
+ @Test
+ public void testResponsiveFlag() {
+ GridLayout gl = new GridLayout();
+ gl.setResponsive(true);
+
+ String design = "<v-grid-layout responsive='true' />";
+
+ testWrite(design, gl);
+ testRead(design, gl);
+ }
+
+}
diff --git a/server/tests/src/com/vaadin/tests/design/DeclarativeTestBase.java b/server/tests/src/com/vaadin/tests/design/DeclarativeTestBase.java
index cba981c947..10f1e5c711 100644
--- a/server/tests/src/com/vaadin/tests/design/DeclarativeTestBase.java
+++ b/server/tests/src/com/vaadin/tests/design/DeclarativeTestBase.java
@@ -24,6 +24,7 @@ import java.util.Map;
import org.junit.Assert;
+import com.vaadin.shared.Connector;
import com.vaadin.ui.Component;
import com.vaadin.ui.Flash;
@@ -59,6 +60,11 @@ public abstract class DeclarativeTestBase<T extends Component> extends
if (readMethod == null || writeMethod == null) {
continue;
}
+ if (Connector.class.isAssignableFrom(c)
+ && readMethod.getName().equals("getParent")) {
+ // Hack to break cycles in the connector hierarchy
+ continue;
+ }
try {
c.getDeclaredMethod(readMethod.getName());
} catch (Exception e) {
@@ -99,7 +105,6 @@ public abstract class DeclarativeTestBase<T extends Component> extends
}
}
});
-
}
@Override
@@ -118,5 +123,4 @@ public abstract class DeclarativeTestBase<T extends Component> extends
}
return comp;
}
-
}
diff --git a/server/tests/src/com/vaadin/tests/design/DeclarativeTestBaseBase.java b/server/tests/src/com/vaadin/tests/design/DeclarativeTestBaseBase.java
index 8dc32e00d6..4cb627d035 100644
--- a/server/tests/src/com/vaadin/tests/design/DeclarativeTestBaseBase.java
+++ b/server/tests/src/com/vaadin/tests/design/DeclarativeTestBaseBase.java
@@ -32,6 +32,8 @@ import org.junit.Assert;
import com.vaadin.ui.Component;
import com.vaadin.ui.declarative.Design;
+import com.vaadin.ui.declarative.DesignContext;
+import com.vaadin.ui.declarative.ShouldWriteDataDelegate;
public abstract class DeclarativeTestBaseBase<T extends Component> {
public interface EqualsAsserter<TT> {
@@ -47,10 +49,21 @@ public abstract class DeclarativeTestBaseBase<T extends Component> {
}
}
- protected String write(T object) {
+ protected String write(T object, boolean writeData) {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- Design.write(object, outputStream);
+
+ DesignContext dc = new DesignContext();
+ if (writeData) {
+ dc.setShouldWriteDataDelegate(new ShouldWriteDataDelegate() {
+ @Override
+ public boolean shouldWriteData(Component component) {
+ return true;
+ }
+ });
+ }
+ dc.setRootComponent(object);
+ Design.write(dc, outputStream);
return outputStream.toString("UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
@@ -71,12 +84,21 @@ public abstract class DeclarativeTestBaseBase<T extends Component> {
return;
}
- if (o1 instanceof Collection && o2 instanceof Collection) {
-
- } else {
+ if (!(o1 instanceof Collection && o2 instanceof Collection)) {
Assert.assertEquals(o1.getClass(), o2.getClass());
}
+ if (o1 instanceof Object[]) {
+ Object[] a1 = ((Object[]) o1);
+ Object[] a2 = ((Object[]) o2);
+ Assert.assertEquals(message + ": array length", a1.length,
+ a2.length);
+ for (int i = 0; i < a1.length; i++) {
+ assertEquals(message, a1[i], a2[i]);
+ }
+ return;
+ }
+
List<EqualsAsserter<Object>> comparators = getComparators(o1);
if (!comparators.isEmpty()) {
for (EqualsAsserter<Object> ec : comparators) {
@@ -113,7 +135,9 @@ public abstract class DeclarativeTestBaseBase<T extends Component> {
protected abstract <TT> EqualsAsserter<TT> getComparator(Class<TT> c);
private boolean isVaadin(Class<?> c) {
- return c.getPackage().getName().startsWith("com.vaadin");
+ return c.getPackage() != null
+ && c.getPackage().getName().startsWith("com.vaadin");
+
}
public void testRead(String design, T expected) {
@@ -121,7 +145,11 @@ public abstract class DeclarativeTestBaseBase<T extends Component> {
}
public void testWrite(String design, T expected) {
- String written = write(expected);
+ testWrite(design, expected, false);
+ }
+
+ public void testWrite(String design, T expected, boolean writeData) {
+ String written = write(expected, writeData);
Element producedElem = Jsoup.parse(written).body().child(0);
Element comparableElem = Jsoup.parse(design).body().child(0);
@@ -132,6 +160,10 @@ public abstract class DeclarativeTestBaseBase<T extends Component> {
Assert.assertEquals(comparable, produced);
}
+ protected Element createElement(Component c) {
+ return new DesignContext().createElement(c);
+ }
+
private String elementToHtml(Element producedElem) {
StringBuilder stringBuilder = new StringBuilder();
elementToHtml(producedElem, stringBuilder);
diff --git a/server/tests/src/com/vaadin/tests/design/DesignContextLocalIdTest.java b/server/tests/src/com/vaadin/tests/design/DesignContextLocalIdTest.java
new file mode 100644
index 0000000000..c3d7e6d8cf
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/design/DesignContextLocalIdTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2014 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.tests.design;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+import org.junit.Test;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.declarative.Design;
+import com.vaadin.ui.declarative.DesignContext;
+
+/**
+ * Tests that setting local id via DesignContext works as intended.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class DesignContextLocalIdTest {
+
+ @Test
+ public void testSetLocalId() throws FileNotFoundException {
+ DesignContext ctx = Design.read(new FileInputStream(
+ "server/tests/src/com/vaadin/tests/design/local-ids.html"),
+ new VerticalLayout());
+ TextField tf = (TextField) ctx.getComponentByLocalId("foo");
+ Button b = (Button) ctx.getComponentByLocalId("bar");
+ // A duplicate id should be handled by removing the id from the old
+ // component.
+ ctx.setComponentLocalId(b, "foo");
+ assertEquals("Found the wrong component by local id.", ctx
+ .getComponentByLocalId("foo").getClass(), Button.class);
+ assertEquals("Found the wrong component by local id.",
+ ctx.getComponentByLocalId("bar"), null);
+ // Set an id also for the text field.
+ ctx.setComponentLocalId(tf, "bar");
+ assertEquals("Found the wrong component by local id.", ctx
+ .getComponentByLocalId("foo").getClass(), Button.class);
+ assertEquals("Found the wrong component by local id.", ctx
+ .getComponentByLocalId("bar").getClass(), TextField.class);
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java b/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java
index 05b2484767..681b9d80a3 100644
--- a/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java
+++ b/server/tests/src/com/vaadin/tests/design/DesignFormatterTest.java
@@ -24,10 +24,14 @@ import java.util.Date;
import java.util.HashSet;
import java.util.TimeZone;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import com.vaadin.data.util.converter.Converter.ConversionException;
import com.vaadin.event.ShortcutAction;
+import com.vaadin.event.ShortcutAction.KeyCode;
+import com.vaadin.event.ShortcutAction.ModifierKey;
import com.vaadin.server.ExternalResource;
import com.vaadin.server.FileResource;
import com.vaadin.server.Resource;
@@ -203,10 +207,8 @@ public class DesignFormatterTest {
@Test
public void testShortcutActionNoCaption() {
- ShortcutAction action = new ShortcutAction(null,
- ShortcutAction.KeyCode.D, new int[] {
- ShortcutAction.ModifierKey.ALT,
- ShortcutAction.ModifierKey.CTRL });
+ ShortcutAction action = new ShortcutAction(null, KeyCode.D, new int[] {
+ ModifierKey.ALT, ModifierKey.CTRL });
String formatted = formatter.format(action);
assertEquals("alt-ctrl-d", formatted);
@@ -216,6 +218,23 @@ public class DesignFormatterTest {
}
@Test
+ public void testInvalidShortcutAction() {
+ assertInvalidShortcut("-");
+ assertInvalidShortcut("foo");
+ assertInvalidShortcut("atl-ctrl");
+ assertInvalidShortcut("-a");
+ }
+
+ protected void assertInvalidShortcut(String shortcut) {
+ try {
+ formatter.parse(shortcut, ShortcutAction.class);
+ Assert.fail("Invalid shortcut '" + shortcut + "' should throw");
+ } catch (ConversionException e) {
+ // expected
+ }
+ }
+
+ @Test
public void testTimeZone() {
TimeZone zone = TimeZone.getTimeZone("GMT+2");
String formatted = formatter.format(zone);
@@ -227,6 +246,25 @@ public class DesignFormatterTest {
assertEquals(zone, result);
}
+ @Test
+ public void testExternalResource() {
+ String url = "://example.com/my%20icon.png?a=b";
+
+ for (String scheme : new String[] { "http", "https", "ftp", "ftps" }) {
+ Resource resource = formatter.parse(scheme + url, Resource.class);
+
+ assertTrue(scheme + " url should be parsed as ExternalResource",
+ resource instanceof ExternalResource);
+ assertEquals("parsed ExternalResource", scheme + url,
+ ((ExternalResource) resource).getURL());
+
+ String formatted = formatter.format(new ExternalResource(scheme
+ + url));
+
+ assertEquals("formatted ExternalResource", scheme + url, formatted);
+ }
+ }
+
/**
* A static method to allow comparison two different actions.
*
diff --git a/server/tests/src/com/vaadin/tests/design/local-ids.html b/server/tests/src/com/vaadin/tests/design/local-ids.html
new file mode 100644
index 0000000000..638d004124
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/design/local-ids.html
@@ -0,0 +1,4 @@
+<v-vertical-layout>
+ <v-text-field caption="Enter your name" _id="foo"/>
+ <v-button _id="bar">Say hello</v-button>
+</v-vertical-layout>
diff --git a/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java b/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java
index 0de8fd6aab..9603032ce5 100644
--- a/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java
+++ b/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java
@@ -16,7 +16,6 @@ import java.util.jar.JarFile;
import junit.framework.TestCase;
-import org.junit.Ignore;
import org.junit.Test;
public class ClassesSerializableTest extends TestCase {
@@ -80,6 +79,7 @@ public class ClassesSerializableTest extends TestCase {
"com\\.vaadin\\.external\\..*", //
"com\\.vaadin\\.util\\.WeakValueMap.*", //
"com\\.vaadin\\.themes\\.valoutil\\.BodyStyleName", //
+ "com\\.vaadin\\.server\\.communication\\.JSR356WebsocketInitializer.*", //
};
/**
diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractselect/AbstractSelectDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/abstractselect/AbstractSelectDeclarativeTest.java
index 61128a1803..b3867a7a3a 100644
--- a/server/tests/src/com/vaadin/tests/server/component/abstractselect/AbstractSelectDeclarativeTest.java
+++ b/server/tests/src/com/vaadin/tests/server/component/abstractselect/AbstractSelectDeclarativeTest.java
@@ -137,12 +137,18 @@ public class AbstractSelectDeclarativeTest extends
}
@Test
- public void testWriteInlineData() {
+ public void testWriteInlineDataIgnored() {
// No data is written by default
testWrite(stripOptionTags(getDesignForInlineData()),
getExpectedComponentForInlineData());
}
+ @Test
+ public void testWriteInlineData() {
+ testWrite(getDesignForInlineData(),
+ getExpectedComponentForInlineData(), true);
+ }
+
private String getDesignForInlineData() {
return "<v-list-select>\n"
+ " <option icon='http://some.url/icon.png'>Value 1</option>\n" //
diff --git a/server/tests/src/com/vaadin/tests/server/component/colorpicker/AbstractColorPickerDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/colorpicker/AbstractColorPickerDeclarativeTest.java
new file mode 100644
index 0000000000..59b2efdc42
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/colorpicker/AbstractColorPickerDeclarativeTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2000-2014 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.tests.server.component.colorpicker;
+
+import org.junit.Test;
+
+import com.vaadin.shared.ui.colorpicker.Color;
+import com.vaadin.tests.design.DeclarativeTestBase;
+import com.vaadin.ui.AbstractColorPicker;
+import com.vaadin.ui.AbstractColorPicker.PopupStyle;
+import com.vaadin.ui.ColorPicker;
+import com.vaadin.ui.ColorPickerArea;
+
+public class AbstractColorPickerDeclarativeTest extends
+ DeclarativeTestBase<AbstractColorPicker> {
+
+ @Test
+ public void testAllAbstractColorPickerFeatures() {
+ String design = "<v-color-picker color='#fafafa' default-caption-enabled='true' position='100,100'"
+ + " popup-style='simple' rgb-visibility='false' hsv-visibility='false'"
+ + " history-visibility=false textfield-visibility=false />";
+ ColorPicker colorPicker = new ColorPicker();
+ int colorInt = Integer.parseInt("fafafa", 16);
+ colorPicker.setColor(new Color(colorInt));
+ colorPicker.setDefaultCaptionEnabled(true);
+ colorPicker.setPosition(100, 100);
+ colorPicker.setPopupStyle(PopupStyle.POPUP_SIMPLE);
+ colorPicker.setRGBVisibility(false);
+ colorPicker.setHSVVisibility(false);
+ colorPicker.setSwatchesVisibility(true);
+ colorPicker.setHistoryVisibility(false);
+ colorPicker.setTextfieldVisibility(false);
+
+ testWrite(design, colorPicker);
+ testRead(design, colorPicker);
+ }
+
+ @Test
+ public void testEmptyColorPicker() {
+ String design = "<v-color-picker />";
+ ColorPicker colorPicker = new ColorPicker();
+ testRead(design, colorPicker);
+ testWrite(design, colorPicker);
+ }
+
+ @Test
+ public void testAllAbstractColorPickerAreaFeatures() {
+ String design = "<v-color-picker-area color='#fafafa' default-caption-enabled='true' position='100,100'"
+ + " popup-style='simple' rgb-visibility='false' hsv-visibility='false'"
+ + " history-visibility=false textfield-visibility=false />";
+ AbstractColorPicker colorPicker = new ColorPickerArea();
+ int colorInt = Integer.parseInt("fafafa", 16);
+ colorPicker.setColor(new Color(colorInt));
+ colorPicker.setDefaultCaptionEnabled(true);
+ colorPicker.setPosition(100, 100);
+ colorPicker.setPopupStyle(PopupStyle.POPUP_SIMPLE);
+ colorPicker.setRGBVisibility(false);
+ colorPicker.setHSVVisibility(false);
+ colorPicker.setSwatchesVisibility(true);
+ colorPicker.setHistoryVisibility(false);
+ colorPicker.setTextfieldVisibility(false);
+
+ testWrite(design, colorPicker);
+ testRead(design, colorPicker);
+ }
+
+ @Test
+ public void testEmptyColorPickerArea() {
+ String design = "<v-color-picker-area />";
+ AbstractColorPicker colorPicker = new ColorPickerArea();
+ testRead(design, colorPicker);
+ testWrite(design, colorPicker);
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/server/component/popupview/PopupViewDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/popupview/PopupViewDeclarativeTest.java
new file mode 100644
index 0000000000..8bad68f5b9
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/popupview/PopupViewDeclarativeTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2014 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.tests.server.component.popupview;
+
+import org.junit.Test;
+
+import com.vaadin.tests.design.DeclarativeTestBase;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.PopupView;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.declarative.DesignContext;
+
+public class PopupViewDeclarativeTest extends DeclarativeTestBase<PopupView> {
+
+ @Test
+ public void testEmptyPopupView() {
+ PopupView component = new PopupView();
+ Component popup = component.getContent().getPopupComponent();
+ String design = "<v-popup-view><popup-content>"
+ + new DesignContext().createElement(popup)
+ + "</popup-content></v-popup-view>";
+ testWrite(design, component);
+ testRead(design, component);
+ }
+
+ @Test
+ public void testVisiblePopupDesign() {
+ final VerticalLayout verticalLayout = new VerticalLayout();
+ verticalLayout.setWidth("300px");
+ verticalLayout.setHeight("400px");
+
+ PopupView component = new PopupView("Click <u>here</u> to open",
+ verticalLayout);
+ component.setHideOnMouseOut(true);
+ component.setPopupVisible(true);
+ // hide-on-mouse-out is true by default. not seen in design
+ String design = "<v-popup-view popup-visible='true'>" //
+ + "Click <u>here</u> to open"
+ + "<popup-content>"
+ + new DesignContext().createElement(verticalLayout)
+ + "</popup-content>" //
+ + "</v-popup-view>";
+ testWrite(design, component);
+ testRead(design, component);
+ }
+
+ @Test
+ public void testHideOnMouseOutDisabled() {
+ final Label label = new Label("Foo");
+ PopupView component = new PopupView("Click Me!", label);
+ component.setHideOnMouseOut(false);
+ String design = "<v-popup-view hide-on-mouse-out='false'>" //
+ + "Click Me!"
+ + "<popup-content>"
+ + new DesignContext().createElement(label) + "</popup-content>" //
+ + "</v-popup-view>";
+ testWrite(design, component);
+ testRead(design, component);
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/server/component/window/WindowDeclarativeTest.java b/server/tests/src/com/vaadin/tests/server/component/window/WindowDeclarativeTest.java
new file mode 100644
index 0000000000..1ab0011442
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/window/WindowDeclarativeTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2000-2014 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.tests.server.component.window;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.event.ShortcutAction.KeyCode;
+import com.vaadin.event.ShortcutAction.ModifierKey;
+import com.vaadin.shared.ui.window.WindowMode;
+import com.vaadin.shared.ui.window.WindowRole;
+import com.vaadin.tests.design.DeclarativeTestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.declarative.DesignException;
+
+/**
+ * Tests declarative support for implementations of {@link Window}.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class WindowDeclarativeTest extends DeclarativeTestBase<Window> {
+
+ @Test
+ public void testDefault() {
+ String design = "<v-window>";
+
+ Window expected = new Window();
+
+ testRead(design, expected);
+ testWrite(design, expected);
+ }
+
+ @Test
+ public void testFeatures() {
+
+ String design = "<v-window position='100,100' window-mode='maximized' "
+ + "center modal=true resizable=false resize-lazy=true closable=false draggable=false "
+ + "close-shortcut='ctrl-alt-escape' "
+ + "assistive-prefix='Hello' assistive-postfix='World' assistive-role='alertdialog' "
+ + "tab-stop-enabled=true "
+ + "tab-stop-top-assistive-text='Do not move above the window' "
+ + "tab-stop-bottom-assistive-text='End of window'>"
+ + "</v-window>";
+
+ Window expected = new Window();
+
+ expected.setPositionX(100);
+ expected.setPositionY(100);
+ expected.setWindowMode(WindowMode.MAXIMIZED);
+
+ expected.center();
+ expected.setModal(!expected.isModal());
+ expected.setResizable(!expected.isResizable());
+ expected.setResizeLazy(!expected.isResizeLazy());
+ expected.setClosable(!expected.isClosable());
+ expected.setDraggable(!expected.isDraggable());
+
+ expected.setCloseShortcut(KeyCode.ESCAPE, ModifierKey.CTRL,
+ ModifierKey.ALT);
+
+ expected.setAssistivePrefix("Hello");
+ expected.setAssistivePostfix("World");
+ expected.setAssistiveRole(WindowRole.ALERTDIALOG);
+ expected.setTabStopEnabled(!expected.isTabStopEnabled());
+ expected.setTabStopTopAssistiveText("Do not move above the window");
+ expected.setTabStopBottomAssistiveText("End of window");
+
+ testRead(design, expected);
+ testWrite(design, expected);
+ }
+
+ @Test
+ public void testInvalidPosition() {
+ assertInvalidPosition("");
+ assertInvalidPosition("1");
+ assertInvalidPosition("100,100.1");
+ assertInvalidPosition("x");
+ assertInvalidPosition("2,foo");
+ // Should be invalid, not checked currently
+ // assertInvalidPosition("1,2,3");
+ }
+
+ protected void assertInvalidPosition(String position) {
+ try {
+ read("<v-window position='" + position + "'>");
+ Assert.fail("Invalid position '" + position + "' should throw");
+ } catch (Exception e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testChildContent() {
+
+ String design = "<v-window>" + createElement(new Button("OK"))
+ + "</v-window>";
+
+ Window expected = new Window();
+ expected.setContent(new Button("OK"));
+
+ testRead(design, expected);
+ testWrite(design, expected);
+ }
+
+ @Test(expected = DesignException.class)
+ public void testMultipleContentChildren() {
+
+ String design = "<v-window>" + createElement(new Label("Hello"))
+ + createElement(new Button("OK")) + "</v-window>";
+
+ read(design);
+ }
+
+ @Test
+ public void testAssistiveDescription() {
+
+ Label assistive1 = new Label("Assistive text");
+ Label assistive2 = new Label("More assistive text");
+
+ String design = "<v-window>"
+ + createElement(assistive1).attr(":assistive-description", "")
+ + createElement(new Button("OK"))
+ + createElement(assistive2).attr(":assistive-description", "");
+
+ Window expected = new Window();
+ expected.setContent(new Button("OK"));
+ expected.setAssistiveDescription(assistive1, assistive2);
+
+ testRead(design, expected);
+
+ String written = "<v-window>" + createElement(new Button("OK"))
+ + createElement(assistive1).attr(":assistive-description", "")
+ + createElement(assistive2).attr(":assistive-description", "");
+
+ testWrite(written, expected);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/integration/ServletIntegrationJSR356WebsocketUITest.java b/uitest/src/com/vaadin/tests/integration/ServletIntegrationJSR356WebsocketUITest.java
new file mode 100644
index 0000000000..f118d38158
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/integration/ServletIntegrationJSR356WebsocketUITest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2014 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.tests.integration;
+
+public class ServletIntegrationJSR356WebsocketUITest extends
+ AbstractServletIntegrationTest {
+ // Uses the test method declared in the super class
+
+ @Override
+ protected String getDeploymentPath(Class<?> uiClass) {
+ return super.getDeploymentPath(uiClass)
+ .replace("/run/", "/run-jsr356/");
+ }
+
+ @Override
+ protected Class<?> getUIClass() {
+ return ServletIntegrationWebsocketUI.class;
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java b/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java
index 77c5676215..2f97ce27c3 100644
--- a/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java
+++ b/uitest/src/com/vaadin/tests/tb3/ServletIntegrationTests.java
@@ -17,21 +17,84 @@
package com.vaadin.tests.tb3;
import java.io.IOException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import org.junit.runner.RunWith;
import org.junit.runners.model.InitializationError;
import com.vaadin.tests.integration.AbstractServletIntegrationTest;
+import com.vaadin.tests.integration.ServletIntegrationJSR356WebsocketUITest;
+import com.vaadin.tests.integration.ServletIntegrationWebsocketUITest;
import com.vaadin.tests.tb3.ServletIntegrationTests.ServletIntegrationTestSuite;
@RunWith(ServletIntegrationTestSuite.class)
public class ServletIntegrationTests {
+ public static Set<String> notJSR356Compatible = new HashSet<String>();
+ public static Set<String> notWebsocketCompatible = new HashSet<String>();
+ static {
+ notJSR356Compatible.add("jboss4");
+ notJSR356Compatible.add("jboss5");
+ notJSR356Compatible.add("jboss6");
+ notJSR356Compatible.add("jbosseap6");
+ notJSR356Compatible.add("jboss7");
+
+ notJSR356Compatible.add("jetty7");
+ notJSR356Compatible.add("jetty8");
+
+ notJSR356Compatible.add("glassfish3");
+
+ notJSR356Compatible.add("tomcat6");
+ notJSR356Compatible.add("tomcat7");
+ notJSR356Compatible.add("tomcat7apacheproxy");
+ notJSR356Compatible.add("weblogic10");
+ notJSR356Compatible.add("osgi"); // Karaf 3, Jetty 8
+
+ notWebsocketCompatible.add("glassfish2");
+ // In theory GF3 could work but in reality broken
+ notWebsocketCompatible.add("glassfish3");
+ notWebsocketCompatible.add("jboss4");
+ notWebsocketCompatible.add("jboss5");
+ notWebsocketCompatible.add("jboss6");
+ notWebsocketCompatible.add("jboss7");
+ notWebsocketCompatible.add("jbosseap6");
+ notWebsocketCompatible.add("jetty5");
+ notWebsocketCompatible.add("jetty6");
+ notWebsocketCompatible.add("tomcat5");
+ notWebsocketCompatible.add("tomcat6");
+ notWebsocketCompatible.add("tomcat7apacheproxy");
+ notWebsocketCompatible.add("weblogic10");
+ }
+
public static class ServletIntegrationTestSuite extends TB3TestSuite {
public ServletIntegrationTestSuite(Class<?> klass)
throws InitializationError, IOException {
super(klass, AbstractServletIntegrationTest.class,
- "com.vaadin.tests.integration", new String[] {});
+ "com.vaadin.tests.integration", new String[] {},
+ new ServletTestLocator());
+ }
+ }
+
+ public static class ServletTestLocator extends TB3TestLocator {
+ @Override
+ protected <T> List<Class<? extends T>> findClasses(Class<T> baseClass,
+ String basePackage, String[] ignoredPackages)
+ throws IOException {
+ List<Class<? extends T>> allClasses = super.findClasses(baseClass,
+ basePackage, ignoredPackages);
+ String serverName = System.getProperty("server-name");
+
+ if (notJSR356Compatible.contains(serverName)) {
+ allClasses
+ .remove(ServletIntegrationJSR356WebsocketUITest.class);
+ }
+
+ if (notWebsocketCompatible.contains(serverName)) {
+ allClasses.remove(ServletIntegrationWebsocketUITest.class);
+ }
+ return allClasses;
}
}
}