You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by mg...@apache.org on 2013/08/05 10:49:18 UTC

[2/4] git commit: WICKET-5301 Create a module for Native WebSocket based on JSR 356

WICKET-5301 Create a module for Native WebSocket based on JSR 356


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/36ad94dd
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/36ad94dd
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/36ad94dd

Branch: refs/heads/master
Commit: 36ad94ddf50121dd1f288232b3e6ce8453d919a5
Parents: d6ff34e
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Mon Aug 5 10:05:47 2013 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Mon Aug 5 10:05:47 2013 +0200

----------------------------------------------------------------------
 .../wicket-native-websocket/pom.xml             |   1 +
 .../ws/api/AbstractWebSocketProcessor.java      |   1 -
 .../protocol/ws/api/WebSocketBehavior.java      |   4 +
 .../ws/api/res/js/wicket-websocket-jquery.js    |  23 +-
 .../api/res/js/wicket-websocket-setup.js.tmpl   |   2 +-
 .../wicket-native-websocket-javax/pom.xml       |  67 +++
 .../ws/javax/JavaxUpgradeHttpRequest.java       | 558 +++++++++++++++++++
 .../ws/javax/JavaxWebSocketConnection.java      | 119 ++++
 .../protocol/ws/javax/JavaxWebSocketFilter.java | 280 ++++++++++
 .../ws/javax/JavaxWebSocketProcessor.java       |  83 +++
 .../protocol/ws/javax/WicketEndpoint.java       |  67 +++
 .../src/test/java/log4j.properties              |  16 +
 .../util/licence/ApacheLicenceHeaderTest.java   |  34 ++
 13 files changed, 1240 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/pom.xml
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/pom.xml b/wicket-experimental/wicket-native-websocket/pom.xml
index e9e87cb..a2f8c05 100644
--- a/wicket-experimental/wicket-native-websocket/pom.xml
+++ b/wicket-experimental/wicket-native-websocket/pom.xml
@@ -33,5 +33,6 @@
 		<module>wicket-native-websocket-jetty</module>
 		<module>wicket-native-websocket-jetty9</module>
 		<module>wicket-native-websocket-tomcat</module>
+		<module>wicket-native-websocket-javax</module>
 	</modules>
 </project>

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
index 16eeb5b..3ac7625 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
@@ -92,7 +92,6 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 	public AbstractWebSocketProcessor(final HttpServletRequest request, final WebApplication application)
 	{
 		this.sessionId = request.getSession(true).getId();
-		Session.get().bind();
 
 		String pageId = request.getParameter("pageId");
 		Checks.notEmpty(pageId, "Request parameter 'pageId' is required!");

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketBehavior.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketBehavior.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketBehavior.java
index ec2bbd5..f7f1e5d 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketBehavior.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketBehavior.java
@@ -114,6 +114,10 @@ public abstract class WebSocketBehavior extends Behavior
 		Url baseUrl = component.getRequestCycle().getUrlRenderer().getBaseUrl();
 		CharSequence ajaxBaseUrl = Strings.escapeMarkup(baseUrl.toString());
 		variables.put("baseUrl", ajaxBaseUrl);
+
+		String contextPath = component.getRequest().getContextPath();
+		variables.put("contextPath", contextPath);
+
 		String webSocketSetupScript = webSocketSetupTemplate.asString(variables);
 
 		response.render(OnDomReadyHeaderItem.forScript(webSocketSetupScript));

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-jquery.js
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-jquery.js b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-jquery.js
index d1d9495..7423c47 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-jquery.js
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-jquery.js
@@ -38,18 +38,15 @@
 
 				var self = this,
 					url,
-					hashIdx,
-					delim;
-
-				url = document.location.toString()
-					.replace('http://', 'ws://')
-					.replace('https://', 'wss://');
-				hashIdx = url.indexOf('#');
-				if (hashIdx > -1) {
-					url = url.substring(0, hashIdx);
-				}
-				delim = url.indexOf('?') > -1 ? '&' : '?';
-				url += delim + 'pageId=' + Wicket.WebSocket.pageId;
+					protocol;
+
+				protocol = document.location.protocol
+					.replace('https:', 'wss:')
+					.replace('http:', 'ws:');
+
+				url = protocol + '//' + document.location.host + Wicket.WebSocket.contextPath + '/wicket/websocket';
+
+				url += '?pageId=' + Wicket.WebSocket.pageId;
 				url += '&wicket-ajax-baseurl=' + Wicket.WebSocket.baseUrl;
 				self.ws = new WebSocket(url);
 
@@ -135,4 +132,4 @@
 		}
 	};
 
-})();
\ No newline at end of file
+})();

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-setup.js.tmpl
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-setup.js.tmpl b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-setup.js.tmpl
index 3d8950a..6d2f8a3 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-setup.js.tmpl
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-setup.js.tmpl
@@ -2,7 +2,7 @@
 	'use strict';
 
 	if (!Wicket.WebSocket.pageId) {
-		jQuery.extend(Wicket.WebSocket, { pageId: ${pageId}, baseUrl: '${baseUrl}' });
+		jQuery.extend(Wicket.WebSocket, { pageId: ${pageId}, baseUrl: '${baseUrl}', contextPath: '${contextPath}' });
 		Wicket.WebSocket.createDefaultConnection();
 	}
 })();

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/pom.xml
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/pom.xml b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/pom.xml
new file mode 100644
index 0000000..1d05f36
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.wicket</groupId>
+		<artifactId>wicket-native-websocket</artifactId>
+		<version>0.9-SNAPSHOT</version>
+		<relativePath>../pom.xml</relativePath>
+	</parent>
+
+	<artifactId>wicket-native-websocket-javax</artifactId>
+	<packaging>jar</packaging>
+	<version>0.9-SNAPSHOT</version>
+	<name>Wicket Native WebSocket Javax</name>
+	<description>Provides the common code needed for the different integrations with web container's WebSocket implementations</description>
+
+	<dependencies>
+		<dependency>
+			<groupId>org.apache.wicket</groupId>
+			<artifactId>wicket-core</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.wicket</groupId>
+			<artifactId>wicket-native-websocket-core</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>javax.websocket</groupId>
+			<artifactId>javax.websocket-api</artifactId>
+			<version>1.0</version>
+            <scope>provided</scope>
+		</dependency>
+
+	</dependencies>
+
+	<repositories>
+		<repository>
+			<id>tc8</id>
+			<url>https://repository.apache.org/content/repositories/orgapachetomcat-048/</url>
+			<releases>
+				<enabled>true</enabled>
+			</releases>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</repository>
+	</repositories>
+
+</project>

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxUpgradeHttpRequest.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxUpgradeHttpRequest.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxUpgradeHttpRequest.java
new file mode 100644
index 0000000..2fea729
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxUpgradeHttpRequest.java
@@ -0,0 +1,558 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.protocol.ws.javax;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.Part;
+import javax.websocket.Session;
+
+import org.apache.wicket.util.string.StringValue;
+
+/**
+ * An artificial HttpServletRequest with data collected from the
+ * available WebSocket Session and from the HandshakeRequest
+ */
+public class JavaxUpgradeHttpRequest implements HttpServletRequest
+{
+	private final HttpSession httpSession;
+	private final String queryString;
+	private final Principal userPrincipal;
+	private final String requestUri;
+	private final Map<String, String[]> parametersMap;
+	private final Map<String, List<String>> headers;
+	private final String contextPath = ""; // artificial
+
+	public JavaxUpgradeHttpRequest(final Session session)
+	{
+		Map<String, Object> userProperties = session.getUserProperties();
+		this.httpSession = (HttpSession) userProperties.get("session");
+		this.headers = (Map<String, List<String>>) userProperties.get("headers");
+		this.queryString = (String) userProperties.get("queryString");
+		this.userPrincipal = (Principal) userProperties.get("userPrincipal");
+		this.requestUri = userProperties.get("requestURI").toString();
+
+		this.parametersMap = new HashMap<>();
+
+		Map<String, List<String>> parameters = (Map<String, List<String>>) userProperties.get("parameterMap");
+		for (Map.Entry<String, List<String>> entry : parameters.entrySet())
+		{
+			String name = entry.getKey();
+			List<String> value = entry.getValue();
+			parametersMap.put(name, value.toArray(new String[value.size()]));
+		}
+	}
+
+	@Override
+	public String getAuthType()
+	{
+		return null;
+	}
+
+	@Override
+	public Cookie[] getCookies()
+	{
+		return new Cookie[0];
+	}
+
+	@Override
+	public long getDateHeader(String name)
+	{
+		String headerValue = getHeader(name);
+		return StringValue.valueOf(headerValue).toLong();
+	}
+
+	@Override
+	public String getHeader(String name)
+	{
+		String value = null;
+		if (headers != null)
+		{
+			List<String> headerValues = headers.get(name);
+			if (headerValues.isEmpty() == false)
+			{
+				value = headerValues.get(0);
+			}
+		}
+		return value;
+	}
+
+	@Override
+	public Enumeration<String> getHeaders(String name)
+	{
+		Enumeration<String> values = null;
+		if (headers != null)
+		{
+			List<String> headerValues = headers.get(name);
+			if (headerValues.isEmpty() == false)
+			{
+				final Iterator<String> iterator = headerValues.iterator();
+				values = new Enumeration<String>()
+				{
+					@Override
+					public boolean hasMoreElements()
+					{
+						return iterator.hasNext();
+					}
+
+					@Override
+					public String nextElement()
+					{
+						return iterator.next();
+					}
+				};
+			}
+		}
+		return values;
+	}
+
+	@Override
+	public Enumeration<String> getHeaderNames()
+	{
+		Enumeration<String> names = null;
+		if (headers != null)
+		{
+			Set<String> headerNames = headers.keySet();
+			if (headerNames.isEmpty() == false)
+			{
+				final Iterator<String> iterator = headerNames.iterator();
+				names = new Enumeration<String>()
+				{
+					@Override
+					public boolean hasMoreElements()
+					{
+						return iterator.hasNext();
+					}
+
+					@Override
+					public String nextElement()
+					{
+						return iterator.next();
+					}
+				};
+			}
+		}
+		return names;
+	}
+
+	@Override
+	public int getIntHeader(String name)
+	{
+		String headerValue = getHeader(name);
+		return StringValue.valueOf(headerValue).toInt();
+	}
+
+	@Override
+	public String getMethod()
+	{
+		return null;
+	}
+
+	@Override
+	public String getPathInfo()
+	{
+		return null;
+	}
+
+	@Override
+	public String getPathTranslated()
+	{
+		return null;
+	}
+
+	@Override
+	public String getContextPath()
+	{
+		return contextPath;
+	}
+
+	@Override
+	public String getQueryString()
+	{
+		return queryString;
+	}
+
+	@Override
+	public String getRemoteUser()
+	{
+		return null;
+	}
+
+	@Override
+	public boolean isUserInRole(String role)
+	{
+		return false;
+	}
+
+	@Override
+	public Principal getUserPrincipal()
+	{
+		return userPrincipal;
+	}
+
+	@Override
+	public String getRequestedSessionId()
+	{
+		return null;
+	}
+
+	@Override
+	public String getRequestURI()
+	{
+		return requestUri;
+	}
+
+	@Override
+	public StringBuffer getRequestURL()
+	{
+		return null;
+	}
+
+	@Override
+	public String getServletPath()
+	{
+		return null;
+	}
+
+	@Override
+	public HttpSession getSession(boolean create)
+	{
+		return httpSession;
+	}
+
+	@Override
+	public HttpSession getSession()
+	{
+		return httpSession;
+	}
+
+	@Override
+	public boolean isRequestedSessionIdValid()
+	{
+		return false;
+	}
+
+	@Override
+	public boolean isRequestedSessionIdFromCookie()
+	{
+		return false;
+	}
+
+	@Override
+	public boolean isRequestedSessionIdFromURL()
+	{
+		return false;
+	}
+
+	@Override
+	public boolean isRequestedSessionIdFromUrl()
+	{
+		return false;
+	}
+
+	@Override
+	public boolean authenticate(HttpServletResponse response) throws IOException, ServletException
+	{
+		return false;
+	}
+
+	@Override
+	public void login(String username, String password) throws ServletException
+	{
+	}
+
+	@Override
+	public void logout() throws ServletException
+	{
+	}
+
+	@Override
+	public Collection<Part> getParts() throws IOException, ServletException
+	{
+		return null;
+	}
+
+	@Override
+	public Part getPart(String name) throws IOException, ServletException
+	{
+		return null;
+	}
+
+	@Override
+	public Object getAttribute(String name)
+	{
+		return null;
+	}
+
+	@Override
+	public Enumeration<String> getAttributeNames()
+	{
+		return new Enumeration<String>()
+		{
+			@Override
+			public boolean hasMoreElements()
+			{
+				return false;
+			}
+
+			@Override
+			public String nextElement()
+			{
+				return null;
+			}
+		};
+	}
+
+	@Override
+	public String getCharacterEncoding()
+	{
+		return null;
+	}
+
+	@Override
+	public void setCharacterEncoding(String env) throws UnsupportedEncodingException
+	{
+	}
+
+	@Override
+	public int getContentLength()
+	{
+		return 0;
+	}
+
+	@Override
+	public String getContentType()
+	{
+		return null;
+	}
+
+	@Override
+	public ServletInputStream getInputStream() throws IOException
+	{
+		return null;
+	}
+
+	@Override
+	public String getParameter(String name)
+	{
+		String[] values = parametersMap.get(name);
+		return values != null ? values[0] : null;
+	}
+
+	@Override
+	public Enumeration<String> getParameterNames()
+	{
+		final Iterator<String> iterator = parametersMap.keySet().iterator();
+		return new Enumeration<String>()
+		{
+			@Override
+			public boolean hasMoreElements()
+			{
+				return iterator.hasNext();
+			}
+
+			@Override
+			public String nextElement()
+			{
+				return iterator.next();
+			}
+		};
+	}
+
+	@Override
+	public String[] getParameterValues(String name)
+	{
+		return parametersMap.get(name);
+	}
+
+	@Override
+	public Map<String, String[]> getParameterMap()
+	{
+		return parametersMap;
+	}
+
+	@Override
+	public String getProtocol()
+	{
+		return null;
+	}
+
+	@Override
+	public String getScheme()
+	{
+		return null;
+	}
+
+	@Override
+	public String getServerName()
+	{
+		return null;
+	}
+
+	@Override
+	public int getServerPort()
+	{
+		return 0;
+	}
+
+	@Override
+	public BufferedReader getReader() throws IOException
+	{
+		return null;
+	}
+
+	@Override
+	public String getRemoteAddr()
+	{
+		return null;
+	}
+
+	@Override
+	public String getRemoteHost()
+	{
+		return null;
+	}
+
+	@Override
+	public void setAttribute(String name, Object o)
+	{
+	}
+
+	@Override
+	public void removeAttribute(String name)
+	{
+	}
+
+	@Override
+	public Locale getLocale()
+	{
+		return null;
+	}
+
+	@Override
+	public Enumeration<Locale> getLocales()
+	{
+		return null;
+	}
+
+	@Override
+	public boolean isSecure()
+	{
+		return false;
+	}
+
+	@Override
+	public RequestDispatcher getRequestDispatcher(String path)
+	{
+		return null;
+	}
+
+	@Override
+	public String getRealPath(String path)
+	{
+		return null;
+	}
+
+	@Override
+	public int getRemotePort()
+	{
+		return 0;
+	}
+
+	@Override
+	public String getLocalName()
+	{
+		return null;
+	}
+
+	@Override
+	public String getLocalAddr()
+	{
+		return null;
+	}
+
+	@Override
+	public int getLocalPort()
+	{
+		return 0;
+	}
+
+	@Override
+	public ServletContext getServletContext()
+	{
+		return null;
+	}
+
+	@Override
+	public AsyncContext startAsync() throws IllegalStateException
+	{
+		return null;
+	}
+
+	@Override
+	public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException
+	{
+		return null;
+	}
+
+	@Override
+	public boolean isAsyncStarted()
+	{
+		return false;
+	}
+
+	@Override
+	public boolean isAsyncSupported()
+	{
+		return false;
+	}
+
+	@Override
+	public AsyncContext getAsyncContext()
+	{
+		return null;
+	}
+
+	@Override
+	public DispatcherType getDispatcherType()
+	{
+		return null;
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketConnection.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketConnection.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketConnection.java
new file mode 100644
index 0000000..553682a
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketConnection.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.protocol.ws.javax;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import javax.websocket.CloseReason;
+import javax.websocket.Session;
+
+import org.apache.wicket.protocol.ws.api.AbstractWebSocketConnection;
+import org.apache.wicket.protocol.ws.api.AbstractWebSocketProcessor;
+import org.apache.wicket.protocol.ws.api.IWebSocketConnection;
+import org.apache.wicket.util.lang.Args;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A wrapper around Jetty9's native WebSocketConnection.
+ *
+ * @since 6.2
+ */
+public class JavaxWebSocketConnection extends AbstractWebSocketConnection
+{
+	private static final Logger LOG = LoggerFactory.getLogger(JavaxWebSocketConnection.class);
+
+	private final Session session;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param session
+	 *            the jetty websocket connection
+	 */
+	public JavaxWebSocketConnection(Session session, AbstractWebSocketProcessor webSocketProcessor)
+	{
+		super(webSocketProcessor);
+		this.session = Args.notNull(session, "connection");
+	}
+
+	@Override
+	public boolean isOpen()
+	{
+		return session.isOpen();
+	}
+
+	@Override
+	public void close(int code, String reason)
+	{
+		if (isOpen())
+		{
+			try
+			{
+				session.close(new CloseReason(new CloseCode(code), reason));
+			} catch (IOException iox)
+			{
+				LOG.error("An error occurred while closing WebSocket session", iox);
+			}
+		}
+	}
+
+	@Override
+	public IWebSocketConnection sendMessage(String message) throws IOException
+	{
+		checkClosed();
+
+		session.getBasicRemote().sendText(message);
+		return this;
+	}
+
+	@Override
+	public IWebSocketConnection sendMessage(byte[] message, int offset, int length)
+		throws IOException
+	{
+		checkClosed();
+
+		ByteBuffer buf = ByteBuffer.wrap(message, offset, length);
+		session.getBasicRemote().sendBinary(buf);
+		return this;
+	}
+
+	private void checkClosed()
+	{
+		if (!isOpen())
+		{
+			throw new IllegalStateException("The connection is closed.");
+		}
+	}
+
+	private static class CloseCode implements CloseReason.CloseCode
+	{
+		private final int code;
+
+		private CloseCode(int code)
+		{
+			this.code = code;
+		}
+
+		@Override
+		public int getCode()
+		{
+			return code;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketFilter.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketFilter.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketFilter.java
new file mode 100644
index 0000000..55b202b
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketFilter.java
@@ -0,0 +1,280 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.protocol.ws.javax;
+
+import java.net.URI;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.websocket.Decoder;
+import javax.websocket.DeploymentException;
+import javax.websocket.Encoder;
+import javax.websocket.Extension;
+import javax.websocket.HandshakeResponse;
+import javax.websocket.server.HandshakeRequest;
+import javax.websocket.server.ServerContainer;
+import javax.websocket.server.ServerEndpointConfig;
+
+import org.apache.wicket.protocol.http.WicketFilter;
+import org.apache.wicket.protocol.ws.AbstractUpgradeFilter;
+import org.apache.wicket.util.string.Strings;
+
+/**
+ * An upgrade filter that setups javax.websocket
+ */
+public class JavaxWebSocketFilter extends AbstractUpgradeFilter
+{
+	/**
+	 * A fake mount path used for WebSocket endpoint.
+	 * WicketFilter should not process this path.
+	 * @see WicketFilter#ignorePaths
+	 */
+	private static final String WICKET_WEB_SOCKET_PATH = "/wicket/websocket";
+
+	/**
+	 * A key used to store the application object in WebSocket's Endpoint user properties
+	 */
+	static final String APPLICATION_KEY = "wicket.application";
+
+	@Override
+	public void init(final boolean isServlet, final FilterConfig filterConfig) throws ServletException
+	{
+		super.init(isServlet, new JavaxWebSocketFilterConfig(filterConfig));
+
+		ServletContext servletContext = filterConfig.getServletContext();
+		ServerContainer sc = (ServerContainer) servletContext.getAttribute(ServerContainer.class.getName());
+
+		try
+		{
+			ServerEndpointConfig config = new WicketServerEndpointConfig(ServerEndpointConfig.Builder.create(WicketEndpoint.class, WICKET_WEB_SOCKET_PATH).build());
+			config.getUserProperties().put(APPLICATION_KEY, getApplication());
+			sc.addEndpoint(config);
+		}
+		catch (DeploymentException e) {
+			throw new IllegalStateException(e);
+		}
+	}
+
+	/**
+	 * A wrapper of the passed FilterConfig in #init() that adds #WICKET_WEB_SOCKET_PATH to
+	 * the list of ignored paths
+	 */
+	private static class JavaxWebSocketFilterConfig implements FilterConfig
+	{
+		private final FilterConfig delegate;
+
+		private JavaxWebSocketFilterConfig(FilterConfig delegate)
+		{
+			this.delegate = delegate;
+		}
+
+		@Override
+		public String getFilterName()
+		{
+			return delegate.getFilterName();
+		}
+
+		@Override
+		public ServletContext getServletContext()
+		{
+			return delegate.getServletContext();
+		}
+
+		@Override
+		public String getInitParameter(String s)
+		{
+			String result = delegate.getInitParameter(s);
+
+			if (WicketFilter.IGNORE_PATHS_PARAM.equalsIgnoreCase(s))
+			{
+				if (Strings.isEmpty(result))
+				{
+					result = WICKET_WEB_SOCKET_PATH;
+				}
+				else
+				{
+					result = result + ',' + WICKET_WEB_SOCKET_PATH;
+				}
+			}
+
+			return result;
+		}
+
+		@Override
+		public Enumeration<String> getInitParameterNames()
+		{
+			return delegate.getInitParameterNames();
+		}
+	}
+
+	/**
+	 * A ServerEndpointConfig that uses custom Configurator to collect
+	 * all available information from the passed HandshakeRequest
+	 */
+	private static class WicketServerEndpointConfig implements ServerEndpointConfig
+	{
+		private final ServerEndpointConfig delegate;
+		private Configurator configurator;
+
+		private WicketServerEndpointConfig(ServerEndpointConfig delegate)
+		{
+			this.delegate = delegate;
+		}
+
+		@Override
+		public Class<?> getEndpointClass()
+		{
+			return delegate.getEndpointClass();
+		}
+
+		@Override
+		public String getPath()
+		{
+			return delegate.getPath();
+		}
+
+		@Override
+		public List<String> getSubprotocols()
+		{
+			return delegate.getSubprotocols();
+		}
+
+		@Override
+		public List<Extension> getExtensions()
+		{
+			return delegate.getExtensions();
+		}
+
+		@Override
+		public Configurator getConfigurator()
+		{
+			if (configurator == null)
+			{
+				configurator = new JavaxWebSocketConfigurator(delegate.getConfigurator());
+			}
+			return configurator;
+		}
+
+		@Override
+		public List<Class<? extends Encoder>> getEncoders()
+		{
+			return delegate.getEncoders();
+		}
+
+		@Override
+		public List<Class<? extends Decoder>> getDecoders()
+		{
+			return delegate.getDecoders();
+		}
+
+		@Override
+		public Map<String, Object> getUserProperties()
+		{
+			return delegate.getUserProperties();
+		}
+	}
+
+	/**
+	 * A custom Configurator that collects all available information from the HandshakeRequest
+	 */
+	private static class JavaxWebSocketConfigurator extends ServerEndpointConfig.Configurator
+	{
+		private final ServerEndpointConfig.Configurator delegate;
+
+		public JavaxWebSocketConfigurator(ServerEndpointConfig.Configurator delegate)
+		{
+			this.delegate = delegate;
+		}
+
+		@Override
+		public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)
+		{
+			delegate.modifyHandshake(sec, request, response);
+
+			// do not store null keys/values because Tomcat 8 uses ConcurrentMap for UserProperties
+
+			Map<String, Object> userProperties = sec.getUserProperties();
+			Object httpSession = request.getHttpSession();
+			if (httpSession != null)
+			{
+				userProperties.put("session", httpSession);
+			}
+
+			Map<String, List<String>> headers = request.getHeaders();
+			if (headers != null)
+			{
+				userProperties.put("headers", headers);
+			}
+
+
+			Map<String, List<String>> parameterMap = request.getParameterMap();
+			if (parameterMap != null)
+			{
+				userProperties.put("parameterMap", parameterMap);
+			}
+
+
+			String queryString = request.getQueryString();
+			if (queryString != null)
+			{
+				userProperties.put("queryString", queryString);
+			}
+
+
+			URI requestURI = request.getRequestURI();
+			if (requestURI != null)
+			{
+				userProperties.put("requestURI", requestURI);
+			}
+
+			Principal userPrincipal = request.getUserPrincipal();
+			if (userPrincipal != null)
+			{
+				userProperties.put("userPrincipal", userPrincipal);
+			}
+		}
+
+		@Override
+		public String getNegotiatedSubprotocol(List<String> supported, List<String> requested)
+		{
+			return delegate.getNegotiatedSubprotocol(supported, requested);
+		}
+
+		@Override
+		public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
+		{
+			return delegate.getNegotiatedExtensions(installed, requested);
+		}
+
+		@Override
+		public boolean checkOrigin(String originHeaderValue)
+		{
+			return delegate.checkOrigin(originHeaderValue);
+		}
+
+		@Override
+		public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException
+		{
+			return super.getEndpointInstance(endpointClass);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketProcessor.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketProcessor.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketProcessor.java
new file mode 100644
index 0000000..1fa18a9
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketProcessor.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.protocol.ws.javax;
+
+import java.nio.ByteBuffer;
+
+import javax.websocket.MessageHandler;
+import javax.websocket.Session;
+
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.protocol.ws.api.AbstractWebSocketProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An {@link org.apache.wicket.protocol.ws.api.IWebSocketProcessor processor} that integrates with
+ * Jetty 9.x {@link Session web socket} implementation.
+ *
+ * @since 6.2
+ */
+public class JavaxWebSocketProcessor extends AbstractWebSocketProcessor
+{
+	private static final Logger LOG = LoggerFactory.getLogger(JavaxWebSocketProcessor.class);
+
+	/**
+	 * Constructor.
+	 *
+	 * @param session
+	 *            the WebSocket session
+	 * @param application
+	 *            the current Wicket Application
+	 */
+	public JavaxWebSocketProcessor(final Session session, final WebApplication application)
+	{
+		super(new JavaxUpgradeHttpRequest(session), application);
+
+		onConnect(new JavaxWebSocketConnection(session, this));
+
+		session.addMessageHandler(new StringMessageHandler());
+		session.addMessageHandler(new BinaryMessageHandler());
+	}
+
+
+	@Override
+	public void onOpen(Object containerConnection)
+	{
+	}
+
+	private class StringMessageHandler implements MessageHandler.Whole<String>
+	{
+		@Override
+		public void onMessage(String message)
+		{
+			JavaxWebSocketProcessor.this.onMessage(message);
+		}
+	}
+
+	private class BinaryMessageHandler implements MessageHandler.Whole<ByteBuffer>
+	{
+		@Override
+		public void onMessage(ByteBuffer message)
+		{
+			byte[] array = message.array();
+			JavaxWebSocketProcessor.this.onMessage(array, 0, array.length);
+		}
+	}
+
+
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
new file mode 100644
index 0000000..57b4e0b
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.protocol.ws.javax;
+
+import javax.websocket.CloseReason;
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.Session;
+
+import org.apache.wicket.ThreadContext;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WicketEndpoint extends Endpoint
+{
+	private static final Logger LOG = LoggerFactory.getLogger(WicketEndpoint.class);
+
+	private JavaxWebSocketProcessor javaxWebSocketProcessor;
+
+	@Override
+	public void onOpen(Session session, EndpointConfig endpointConfig)
+	{
+		WebApplication app = (WebApplication) session.getUserProperties().get(JavaxWebSocketFilter.APPLICATION_KEY);
+
+		try
+		{
+			ThreadContext.setApplication(app);
+			javaxWebSocketProcessor = new JavaxWebSocketProcessor(session, app);
+		}
+		finally
+		{
+			ThreadContext.detach();
+		}
+
+	}
+
+	@Override
+	public void onClose(Session session, CloseReason closeReason)
+	{
+		super.onClose(session, closeReason);
+
+		javaxWebSocketProcessor.onClose(closeReason.getCloseCode().getCode(), closeReason.getReasonPhrase());
+	}
+
+	@Override
+	public void onError(Session session, Throwable t)
+	{
+		super.onError(session, t);
+
+		LOG.error("An error occurred in web socket connection with id : " + session.getId(), t);
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/test/java/log4j.properties
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/test/java/log4j.properties b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/test/java/log4j.properties
new file mode 100644
index 0000000..976b5c8
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/test/java/log4j.properties
@@ -0,0 +1,16 @@
+log4j.debug=false
+
+log4j.rootLogger=INFO,Stdout
+
+# please keep this setting FATAL to avoid questions from users
+# why there are stacktraces in the test output. You can turn it
+# down if you need to when testing, but don't check it in. (eelco)
+
+# changing back to ERROR. Looks like in some cases the log4j.properties
+# in wicket gets picked which results in not printing the exceptions
+# and that can be a bit dangerous (matej)
+log4j.logger.org.apache.wicket=ERROR
+
+log4j.appender.Stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.Stdout.layout.conversionPattern=%-5p - %-26.26c{1} - %m\n

http://git-wip-us.apache.org/repos/asf/wicket/blob/36ad94dd/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/test/java/org/apache/wicket/protocol/ws/util/licence/ApacheLicenceHeaderTest.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/test/java/org/apache/wicket/protocol/ws/util/licence/ApacheLicenceHeaderTest.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/test/java/org/apache/wicket/protocol/ws/util/licence/ApacheLicenceHeaderTest.java
new file mode 100644
index 0000000..cd3cbf1
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-javax/src/test/java/org/apache/wicket/protocol/ws/util/licence/ApacheLicenceHeaderTest.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.wicket.protocol.ws.util.licence;
+
+import org.apache.wicket.util.license.ApacheLicenseHeaderTestCase;
+
+/**
+ * Test that the license headers are in place in this project. The tests are run from
+ * {@link org.apache.wicket.util.license.ApacheLicenseHeaderTestCase}, but you can add project specific tests here if needed.
+ */
+public class ApacheLicenceHeaderTest extends ApacheLicenseHeaderTestCase
+{
+	/**
+	 * Construct.
+	 */
+	public ApacheLicenceHeaderTest()
+	{
+		// addHeaders = true;
+	}
+}