diff options
13 files changed, 903 insertions, 73 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/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/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/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/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; } } } |