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/11/22 11:52:04 UTC

[1/3] git commit: WICKET-5423 Create IResource based implementation of Native Web Sockets

Updated Branches:
  refs/heads/wicket-6.x fa88b3bdc -> 9c3a0ad5c


WICKET-5423 Create IResource based implementation of Native Web Sockets

Move IWebSocketConnectionRegistry to **.api.registry package


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

Branch: refs/heads/wicket-6.x
Commit: 9c3a0ad5cffe06eb5bd1b4979ccbdbd98d3975a2
Parents: ff14a7d
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Fri Nov 22 12:13:34 2013 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Fri Nov 22 12:51:50 2013 +0200

----------------------------------------------------------------------
 .../wicket/protocol/ws/IWebSocketSettings.java  |   2 +-
 .../wicket/protocol/ws/WebSocketSettings.java   |   4 +-
 .../ws/api/AbstractWebSocketProcessor.java      |   1 +
 .../ws/api/IWebSocketConnectionRegistry.java    |  74 ----------
 .../api/SimpleWebSocketConnectionRegistry.java  | 140 -------------------
 .../ws/api/WebSocketPushBroadcaster.java        |   1 +
 .../protocol/ws/api/WebSocketResponse.java      |   3 +-
 .../wicket/protocol/ws/api/registry/IKey.java   |   2 +-
 .../registry/IWebSocketConnectionRegistry.java  |  75 ++++++++++
 .../SimpleWebSocketConnectionRegistry.java      | 140 +++++++++++++++++++
 10 files changed, 223 insertions(+), 219 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/IWebSocketSettings.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/IWebSocketSettings.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/IWebSocketSettings.java
index b3a3833..bcc35ea 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/IWebSocketSettings.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/IWebSocketSettings.java
@@ -19,7 +19,7 @@ package org.apache.wicket.protocol.ws;
 
 import org.apache.wicket.Application;
 import org.apache.wicket.MetaDataKey;
-import org.apache.wicket.protocol.ws.api.IWebSocketConnectionRegistry;
+import org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry;
 import org.apache.wicket.protocol.ws.concurrent.Executor;
 
 /**

http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/WebSocketSettings.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/WebSocketSettings.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/WebSocketSettings.java
index 3c7180d..1b5ea56 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/WebSocketSettings.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/WebSocketSettings.java
@@ -18,8 +18,8 @@ package org.apache.wicket.protocol.ws;
 
 import java.util.concurrent.Callable;
 
-import org.apache.wicket.protocol.ws.api.IWebSocketConnectionRegistry;
-import org.apache.wicket.protocol.ws.api.SimpleWebSocketConnectionRegistry;
+import org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry;
+import org.apache.wicket.protocol.ws.api.registry.SimpleWebSocketConnectionRegistry;
 import org.apache.wicket.protocol.ws.concurrent.Executor;
 import org.apache.wicket.util.lang.Args;
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/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 2dade93..b704303 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
@@ -45,6 +45,7 @@ import org.apache.wicket.protocol.ws.api.message.IWebSocketMessage;
 import org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;
 import org.apache.wicket.protocol.ws.api.message.TextMessage;
 import org.apache.wicket.protocol.ws.api.registry.IKey;
+import org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry;
 import org.apache.wicket.protocol.ws.api.registry.PageIdKey;
 import org.apache.wicket.protocol.ws.api.registry.ResourceNameKey;
 import org.apache.wicket.request.Url;

http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/IWebSocketConnectionRegistry.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/IWebSocketConnectionRegistry.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/IWebSocketConnectionRegistry.java
deleted file mode 100644
index 8fc47b7..0000000
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/IWebSocketConnectionRegistry.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.api;
-
-import java.util.Collection;
-import org.apache.wicket.Application;
-import org.apache.wicket.protocol.ws.api.registry.IKey;
-
-/**
- * Tracks all currently connected WebSocket clients
- *
- * @since 6.0
- */
-public interface IWebSocketConnectionRegistry
-{
-	/**
-	 * @param application
-	 *      the web application to look in
-	 * @param sessionId
-	 *      the web socket client session id
-	 * @param key
-	 *      the web socket client key
-	 * @return the web socket connection used by a client from the specified coordinates
-	 */
-	IWebSocketConnection getConnection(Application application, String sessionId, IKey key);
-
-
-	/**
-	 * @param application
-	 *            the web application to look in
-	 * @return collection of web socket connection used by any client connected to specified application
-	 */
-	Collection<IWebSocketConnection> getConnections(Application application);
-
-	/**
-	 * Adds a new connection into the registry at the specified coordinates (application+session+page)
-	 *
-	 * @param application
-	 *      the web application to look in
-	 * @param sessionId
-	 *      the web socket client session id
-	 * @param key
-	 *      the web socket client key
-	 * @param connection
-	 *      the web socket connection to add
-	 */
-	void setConnection(Application application, String sessionId, IKey key, IWebSocketConnection connection);
-
-	/**
-	 * Removes a web socket connection from the registry at the specified coordinates (application+session+page)
-	 *
-	 * @param application
-	 *      the web application to look in
-	 * @param sessionId
-	 *      the web socket client session id
-	 * @param key
-	 *      the web socket client key
-	 */
-	void removeConnection(Application application, String sessionId, IKey key);
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/SimpleWebSocketConnectionRegistry.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/SimpleWebSocketConnectionRegistry.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/SimpleWebSocketConnectionRegistry.java
deleted file mode 100644
index bf8e930..0000000
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/SimpleWebSocketConnectionRegistry.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.api;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.concurrent.ConcurrentMap;
-
-import org.apache.wicket.Application;
-import org.apache.wicket.MetaDataKey;
-import org.apache.wicket.protocol.ws.api.registry.IKey;
-import org.apache.wicket.util.lang.Args;
-import org.apache.wicket.util.lang.Generics;
-
-/**
- * A registry that keeps all currently opened web socket connections in
- * maps in Application's meta data.
- *
- * TODO remove the synchronizations below and use ConcurrentMap#putIfAbsent()
- *
- * @since 6.0
- */
-public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRegistry
-{
-	private static final MetaDataKey<ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>>> KEY =
-			new MetaDataKey<ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>>>()
-	{
-	};
-
-	@Override
-	public IWebSocketConnection getConnection(Application application, String sessionId, IKey key)
-	{
-		Args.notNull(application, "application");
-		Args.notNull(sessionId, "sessionId");
-		Args.notNull(key, "key");
-
-		IWebSocketConnection connection = null;
-		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
-		if (connectionsBySession != null)
-		{
-			ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId);
-			if (connectionsByPage != null)
-			{
-				connection = connectionsByPage.get(key);
-			}
-		}
-		return connection;
-	}
-
-	/**
-	 * Returns a collection of currently active websockets. The connections might close at any time.
-	 *
-	 * @param application
-	 * @return
-	 */
-	public Collection<IWebSocketConnection> getConnections(Application application)
-	{
-		Args.notNull(application, "application");
-
-		Collection<IWebSocketConnection> connections = new ArrayList<IWebSocketConnection>();
-		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
-		if (connectionsBySession != null)
-		{
-			for (ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage : connectionsBySession.values())
-			{
-				connections.addAll(connectionsByPage.values());
-			}
-		}
-		return connections;
-	}
-
-	@Override
-	public void setConnection(Application application, String sessionId, IKey key, IWebSocketConnection connection)
-	{
-		Args.notNull(application, "application");
-		Args.notNull(sessionId, "sessionId");
-		Args.notNull(key, "key");
-
-		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
-		if (connectionsBySession == null)
-		{
-			synchronized (KEY)
-			{
-				connectionsBySession = application.getMetaData(KEY);
-				if (connectionsBySession == null)
-				{
-					connectionsBySession = Generics.newConcurrentHashMap();
-					application.setMetaData(KEY, connectionsBySession);
-				}
-			}
-		}
-
-		ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId);
-		if (connectionsByPage == null && connection != null)
-		{
-			synchronized (connectionsBySession)
-			{
-				connectionsByPage = connectionsBySession.get(sessionId);
-				if (connectionsByPage == null)
-				{
-					connectionsByPage = Generics.newConcurrentHashMap();
-					connectionsBySession.put(sessionId, connectionsByPage);
-				}
-			}
-		}
-
-		if (connection != null)
-		{
-			connectionsByPage.put(key, connection);
-		}
-		else if (connectionsByPage != null)
-		{
-			connectionsByPage.remove(key);
-			if (connectionsByPage.isEmpty())
-			{
-				connectionsBySession.remove(sessionId);
-			}
-		}
-	}
-
-	@Override
-	public void removeConnection(Application application, String sessionId, IKey key)
-	{
-		setConnection(application, sessionId, key, null);
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
index 24e4056..cbe2daf 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
@@ -25,6 +25,7 @@ import org.apache.wicket.protocol.ws.IWebSocketSettings;
 import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
 import org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;
 import org.apache.wicket.protocol.ws.api.registry.IKey;
+import org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry;
 import org.apache.wicket.protocol.ws.concurrent.Executor;
 import org.apache.wicket.util.lang.Args;
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketResponse.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketResponse.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketResponse.java
index 7faa195..d5f36bf 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketResponse.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketResponse.java
@@ -32,7 +32,8 @@ import org.slf4j.LoggerFactory;
  * when Wicket thread locals are available.
  *
  * When the thread locals are not available then you can write directly to the {@link IWebSocketConnection}
- * taken from {@link IWebSocketConnectionRegistry}. In this case the response wont be cached.
+ * taken from {@link org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry}.
+ * In this case the response wont be cached.
  *
  * @since 6.0
  */

http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
index cecda06..e05e76e 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
@@ -18,7 +18,7 @@ package org.apache.wicket.protocol.ws.api.registry;
 
 /**
  * A marker interface for keys that are used to find a web socket
- * connection in {@link org.apache.wicket.protocol.ws.api.IWebSocketConnectionRegistry}
+ * connection in {@link IWebSocketConnectionRegistry}
  */
 public interface IKey
 {}

http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java
new file mode 100644
index 0000000..e62ea4f
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java
@@ -0,0 +1,75 @@
+/*
+ * 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.api.registry;
+
+import java.util.Collection;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.protocol.ws.api.IWebSocketConnection;
+
+/**
+ * Tracks all currently connected WebSocket clients
+ *
+ * @since 6.0
+ */
+public interface IWebSocketConnectionRegistry
+{
+	/**
+	 * @param application
+	 *      the web application to look in
+	 * @param sessionId
+	 *      the web socket client session id
+	 * @param key
+	 *      the web socket client key
+	 * @return the web socket connection used by a client from the specified coordinates
+	 */
+	IWebSocketConnection getConnection(Application application, String sessionId, IKey key);
+
+
+	/**
+	 * @param application
+	 *            the web application to look in
+	 * @return collection of web socket connection used by any client connected to specified application
+	 */
+	Collection<IWebSocketConnection> getConnections(Application application);
+
+	/**
+	 * Adds a new connection into the registry at the specified coordinates (application+session+page)
+	 *
+	 * @param application
+	 *      the web application to look in
+	 * @param sessionId
+	 *      the web socket client session id
+	 * @param key
+	 *      the web socket client key
+	 * @param connection
+	 *      the web socket connection to add
+	 */
+	void setConnection(Application application, String sessionId, IKey key, IWebSocketConnection connection);
+
+	/**
+	 * Removes a web socket connection from the registry at the specified coordinates (application+session+page)
+	 *
+	 * @param application
+	 *      the web application to look in
+	 * @param sessionId
+	 *      the web socket client session id
+	 * @param key
+	 *      the web socket client key
+	 */
+	void removeConnection(Application application, String sessionId, IKey key);
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/9c3a0ad5/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/SimpleWebSocketConnectionRegistry.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/SimpleWebSocketConnectionRegistry.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/SimpleWebSocketConnectionRegistry.java
new file mode 100644
index 0000000..ef78f97
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/SimpleWebSocketConnectionRegistry.java
@@ -0,0 +1,140 @@
+/*
+ * 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.api.registry;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.MetaDataKey;
+import org.apache.wicket.protocol.ws.api.IWebSocketConnection;
+import org.apache.wicket.util.lang.Args;
+import org.apache.wicket.util.lang.Generics;
+
+/**
+ * A registry that keeps all currently opened web socket connections in
+ * maps in Application's meta data.
+ *
+ * TODO remove the synchronizations below and use ConcurrentMap#putIfAbsent()
+ *
+ * @since 6.0
+ */
+public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRegistry
+{
+	private static final MetaDataKey<ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>>> KEY =
+			new MetaDataKey<ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>>>()
+	{
+	};
+
+	@Override
+	public IWebSocketConnection getConnection(Application application, String sessionId, IKey key)
+	{
+		Args.notNull(application, "application");
+		Args.notNull(sessionId, "sessionId");
+		Args.notNull(key, "key");
+
+		IWebSocketConnection connection = null;
+		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
+		if (connectionsBySession != null)
+		{
+			ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId);
+			if (connectionsByPage != null)
+			{
+				connection = connectionsByPage.get(key);
+			}
+		}
+		return connection;
+	}
+
+	/**
+	 * Returns a collection of currently active websockets. The connections might close at any time.
+	 *
+	 * @param application
+	 * @return
+	 */
+	public Collection<IWebSocketConnection> getConnections(Application application)
+	{
+		Args.notNull(application, "application");
+
+		Collection<IWebSocketConnection> connections = new ArrayList<IWebSocketConnection>();
+		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
+		if (connectionsBySession != null)
+		{
+			for (ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage : connectionsBySession.values())
+			{
+				connections.addAll(connectionsByPage.values());
+			}
+		}
+		return connections;
+	}
+
+	@Override
+	public void setConnection(Application application, String sessionId, IKey key, IWebSocketConnection connection)
+	{
+		Args.notNull(application, "application");
+		Args.notNull(sessionId, "sessionId");
+		Args.notNull(key, "key");
+
+		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
+		if (connectionsBySession == null)
+		{
+			synchronized (KEY)
+			{
+				connectionsBySession = application.getMetaData(KEY);
+				if (connectionsBySession == null)
+				{
+					connectionsBySession = Generics.newConcurrentHashMap();
+					application.setMetaData(KEY, connectionsBySession);
+				}
+			}
+		}
+
+		ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId);
+		if (connectionsByPage == null && connection != null)
+		{
+			synchronized (connectionsBySession)
+			{
+				connectionsByPage = connectionsBySession.get(sessionId);
+				if (connectionsByPage == null)
+				{
+					connectionsByPage = Generics.newConcurrentHashMap();
+					connectionsBySession.put(sessionId, connectionsByPage);
+				}
+			}
+		}
+
+		if (connection != null)
+		{
+			connectionsByPage.put(key, connection);
+		}
+		else if (connectionsByPage != null)
+		{
+			connectionsByPage.remove(key);
+			if (connectionsByPage.isEmpty())
+			{
+				connectionsBySession.remove(sessionId);
+			}
+		}
+	}
+
+	@Override
+	public void removeConnection(Application application, String sessionId, IKey key)
+	{
+		setConnection(application, sessionId, key, null);
+	}
+}


[2/3] git commit: WICKET-5423 Create IResource based implementation of Native Web Sockets

Posted by mg...@apache.org.
WICKET-5423 Create IResource based implementation of Native Web Sockets

Add support for testing WebSocketResource and unit tests


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

Branch: refs/heads/wicket-6.x
Commit: ff14a7d0124e473901af9f973cdeee13d12981de
Parents: 0c97e75
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Thu Nov 21 17:20:04 2013 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Fri Nov 22 12:51:50 2013 +0200

----------------------------------------------------------------------
 .../ws/util/tester/TestWebSocketProcessor.java  |  42 ++++-
 .../ws/util/tester/WebSocketTester.java         |  36 +++-
 .../ws/util/tester/TestWebSocketResource.java   | 104 +++++++++++
 .../util/tester/WebSocketBehaviorTestPage.java  |  83 +++++++++
 .../ws/util/tester/WebSocketTestPage.java       |  83 ---------
 .../tester/WebSocketTesterBehaviorTest.java     | 178 +++++++++++++++++++
 .../tester/WebSocketTesterResourceTest.java     | 142 +++++++++++++++
 .../ws/util/tester/WebSocketTesterTest.java     | 177 ------------------
 8 files changed, 582 insertions(+), 263 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/ff14a7d0/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketProcessor.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketProcessor.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketProcessor.java
index 0d79e9e..80642a8 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketProcessor.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketProcessor.java
@@ -48,6 +48,17 @@ abstract class TestWebSocketProcessor extends AbstractWebSocketProcessor
 	}
 
 	/**
+	 * Constructor.
+	 *
+	 * @param resourceName
+	 *      the name of the shared resource that will handle the web socket messages
+	 */
+	public TestWebSocketProcessor(final WicketTester wicketTester, final String resourceName)
+	{
+		super(createRequest(wicketTester, resourceName),  wicketTester.getApplication());
+	}
+
+	/**
 	 * Creates an HttpServletRequest that is needed by AbstractWebSocketProcessor
 	 *
 	 * @param page
@@ -57,14 +68,41 @@ abstract class TestWebSocketProcessor extends AbstractWebSocketProcessor
 	private static HttpServletRequest createRequest(final WicketTester wicketTester, final Page page)
 	{
 		Args.notNull(page, "page");
-		Application application = page.getApplication();
+		MockHttpServletRequest request = createRequest(wicketTester);
+		request.addParameter("pageId", page.getId());
+		return request;
+	}
+
+	/**
+	 * Creates an HttpServletRequest that is needed by AbstractWebSocketProcessor
+	 *
+	 * @param resourceName
+	 *      the page that may have registered {@link org.apache.wicket.protocol.ws.api.WebSocketBehavior}
+	 * @return a mock http request
+	 */
+	private static HttpServletRequest createRequest(final WicketTester wicketTester, final String resourceName)
+	{
+		Args.notNull(resourceName, "resourceName");
+		MockHttpServletRequest request = createRequest(wicketTester);
+		request.addParameter("resourceName", resourceName);
+		return request;
+	}
+
+	/**
+	 * Creates an HttpServletRequest that is needed by AbstractWebSocketProcessor
+	 *
+	 * @return a mock http request
+	 */
+	private static MockHttpServletRequest createRequest(final WicketTester wicketTester)
+	{
+		Application application = wicketTester.getApplication();
 		HttpSession httpSession = wicketTester.getHttpSession();
 		MockHttpServletRequest request = new MockHttpServletRequest(application, httpSession, null);
-		request.addParameter("pageId", page.getId());
 		request.addParameter(WebRequest.PARAM_AJAX_BASE_URL, ".");
 		return request;
 	}
 
+
 	/**
 	 * Setups TestWebSocketConnection.
 	 *

http://git-wip-us.apache.org/repos/asf/wicket/blob/ff14a7d0/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTester.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTester.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTester.java
index 761690b..4f8a9b5 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTester.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTester.java
@@ -47,8 +47,42 @@ public class WebSocketTester
 		WebApplication webApplication = wicketTester.getApplication();
 		webApplication.getWicketFilter().setFilterPath("");
 
-		socketProcessor = new TestWebSocketProcessor(wicketTester, page) {
+		socketProcessor = new TestWebSocketProcessor(wicketTester, page)
+		{
+			@Override
+			protected void onOutMessage(String message)
+			{
+				WebSocketTester.this.onOutMessage(message);
+			}
+
+			@Override
+			protected void onOutMessage(byte[] message, int offset, int length)
+			{
+				WebSocketTester.this.onOutMessage(message, offset, length);
+			}
+		};
+		socketProcessor.onOpen(null);
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * Prepares a WebSockConnection that will be used to send messages from the client (the test case)
+	 * to the server.
+	 *
+	 * @param resourceName
+	 *      the name of the shared WebSocketResource that will handle the web socket messages
+	 */
+	public WebSocketTester(final WicketTester wicketTester, final String resourceName)
+	{
+		Args.notNull(wicketTester, "wicketTester");
+		Args.notNull(resourceName, "resourceName");
+
+		WebApplication webApplication = wicketTester.getApplication();
+		webApplication.getWicketFilter().setFilterPath("");
 
+		socketProcessor = new TestWebSocketProcessor(wicketTester, resourceName)
+		{
 			@Override
 			protected void onOutMessage(String message)
 			{

http://git-wip-us.apache.org/repos/asf/wicket/blob/ff14a7d0/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketResource.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketResource.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketResource.java
new file mode 100644
index 0000000..2bee3f1
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketResource.java
@@ -0,0 +1,104 @@
+/*
+ * 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.tester;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.wicket.util.string.Strings;
+import org.junit.Assert;
+import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler;
+import org.apache.wicket.protocol.ws.api.WebSocketResource;
+import org.apache.wicket.protocol.ws.api.message.BinaryMessage;
+import org.apache.wicket.protocol.ws.api.message.ClosedMessage;
+import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
+import org.apache.wicket.protocol.ws.api.message.TextMessage;
+
+/**
+ *
+ */
+public class TestWebSocketResource extends WebSocketResource
+{
+	static final String TEXT = "TestWebSocketResource-text";
+	static final String BINARY = "TestWebSocketResource-binary";
+
+	static final AtomicBoolean ON_CONNECT_CALLED = new AtomicBoolean(false);
+	static final AtomicBoolean ON_CLOSE_CALLED = new AtomicBoolean(false);
+
+	private final String expectedMessage;
+
+	private final byte[] expectedBinaryMessage;
+	private final int expectedOffset;
+	private final int expectedLength;
+
+	TestWebSocketResource(String expected)
+	{
+		this.expectedMessage = expected;
+
+		this.expectedBinaryMessage = null;
+		this.expectedOffset = -1;
+		this.expectedLength = -1;
+	}
+
+	TestWebSocketResource(byte[] message, int offset, int length)
+	{
+		this.expectedBinaryMessage = message;
+		this.expectedOffset = offset;
+		this.expectedLength = length;
+
+		this.expectedMessage = null;
+	}
+
+	@Override
+	protected void onConnect(ConnectedMessage message)
+	{
+		super.onConnect(message);
+		ON_CONNECT_CALLED.set(true);
+	}
+
+	@Override
+	protected void onClose(ClosedMessage message)
+	{
+		ON_CLOSE_CALLED.set(true);
+		super.onClose(message);
+	}
+
+	@Override
+	protected void onMessage(WebSocketRequestHandler handler, TextMessage message)
+	{
+		super.onMessage(handler, message);
+
+		String text = message.getText();
+		Assert.assertEquals(expectedMessage, text);
+		handler.push(Strings.capitalize(text));
+	}
+
+	@Override
+	protected void onMessage(WebSocketRequestHandler handler, BinaryMessage binaryMessage)
+	{
+		super.onMessage(handler, binaryMessage);
+
+		byte[] data = binaryMessage.getData();
+		int offset = binaryMessage.getOffset();
+		int length = binaryMessage.getLength();
+
+		Assert.assertEquals(expectedBinaryMessage, data);
+		Assert.assertEquals(expectedOffset, offset);
+		Assert.assertEquals(expectedLength, length);
+
+		handler.push(data, offset, length);
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/ff14a7d0/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketBehaviorTestPage.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketBehaviorTestPage.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketBehaviorTestPage.java
new file mode 100644
index 0000000..d64f103
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketBehaviorTestPage.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.util.tester;
+
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler;
+import org.apache.wicket.markup.IMarkupResourceStreamProvider;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.protocol.ws.api.WebSocketBehavior;
+import org.apache.wicket.protocol.ws.api.message.BinaryMessage;
+import org.apache.wicket.protocol.ws.api.message.TextMessage;
+import org.apache.wicket.util.resource.IResourceStream;
+import org.apache.wicket.util.resource.StringResourceStream;
+import org.apache.wicket.util.string.Strings;
+import org.junit.Assert;
+
+/**
+ * A page used for {@link WebSocketTesterBehaviorTest}
+ *
+ * @since 6.0
+ */
+class WebSocketBehaviorTestPage extends WebPage implements IMarkupResourceStreamProvider
+{
+	WebSocketBehaviorTestPage()
+	{
+		add(new WebSocketBehavior() {});
+	}
+
+	WebSocketBehaviorTestPage(final String expectedMessage)
+	{
+		add(new WebSocketBehavior()
+		{
+			@Override
+			protected void onMessage(WebSocketRequestHandler handler, TextMessage message)
+			{
+				// assert the inbould message
+				Assert.assertEquals(expectedMessage, message.getText());
+
+				// now send an outbound message
+				handler.push(Strings.capitalize(expectedMessage));
+			}
+		});
+	}
+
+	WebSocketBehaviorTestPage(final byte[] message, final int offset, final int length)
+	{
+		add(new WebSocketBehavior()
+		{
+			@Override
+			protected void onMessage(WebSocketRequestHandler handler, BinaryMessage binaryMessage)
+			{
+				Assert.assertArrayEquals(message, binaryMessage.getData());
+				Assert.assertEquals(offset, binaryMessage.getOffset());
+				Assert.assertEquals(length, binaryMessage.getLength());
+
+				String msg = new String(message);
+				byte[] pushedMessage = Strings.capitalize(msg).getBytes();
+
+				handler.push(pushedMessage, offset + 1, length - 1);
+			}
+		});
+	}
+
+	@Override
+	public IResourceStream getMarkupResourceStream(MarkupContainer container, Class<?> containerClass)
+	{
+		return new StringResourceStream("<html/>");
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/ff14a7d0/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTestPage.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTestPage.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTestPage.java
deleted file mode 100644
index 39eef88..0000000
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTestPage.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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.tester;
-
-import org.apache.wicket.MarkupContainer;
-import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler;
-import org.apache.wicket.markup.IMarkupResourceStreamProvider;
-import org.apache.wicket.markup.html.WebPage;
-import org.apache.wicket.protocol.ws.api.WebSocketBehavior;
-import org.apache.wicket.protocol.ws.api.message.BinaryMessage;
-import org.apache.wicket.protocol.ws.api.message.TextMessage;
-import org.apache.wicket.util.resource.IResourceStream;
-import org.apache.wicket.util.resource.StringResourceStream;
-import org.apache.wicket.util.string.Strings;
-import org.junit.Assert;
-
-/**
- * A page used for {@link WebSocketTesterTest}
- *
- * @since 6.0
- */
-class WebSocketTestPage extends WebPage implements IMarkupResourceStreamProvider
-{
-	WebSocketTestPage()
-	{
-		add(new WebSocketBehavior() {});
-	}
-
-	WebSocketTestPage(final String expectedMessage)
-	{
-		add(new WebSocketBehavior()
-		{
-			@Override
-			protected void onMessage(WebSocketRequestHandler handler, TextMessage message)
-			{
-				// assert the inbould message
-				Assert.assertEquals(expectedMessage, message.getText());
-				
-				// now send an outbound message
-				handler.push(Strings.capitalize(expectedMessage));
-			}
-		});
-	}
-	
-	WebSocketTestPage(final byte[] message, final int offset, final int length)
-	{
-		add(new WebSocketBehavior()
-		{
-			@Override
-			protected void onMessage(WebSocketRequestHandler handler, BinaryMessage binaryMessage)
-			{
-				Assert.assertArrayEquals(message, binaryMessage.getData());
-				Assert.assertEquals(offset, binaryMessage.getOffset());
-				Assert.assertEquals(length, binaryMessage.getLength());
-				
-				String msg = new String(message);
-				byte[] pushedMessage = Strings.capitalize(msg).getBytes();
-				
-				handler.push(pushedMessage, offset + 1, length - 1);
-			}
-		});
-	}
-
-	@Override
-	public IResourceStream getMarkupResourceStream(MarkupContainer container, Class<?> containerClass)
-	{
-		return new StringResourceStream("<html/>");
-	}
-}

http://git-wip-us.apache.org/repos/asf/wicket/blob/ff14a7d0/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterBehaviorTest.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterBehaviorTest.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterBehaviorTest.java
new file mode 100644
index 0000000..ce123cb
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterBehaviorTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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.tester;
+
+import java.io.UnsupportedEncodingException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.protocol.ws.IWebSocketSettings;
+import org.apache.wicket.protocol.ws.api.WebSocketPushBroadcaster;
+import org.apache.wicket.protocol.ws.api.event.WebSocketPushPayload;
+import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
+import org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;
+import org.apache.wicket.protocol.ws.api.registry.PageIdKey;
+import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.tester.WicketTester;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for WebSocketTester.
+ * Uses WebSocketBehavior.
+ *
+ * @since 6.0
+ */
+public class WebSocketTesterBehaviorTest extends Assert
+{
+	WicketTester tester;
+
+	@Before
+	public void before()
+	{
+		tester = new WicketTester();
+	}
+
+	@After
+	public void after()
+	{
+		tester.destroy();
+	}
+
+	/**
+	 * A simple test that sends and receives a text message.
+	 * The page asserts that it received the correct message and then
+	 * pushed back the same message but capitalized.
+	 */
+	@Test
+	public void sendTextMessageBehavior()
+	{
+		final String expectedMessage = "some message";
+
+		WebSocketBehaviorTestPage page = new WebSocketBehaviorTestPage(expectedMessage);
+		tester.startPage(page);
+
+		WebSocketTester webSocketTester = new WebSocketTester(tester, page) {
+			@Override
+			protected void onOutMessage(String message)
+			{
+				assertEquals(Strings.capitalize(expectedMessage), message);
+			}
+		};
+
+		webSocketTester.sendMessage(expectedMessage);
+		webSocketTester.destroy();
+	}
+
+	/**
+	 * A simple test that sends and receives a binary message.
+	 * The page asserts that it received the correct message, offset and lenght and then
+	 * pushes back the same message but capitalized, offset plus 1 and length minus 1.
+	 */
+	@Test
+	public void sendBinaryMessageBehavior() throws UnsupportedEncodingException
+	{
+		final byte[] expectedMessage = "some message".getBytes("UTF-8");
+		final int offset = 1;
+		final int length = 2;
+
+		WebSocketBehaviorTestPage page = new WebSocketBehaviorTestPage(expectedMessage, offset, length);
+		tester.startPage(page);
+
+		WebSocketTester webSocketTester = new WebSocketTester(tester, page) {
+			@Override
+			protected void onOutMessage(byte[] message, int off, int len)
+			{
+				try
+				{
+					String msg = new String(expectedMessage);
+					byte[] pushedMessage = Strings.capitalize(msg).getBytes("UTF-8");
+
+					assertArrayEquals(pushedMessage, message);
+					assertEquals(offset + 1, off);
+					assertEquals(length - 1, len);
+
+				} catch (UnsupportedEncodingException uex)
+				{
+					throw new RuntimeException(uex);
+				}
+			}
+		};
+
+		webSocketTester.sendMessage(expectedMessage, offset, length);
+		webSocketTester.destroy();
+	}
+
+	@Test
+	public void serverSideBroadcast()
+	{
+		final String message = "Broadcasted Message";
+
+		final AtomicBoolean messageReceived = new AtomicBoolean(false);
+
+		WebSocketBehaviorTestPage page = new WebSocketBehaviorTestPage()
+		{
+			@Override
+			public void onEvent(IEvent<?> event)
+			{
+				super.onEvent(event);
+
+				if (event.getPayload() instanceof WebSocketPushPayload)
+				{
+					WebSocketPushPayload payload = (WebSocketPushPayload) event.getPayload();
+
+					if (payload.getMessage() instanceof BroadcastMessage)
+					{
+						BroadcastMessage broadcastMessage = (BroadcastMessage) payload.getMessage();
+						if (message.equals(broadcastMessage.getText()))
+						{
+							messageReceived.set(true);
+						}
+					}
+				}
+			}
+		};
+		tester.startPage(page);
+		tester.getSession().bind();
+
+		new WebSocketTester(tester, page);
+		IWebSocketSettings webSocketSettings = IWebSocketSettings.Holder.get(tester.getApplication());
+		WebSocketPushBroadcaster broadcaster = new WebSocketPushBroadcaster(webSocketSettings.getConnectionRegistry());
+		ConnectedMessage wsMessage = new ConnectedMessage(tester.getApplication(),
+				tester.getHttpSession().getId(), new PageIdKey(page.getPageId()));
+		broadcaster.broadcast(wsMessage, new BroadcastMessage(message));
+
+		assertEquals(true, messageReceived.get());
+	}
+
+	private static class BroadcastMessage implements IWebSocketPushMessage
+	{
+		private final String message;
+
+		private BroadcastMessage(String message)
+		{
+			this.message = message;
+		}
+
+		public String getText()
+		{
+			return message;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/ff14a7d0/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterResourceTest.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterResourceTest.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterResourceTest.java
new file mode 100644
index 0000000..d64c35d
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterResourceTest.java
@@ -0,0 +1,142 @@
+/*
+ * 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.tester;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.wicket.mock.MockApplication;
+import org.apache.wicket.protocol.http.WebApplication;
+import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.tester.WicketTester;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for WebSocketTester.
+ * Uses WebSocketBehavior.
+ *
+ * @since 6.0
+ */
+public class WebSocketTesterResourceTest extends Assert
+{
+	private static final String EXPECTED_TEXT = "expected text";
+	private static final byte[] EXPECTED_BINARY = new byte[] {1, 2, 3};
+	private static final int    EXPECTED_OFFSET = 1;
+	private static final int    EXPECTED_LENGTH = 1;
+
+	private static final AtomicBoolean ON_OUT_TEXT_CALLED = new AtomicBoolean(false);
+	private static final AtomicBoolean ON_OUT_BINARY_CALLED = new AtomicBoolean(false);
+
+	WicketTester tester;
+
+	@Before
+	public void before()
+	{
+		TestWebSocketResource.ON_CONNECT_CALLED.set(false);
+		TestWebSocketResource.ON_CLOSE_CALLED.set(false);
+		ON_OUT_BINARY_CALLED.set(false);
+		ON_OUT_TEXT_CALLED.set(false);
+
+		WebApplication application = new MockApplication()
+		{
+			@Override
+			protected void init()
+			{
+				super.init();
+
+				getSharedResources().add(TestWebSocketResource.TEXT,
+						new TestWebSocketResource(EXPECTED_TEXT));
+
+				getSharedResources().add(TestWebSocketResource.BINARY,
+						new TestWebSocketResource(EXPECTED_BINARY, EXPECTED_OFFSET, EXPECTED_LENGTH));
+			}
+		};
+		tester = new WicketTester(application);
+	}
+
+	@After
+	public void after()
+	{
+		tester.destroy();
+	}
+
+	/**
+	 * A simple test that sends and receives a text message.
+	 * The page asserts that it received the correct message and then
+	 * pushed back the same message but capitalized.
+	 */
+	@Test
+	public void sendTextMessage()
+	{
+		assertFalse(TestWebSocketResource.ON_CONNECT_CALLED.get());
+
+		WebSocketTester webSocketTester = new WebSocketTester(tester, TestWebSocketResource.TEXT)
+		{
+			@Override
+			protected void onOutMessage(String message)
+			{
+				ON_OUT_TEXT_CALLED.set(true);
+				assertEquals(Strings.capitalize(EXPECTED_TEXT), message);
+			}
+		};
+
+		assertTrue(TestWebSocketResource.ON_CONNECT_CALLED.get());
+		assertFalse(ON_OUT_TEXT_CALLED.get());
+
+		webSocketTester.sendMessage(EXPECTED_TEXT);
+		assertTrue(ON_OUT_TEXT_CALLED.get());
+
+		assertFalse(TestWebSocketResource.ON_CLOSE_CALLED.get());
+		webSocketTester.destroy();
+		assertTrue(TestWebSocketResource.ON_CLOSE_CALLED.get());
+	}
+
+	/**
+	 * A simple test that sends and receives a text message.
+	 * The page asserts that it received the correct message and then
+	 * pushed back the same message but capitalized.
+	 */
+	@Test
+	public void sendBinaryMessage()
+	{
+		assertFalse(TestWebSocketResource.ON_CONNECT_CALLED.get());
+
+		WebSocketTester webSocketTester = new WebSocketTester(tester, TestWebSocketResource.BINARY)
+		{
+			@Override
+			protected void onOutMessage(byte[] message, int offset, int length)
+			{
+				ON_OUT_BINARY_CALLED.set(true);
+				Assert.assertArrayEquals(EXPECTED_BINARY, message);
+				Assert.assertEquals(offset, offset);
+				Assert.assertEquals(length, length);
+			}
+		};
+
+		assertTrue(TestWebSocketResource.ON_CONNECT_CALLED.get());
+		assertFalse(ON_OUT_BINARY_CALLED.get());
+
+		webSocketTester.sendMessage(EXPECTED_BINARY, EXPECTED_OFFSET, EXPECTED_LENGTH);
+		assertTrue(ON_OUT_BINARY_CALLED.get());
+
+		assertFalse(TestWebSocketResource.ON_CLOSE_CALLED.get());
+		webSocketTester.destroy();
+		assertTrue(TestWebSocketResource.ON_CLOSE_CALLED.get());
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/ff14a7d0/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterTest.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterTest.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterTest.java
deleted file mode 100644
index cb66c0d..0000000
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * 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.tester;
-
-import java.io.UnsupportedEncodingException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.wicket.event.IEvent;
-import org.apache.wicket.protocol.ws.IWebSocketSettings;
-import org.apache.wicket.protocol.ws.api.WebSocketPushBroadcaster;
-import org.apache.wicket.protocol.ws.api.event.WebSocketPushPayload;
-import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
-import org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;
-import org.apache.wicket.protocol.ws.api.registry.PageIdKey;
-import org.apache.wicket.util.string.Strings;
-import org.apache.wicket.util.tester.WicketTester;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Tests for WebSocketTester.
- *
- * @since 6.0
- */
-public class WebSocketTesterTest extends Assert
-{
-	WicketTester tester;
-
-	@Before
-	public void before()
-	{
-		tester = new WicketTester();
-	}
-
-	@After
-	public void after()
-	{
-		tester.destroy();
-	}
-
-	/**
-	 * A simple test that sends and receives a text message.
-	 * The page asserts that it received the correct message and then
-	 * pushed back the same message but capitalized.
-	 */
-	@Test
-	public void sendTextMessage()
-	{
-		final String expectedMessage = "some message";
-
-		WebSocketTestPage page = new WebSocketTestPage(expectedMessage);
-		tester.startPage(page);
-
-		WebSocketTester webSocketTester = new WebSocketTester(tester, page) {
-			@Override
-			protected void onOutMessage(String message)
-			{
-				assertEquals(Strings.capitalize(expectedMessage), message);
-			}
-		};
-
-		webSocketTester.sendMessage(expectedMessage);
-		webSocketTester.destroy();
-	}
-
-	/**
-	 * A simple test that sends and receives a binary message.
-	 * The page asserts that it received the correct message, offset and lenght and then
-	 * pushes back the same message but capitalized, offset plus 1 and length minus 1.
-	 */
-	@Test
-	public void sendBinaryMessage() throws UnsupportedEncodingException
-	{
-		final byte[] expectedMessage = "some message".getBytes("UTF-8");
-		final int offset = 1;
-		final int length = 2;
-
-		WebSocketTestPage page = new WebSocketTestPage(expectedMessage, offset, length);
-		tester.startPage(page);
-
-		WebSocketTester webSocketTester = new WebSocketTester(tester, page) {
-			@Override
-			protected void onOutMessage(byte[] message, int off, int len)
-			{
-				try
-				{
-					String msg = new String(expectedMessage);
-					byte[] pushedMessage = Strings.capitalize(msg).getBytes("UTF-8");
-
-					assertArrayEquals(pushedMessage, message);
-					assertEquals(offset + 1, off);
-					assertEquals(length - 1, len);
-
-				} catch (UnsupportedEncodingException uex)
-				{
-					throw new RuntimeException(uex);
-				}
-			}
-		};
-
-		webSocketTester.sendMessage(expectedMessage, offset, length);
-		webSocketTester.destroy();
-	}
-
-	@Test
-	public void serverSideBroadcast()
-	{
-		final String message = "Broadcasted Message";
-
-		final AtomicBoolean messageReceived = new AtomicBoolean(false);
-
-		WebSocketTestPage page = new WebSocketTestPage()
-		{
-			@Override
-			public void onEvent(IEvent<?> event)
-			{
-				super.onEvent(event);
-
-				if (event.getPayload() instanceof WebSocketPushPayload)
-				{
-					WebSocketPushPayload payload = (WebSocketPushPayload) event.getPayload();
-
-					if (payload.getMessage() instanceof BroadcastMessage)
-					{
-						BroadcastMessage broadcastMessage = (BroadcastMessage) payload.getMessage();
-						if (message.equals(broadcastMessage.getText()))
-						{
-							messageReceived.set(true);
-						}
-					}
-				}
-			}
-		};
-		tester.startPage(page);
-		tester.getSession().bind();
-
-		new WebSocketTester(tester, page);
-		IWebSocketSettings webSocketSettings = IWebSocketSettings.Holder.get(tester.getApplication());
-		WebSocketPushBroadcaster broadcaster = new WebSocketPushBroadcaster(webSocketSettings.getConnectionRegistry());
-		ConnectedMessage wsMessage = new ConnectedMessage(tester.getApplication(),
-				tester.getHttpSession().getId(), new PageIdKey(page.getPageId()));
-		broadcaster.broadcast(wsMessage, new BroadcastMessage(message));
-
-		assertEquals(true, messageReceived.get());
-	}
-
-	private static class BroadcastMessage implements IWebSocketPushMessage
-	{
-		private final String message;
-
-		private BroadcastMessage(String message)
-		{
-			this.message = message;
-		}
-
-		public String getText()
-		{
-			return message;
-		}
-	}
-}


[3/3] git commit: WICKET-5423 Create IResource based implementation of Native Web Sockets

Posted by mg...@apache.org.
WICKET-5423 Create IResource based implementation of Native Web Sockets


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

Branch: refs/heads/wicket-6.x
Commit: 0c97e75e59b294eda46d0914152248b1a99c2932
Parents: fa88b3b
Author: Martin Tzvetanov Grigorov <mg...@apache.org>
Authored: Thu Nov 21 16:04:54 2013 +0200
Committer: Martin Tzvetanov Grigorov <mg...@apache.org>
Committed: Fri Nov 22 12:51:50 2013 +0200

----------------------------------------------------------------------
 .../java/org/apache/wicket/SharedResources.java |  16 ++-
 .../ws/api/AbstractWebSocketProcessor.java      | 132 +++++++++++++++++--
 .../protocol/ws/api/BaseWebSocketBehavior.java  | 114 ++++++++++++++++
 .../ws/api/IWebSocketConnectionRegistry.java    |  20 +--
 .../api/SimpleWebSocketConnectionRegistry.java  |  36 ++---
 .../protocol/ws/api/WebSocketBehavior.java      |  53 ++------
 .../ws/api/WebSocketPushBroadcaster.java        |   5 +-
 .../protocol/ws/api/WebSocketResource.java      |  85 ++++++++++++
 .../protocol/ws/api/message/ClosedMessage.java  |  11 +-
 .../ws/api/message/ConnectedMessage.java        |  11 +-
 .../wicket/protocol/ws/api/registry/IKey.java   |  24 ++++
 .../protocol/ws/api/registry/PageIdKey.java     |  51 +++++++
 .../ws/api/registry/ResourceNameKey.java        |  51 +++++++
 .../ws/api/res/js/wicket-websocket-jquery.js    |   7 +-
 .../api/res/js/wicket-websocket-setup.js.tmpl   |   5 +-
 .../ws/util/tester/WebSocketTesterTest.java     |   3 +-
 16 files changed, 527 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-core/src/main/java/org/apache/wicket/SharedResources.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/SharedResources.java b/wicket-core/src/main/java/org/apache/wicket/SharedResources.java
index 0173ac9..68fe470 100644
--- a/wicket-core/src/main/java/org/apache/wicket/SharedResources.java
+++ b/wicket-core/src/main/java/org/apache/wicket/SharedResources.java
@@ -22,6 +22,7 @@ import org.apache.wicket.request.resource.IResource;
 import org.apache.wicket.request.resource.ResourceReference;
 import org.apache.wicket.request.resource.ResourceReference.Key;
 import org.apache.wicket.request.resource.ResourceReferenceRegistry;
+import org.apache.wicket.util.lang.Args;
 
 /**
  * Class which holds shared resources. Resources can be shared by name. An optional scope can be
@@ -44,7 +45,7 @@ public class SharedResources
 	 */
 	public SharedResources(ResourceReferenceRegistry registry)
 	{
-		this.registry = registry;
+		this.registry = Args.notNull(registry, "registry");
 	}
 
 	/**
@@ -123,6 +124,19 @@ public class SharedResources
 	}
 
 	/**
+	 * Resolves a {@link ResourceReference} for a shared resource by using
+	 * {@link org.apache.wicket.Application} as a scope and {@code null} for
+	 * locale, style and variation.
+	 *
+	 * @param name
+	 *            Logical name of resource
+	 */
+	public final ResourceReference get(String name)
+	{
+		return get(Application.class, name, null, null, null, false);
+	}
+
+	/**
 	 * Resolves a {@link ResourceReference} for a shared resource.
 	 * 
 	 * @param scope

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/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 3ac7625..2dade93 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
@@ -21,10 +21,13 @@ import java.lang.reflect.Method;
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.wicket.Application;
+import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.Page;
 import org.apache.wicket.Session;
 import org.apache.wicket.ThreadContext;
 import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.markup.IMarkupResourceStreamProvider;
+import org.apache.wicket.markup.html.WebPage;
 import org.apache.wicket.page.IPageManager;
 import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.protocol.http.WicketFilter;
@@ -41,13 +44,23 @@ import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
 import org.apache.wicket.protocol.ws.api.message.IWebSocketMessage;
 import org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;
 import org.apache.wicket.protocol.ws.api.message.TextMessage;
+import org.apache.wicket.protocol.ws.api.registry.IKey;
+import org.apache.wicket.protocol.ws.api.registry.PageIdKey;
+import org.apache.wicket.protocol.ws.api.registry.ResourceNameKey;
 import org.apache.wicket.request.Url;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.request.cycle.RequestCycleContext;
 import org.apache.wicket.request.http.WebRequest;
+import org.apache.wicket.request.resource.IResource;
+import org.apache.wicket.request.resource.ResourceReference;
+import org.apache.wicket.request.resource.SharedResourceReference;
 import org.apache.wicket.session.ISessionStore;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.lang.Checks;
+import org.apache.wicket.util.lang.Classes;
+import org.apache.wicket.util.resource.IResourceStream;
+import org.apache.wicket.util.resource.StringResourceStream;
+import org.apache.wicket.util.string.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,6 +74,11 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 {
 	private static final Logger LOG = LoggerFactory.getLogger(AbstractWebSocketProcessor.class);
 
+	/**
+	 * A pageId indicating that the endpoint is WebSocketResource
+	 */
+	private static final int NO_PAGE_ID = -1;
+
 	private static final Method GET_FILTER_PATH_METHOD;
 	static
 	{
@@ -76,6 +94,7 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 
 	private final WebRequest webRequest;
 	private final int pageId;
+	private final String resourceName;
 	private final Url baseUrl;
 	private final WebApplication application;
 	private final String sessionId;
@@ -94,8 +113,19 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 		this.sessionId = request.getSession(true).getId();
 
 		String pageId = request.getParameter("pageId");
-		Checks.notEmpty(pageId, "Request parameter 'pageId' is required!");
-		this.pageId = Integer.parseInt(pageId, 10);
+		resourceName = request.getParameter("resourceName");
+		if (Strings.isEmpty(pageId) && Strings.isEmpty(resourceName))
+		{
+			throw new IllegalArgumentException("The request should have either 'pageId' or 'resourceName' parameter!");
+		}
+		if (Strings.isEmpty(pageId) == false)
+		{
+			this.pageId = Integer.parseInt(pageId, 10);
+		}
+		else
+		{
+			this.pageId = NO_PAGE_ID;
+		}
 
 		String baseUrl = request.getParameter(WebRequest.PARAM_AJAX_BASE_URL);
 		Checks.notNull(baseUrl, String.format("Request parameter '%s' is required!", WebRequest.PARAM_AJAX_BASE_URL));
@@ -145,15 +175,17 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 	 */
 	protected final void onConnect(final IWebSocketConnection connection)
 	{
-		connectionRegistry.setConnection(getApplication(), getSessionId(), pageId, connection);
-		broadcastMessage(new ConnectedMessage(getApplication(), getSessionId(), pageId));
+		IKey key = getRegistryKey();
+		connectionRegistry.setConnection(getApplication(), getSessionId(), key, connection);
+		broadcastMessage(new ConnectedMessage(getApplication(), getSessionId(), key));
 	}
 
 	@Override
 	public void onClose(int closeCode, String message)
 	{
-		broadcastMessage(new ClosedMessage(getApplication(), getSessionId(), pageId));
-		connectionRegistry.removeConnection(getApplication(), getSessionId(), pageId);
+		IKey key = getRegistryKey();
+		broadcastMessage(new ClosedMessage(getApplication(), getSessionId(), key));
+		connectionRegistry.removeConnection(getApplication(), getSessionId(), key);
 	}
 
 	/**
@@ -170,7 +202,8 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 	 */
 	public final void broadcastMessage(final IWebSocketMessage message)
 	{
-		IWebSocketConnection connection = connectionRegistry.getConnection(application, sessionId, pageId);
+		IKey key = getRegistryKey();
+		IWebSocketConnection connection = connectionRegistry.getConnection(application, sessionId, key);
 
 		if (connection != null && connection.isOpen())
 		{
@@ -213,12 +246,13 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 				IPageManager pageManager = session.getPageManager();
 				try
 				{
-					Page page = (Page) pageManager.getPage(pageId);
+					Page page = getPage(pageManager);
+
 					WebSocketRequestHandler requestHandler = new WebSocketRequestHandler(page, connection);
 
 					WebSocketPayload payload = createEventPayload(message, requestHandler);
 
-					page.send(application, Broadcast.BREADTH, payload);
+					sendPayload(payload, page);
 
 					if (!(message instanceof ConnectedMessage || message instanceof ClosedMessage))
 					{
@@ -254,6 +288,59 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 		}
 	}
 
+	/**
+	 * Sends the payload either to the page (and its WebSocketBehavior)
+	 * or to the WebSocketResource with name {@linkplain #resourceName}
+	 *
+	 * @param payload
+	 *          The payload with the web socket message
+	 * @param page
+	 *          The page that owns the WebSocketBehavior, in case of behavior usage
+	 */
+	private void sendPayload(WebSocketPayload payload, Page page)
+	{
+		if (pageId != NO_PAGE_ID)
+		{
+			page.send(application, Broadcast.BREADTH, payload);
+		}
+		else
+		{
+			ResourceReference reference = new SharedResourceReference(resourceName);
+			IResource resource = reference.getResource();
+			if (resource instanceof WebSocketResource)
+			{
+				WebSocketResource wsResource = (WebSocketResource) resource;
+				wsResource.onPayload(payload);
+			}
+			else
+			{
+				throw new IllegalStateException(
+						String.format("Shared resource with name '%s' is not a %s but %s",
+								resourceName, WebSocketResource.class.getSimpleName(),
+								Classes.name(resource.getClass())));
+			}
+		}
+	}
+
+	/**
+	 * @param pageManager
+	 *      the page manager to use when finding a page by id
+	 * @return the page to use when creating WebSocketRequestHandler
+	 */
+	private Page getPage(IPageManager pageManager)
+	{
+		Page page;
+		if (pageId != -1)
+		{
+			page = (Page) pageManager.getPage(pageId);
+		}
+		else
+		{
+			page = new WebSocketResourcePage();
+		}
+		return page;
+	}
+
 	protected final WebApplication getApplication()
 	{
 		return application;
@@ -293,4 +380,31 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 		}
 		return payload;
 	}
+
+	private IKey getRegistryKey()
+	{
+		IKey key;
+		if (Strings.isEmpty(resourceName))
+		{
+			key = new PageIdKey(pageId);
+		}
+		else
+		{
+			key = new ResourceNameKey(resourceName);
+		}
+		return key;
+	}
+
+	/**
+	 * A dummy page that is used to create a new WebSocketRequestHandler for
+	 * web socket connections to WebSocketResource
+	 */
+	private static class WebSocketResourcePage extends WebPage implements IMarkupResourceStreamProvider
+	{
+		@Override
+		public IResourceStream getMarkupResourceStream(MarkupContainer container, Class<?> containerClass)
+		{
+			return new StringResourceStream("");
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/BaseWebSocketBehavior.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/BaseWebSocketBehavior.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/BaseWebSocketBehavior.java
new file mode 100644
index 0000000..d3999e9
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/BaseWebSocketBehavior.java
@@ -0,0 +1,114 @@
+/*
+ * 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.api;
+
+import java.util.Map;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
+import org.apache.wicket.request.Url;
+import org.apache.wicket.util.lang.Args;
+import org.apache.wicket.util.lang.Generics;
+import org.apache.wicket.util.string.Strings;
+import org.apache.wicket.util.template.PackageTextTemplate;
+
+/**
+ * A behavior that contributes {@link WicketWebSocketJQueryResourceReference}
+ */
+public class BaseWebSocketBehavior extends Behavior
+{
+	private final String resourceName;
+
+	/**
+	 * Constructor.
+	 *
+	 * Contributes WebSocket initialization code that will
+	 * work with {@link org.apache.wicket.protocol.ws.api.WebSocketBehavior}
+	 */
+	protected BaseWebSocketBehavior()
+	{
+		this.resourceName = null;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * Contributes WebSocket initialization code that will
+	 * work with {@link org.apache.wicket.protocol.ws.api.WebSocketResource}
+	 *
+	 * To use WebSocketResource the application have to setup the
+	 * resource as a shared one in its {@link org.apache.wicket.Application#init()}
+	 * method:
+	 * <code><pre>
+	 *     getSharedResources().add(resourceName, new MyWebSocketResource())
+	 * </pre></code>
+	 *
+	 *  @param resourceName
+	 *          the name of the shared {@link org.apache.wicket.protocol.ws.api.WebSocketResource}
+	 */
+	public BaseWebSocketBehavior(String resourceName)
+	{
+		this.resourceName = Args.notEmpty(resourceName, "resourceName");
+	}
+
+	@Override
+	public void renderHead(Component component, IHeaderResponse response)
+	{
+		super.renderHead(component, response);
+
+		response.render(JavaScriptHeaderItem.forReference(WicketWebSocketJQueryResourceReference.get()));
+
+		PackageTextTemplate webSocketSetupTemplate =
+				new PackageTextTemplate(WicketWebSocketJQueryResourceReference.class,
+						"res/js/wicket-websocket-setup.js.tmpl");
+
+		Map<String, Object> variables = Generics.newHashMap();
+
+		// set falsy JS values for the non-used parameter
+		if (Strings.isEmpty(resourceName))
+		{
+			int pageId = component.getPage().getPageId();
+			variables.put("pageId", pageId);
+			variables.put("resourceName", "");
+		}
+		else
+		{
+			variables.put("resourceName", resourceName);
+			variables.put("pageId", 0);
+		}
+
+		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));
+	}
+
+	@Override
+	public boolean getStatelessHint(Component component)
+	{
+		return false;
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/IWebSocketConnectionRegistry.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/IWebSocketConnectionRegistry.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/IWebSocketConnectionRegistry.java
index f2de9ad..8fc47b7 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/IWebSocketConnectionRegistry.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/IWebSocketConnectionRegistry.java
@@ -18,6 +18,7 @@ package org.apache.wicket.protocol.ws.api;
 
 import java.util.Collection;
 import org.apache.wicket.Application;
+import org.apache.wicket.protocol.ws.api.registry.IKey;
 
 /**
  * Tracks all currently connected WebSocket clients
@@ -31,11 +32,12 @@ public interface IWebSocketConnectionRegistry
 	 *      the web application to look in
 	 * @param sessionId
 	 *      the web socket client session id
-	 * @param pageId
-	 *      the web socket client page id
+	 * @param key
+	 *      the web socket client key
 	 * @return the web socket connection used by a client from the specified coordinates
 	 */
-	IWebSocketConnection getConnection(Application application, String sessionId, Integer pageId);
+	IWebSocketConnection getConnection(Application application, String sessionId, IKey key);
+
 
 	/**
 	 * @param application
@@ -51,12 +53,12 @@ public interface IWebSocketConnectionRegistry
 	 *      the web application to look in
 	 * @param sessionId
 	 *      the web socket client session id
-	 * @param pageId
-	 *      the web socket client page id
+	 * @param key
+	 *      the web socket client key
 	 * @param connection
 	 *      the web socket connection to add
 	 */
-	void setConnection(Application application, String sessionId, Integer pageId, IWebSocketConnection connection);
+	void setConnection(Application application, String sessionId, IKey key, IWebSocketConnection connection);
 
 	/**
 	 * Removes a web socket connection from the registry at the specified coordinates (application+session+page)
@@ -65,8 +67,8 @@ public interface IWebSocketConnectionRegistry
 	 *      the web application to look in
 	 * @param sessionId
 	 *      the web socket client session id
-	 * @param pageId
-	 *      the web socket client page id
+	 * @param key
+	 *      the web socket client key
 	 */
-	void removeConnection(Application application, String sessionId, Integer pageId);
+	void removeConnection(Application application, String sessionId, IKey key);
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/SimpleWebSocketConnectionRegistry.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/SimpleWebSocketConnectionRegistry.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/SimpleWebSocketConnectionRegistry.java
index 97c590f..bf8e930 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/SimpleWebSocketConnectionRegistry.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/SimpleWebSocketConnectionRegistry.java
@@ -22,6 +22,7 @@ import java.util.concurrent.ConcurrentMap;
 
 import org.apache.wicket.Application;
 import org.apache.wicket.MetaDataKey;
+import org.apache.wicket.protocol.ws.api.registry.IKey;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.lang.Generics;
 
@@ -35,26 +36,26 @@ import org.apache.wicket.util.lang.Generics;
  */
 public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRegistry
 {
-	private static final MetaDataKey<ConcurrentMap<String, ConcurrentMap<Integer, IWebSocketConnection>>> KEY =
-			new MetaDataKey<ConcurrentMap<String, ConcurrentMap<Integer, IWebSocketConnection>>>()
+	private static final MetaDataKey<ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>>> KEY =
+			new MetaDataKey<ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>>>()
 	{
 	};
 
 	@Override
-	public IWebSocketConnection getConnection(Application application, String sessionId, Integer pageId)
+	public IWebSocketConnection getConnection(Application application, String sessionId, IKey key)
 	{
 		Args.notNull(application, "application");
 		Args.notNull(sessionId, "sessionId");
-		Args.notNull(pageId, "pageId");
+		Args.notNull(key, "key");
 
 		IWebSocketConnection connection = null;
-		ConcurrentMap<String, ConcurrentMap<Integer, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
+		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
 		if (connectionsBySession != null)
 		{
-			ConcurrentMap<Integer, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId);
+			ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId);
 			if (connectionsByPage != null)
 			{
-				connection = connectionsByPage.get(pageId);
+				connection = connectionsByPage.get(key);
 			}
 		}
 		return connection;
@@ -71,12 +72,11 @@ public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRe
 		Args.notNull(application, "application");
 
 		Collection<IWebSocketConnection> connections = new ArrayList<IWebSocketConnection>();
-		ConcurrentMap<String, ConcurrentMap<Integer, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
+		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
 		if (connectionsBySession != null)
 		{
-			for (ConcurrentMap<Integer, IWebSocketConnection> connectionsByPage : connectionsBySession.values())
+			for (ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage : connectionsBySession.values())
 			{
-
 				connections.addAll(connectionsByPage.values());
 			}
 		}
@@ -84,13 +84,13 @@ public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRe
 	}
 
 	@Override
-	public void setConnection(Application application, String sessionId, Integer pageId, IWebSocketConnection connection)
+	public void setConnection(Application application, String sessionId, IKey key, IWebSocketConnection connection)
 	{
 		Args.notNull(application, "application");
 		Args.notNull(sessionId, "sessionId");
-		Args.notNull(pageId, "pageId");
+		Args.notNull(key, "key");
 
-		ConcurrentMap<String, ConcurrentMap<Integer, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
+		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
 		if (connectionsBySession == null)
 		{
 			synchronized (KEY)
@@ -104,7 +104,7 @@ public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRe
 			}
 		}
 
-		ConcurrentMap<Integer, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId);
+		ConcurrentMap<IKey, IWebSocketConnection> connectionsByPage = connectionsBySession.get(sessionId);
 		if (connectionsByPage == null && connection != null)
 		{
 			synchronized (connectionsBySession)
@@ -120,11 +120,11 @@ public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRe
 
 		if (connection != null)
 		{
-			connectionsByPage.put(pageId, connection);
+			connectionsByPage.put(key, connection);
 		}
 		else if (connectionsByPage != null)
 		{
-			connectionsByPage.remove(pageId);
+			connectionsByPage.remove(key);
 			if (connectionsByPage.isEmpty())
 			{
 				connectionsBySession.remove(sessionId);
@@ -133,8 +133,8 @@ public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRe
 	}
 
 	@Override
-	public void removeConnection(Application application, String sessionId, Integer pageId)
+	public void removeConnection(Application application, String sessionId, IKey key)
 	{
-		setConnection(application, sessionId, pageId, null);
+		setConnection(application, sessionId, key, null);
 	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/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 f7f1e5d..d33957b 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
@@ -16,14 +16,8 @@
  */
 package org.apache.wicket.protocol.ws.api;
 
-import java.util.Map;
-
 import org.apache.wicket.Component;
-import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.event.IEvent;
-import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.head.JavaScriptHeaderItem;
-import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
 import org.apache.wicket.protocol.ws.api.event.WebSocketBinaryPayload;
 import org.apache.wicket.protocol.ws.api.event.WebSocketClosedPayload;
 import org.apache.wicket.protocol.ws.api.event.WebSocketConnectedPayload;
@@ -33,22 +27,24 @@ import org.apache.wicket.protocol.ws.api.message.BinaryMessage;
 import org.apache.wicket.protocol.ws.api.message.ClosedMessage;
 import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
 import org.apache.wicket.protocol.ws.api.message.TextMessage;
-import org.apache.wicket.request.Url;
-import org.apache.wicket.util.lang.Generics;
-import org.apache.wicket.util.string.Strings;
-import org.apache.wicket.util.template.PackageTextTemplate;
 
 /**
- * A behavior that contributes {@link WicketWebSocketJQueryResourceReference} and
- * provides optional callbacks for the WebSocket messages (connect, message, close)
+ * A behavior that provides optional callbacks for the WebSocket
+ * messages (connect, message, close)
  *
  * @since 6.0
  */
-public abstract class WebSocketBehavior extends Behavior
+public abstract class WebSocketBehavior extends BaseWebSocketBehavior
 {
+	public WebSocketBehavior()
+	{
+	}
+
 	@Override
 	public void onEvent(Component component, IEvent<?> event)
 	{
+		super.onEvent(component, event);
+
 		Object payload = event.getPayload();
 		if (payload instanceof WebSocketPayload)
 		{
@@ -97,35 +93,4 @@ public abstract class WebSocketBehavior extends Behavior
 	protected void onMessage(WebSocketRequestHandler handler, BinaryMessage binaryMessage)
 	{
 	}
-
-	@Override
-	public void renderHead(Component component, IHeaderResponse response)
-	{
-		super.renderHead(component, response);
-
-		response.render(JavaScriptHeaderItem.forReference(WicketWebSocketJQueryResourceReference.get()));
-
-		PackageTextTemplate webSocketSetupTemplate =
-				new PackageTextTemplate(WicketWebSocketJQueryResourceReference.class, "res/js/wicket-websocket-setup.js.tmpl");
-		Map<String, Object> variables = Generics.newHashMap();
-		int pageId = component.getPage().getPageId();
-		variables.put("pageId", Integer.valueOf(pageId));
-
-		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));
-	}
-
-	@Override
-	public boolean getStatelessHint(Component component)
-	{
-		return false;
-	}
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
index a2a81ef..24e4056 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
@@ -24,6 +24,7 @@ import org.apache.wicket.Application;
 import org.apache.wicket.protocol.ws.IWebSocketSettings;
 import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
 import org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;
+import org.apache.wicket.protocol.ws.api.registry.IKey;
 import org.apache.wicket.protocol.ws.concurrent.Executor;
 import org.apache.wicket.util.lang.Args;
 
@@ -68,8 +69,8 @@ public class WebSocketPushBroadcaster
 
 		Application application = connection.getApplication();
 		String sessionId = connection.getSessionId();
-		Integer pageId = connection.getPageId();
-		IWebSocketConnection wsConnection = registry.getConnection(application, sessionId, pageId);
+		IKey key = connection.getKey();
+		IWebSocketConnection wsConnection = registry.getConnection(application, sessionId, key);
 		if (wsConnection == null)
 		{
 			return;

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketResource.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketResource.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketResource.java
new file mode 100644
index 0000000..d17914c
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketResource.java
@@ -0,0 +1,85 @@
+/*
+ * 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.api;
+
+import org.apache.wicket.protocol.ws.api.event.WebSocketBinaryPayload;
+import org.apache.wicket.protocol.ws.api.event.WebSocketClosedPayload;
+import org.apache.wicket.protocol.ws.api.event.WebSocketConnectedPayload;
+import org.apache.wicket.protocol.ws.api.event.WebSocketPayload;
+import org.apache.wicket.protocol.ws.api.event.WebSocketTextPayload;
+import org.apache.wicket.protocol.ws.api.message.BinaryMessage;
+import org.apache.wicket.protocol.ws.api.message.ClosedMessage;
+import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
+import org.apache.wicket.protocol.ws.api.message.TextMessage;
+import org.apache.wicket.request.resource.IResource;
+
+/**
+ * An IResource that can be used as WebSocket endpoint
+ */
+public abstract class WebSocketResource implements IResource
+{
+	void onPayload(WebSocketPayload<?> payload)
+	{
+		WebSocketRequestHandler webSocketHandler = payload.getHandler();
+
+		if (payload instanceof WebSocketTextPayload)
+		{
+			WebSocketTextPayload textPayload = (WebSocketTextPayload) payload;
+			TextMessage data = textPayload.getMessage();
+			onMessage(webSocketHandler, data);
+		}
+		else if (payload instanceof WebSocketBinaryPayload)
+		{
+			WebSocketBinaryPayload binaryPayload = (WebSocketBinaryPayload) payload;
+			BinaryMessage binaryData = binaryPayload.getMessage();
+			onMessage(webSocketHandler, binaryData);
+		}
+		else if (payload instanceof WebSocketConnectedPayload)
+		{
+			WebSocketConnectedPayload connectedPayload = (WebSocketConnectedPayload) payload;
+			ConnectedMessage message = connectedPayload.getMessage();
+			onConnect(message);
+		}
+		else if (payload instanceof WebSocketClosedPayload)
+		{
+			WebSocketClosedPayload connectedPayload = (WebSocketClosedPayload) payload;
+			ClosedMessage message = connectedPayload.getMessage();
+			onClose(message);
+		}
+	}
+
+	protected void onConnect(ConnectedMessage message)
+	{
+	}
+
+	protected void onClose(ClosedMessage message)
+	{
+	}
+
+	protected void onMessage(WebSocketRequestHandler handler, TextMessage message)
+	{
+	}
+
+	protected void onMessage(WebSocketRequestHandler handler, BinaryMessage binaryMessage)
+	{
+	}
+
+	@Override
+	public final void respond(Attributes attributes)
+	{
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ClosedMessage.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ClosedMessage.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ClosedMessage.java
index 9b2abc4..43046c0 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ClosedMessage.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ClosedMessage.java
@@ -17,6 +17,7 @@
 package org.apache.wicket.protocol.ws.api.message;
 
 import org.apache.wicket.Application;
+import org.apache.wicket.protocol.ws.api.registry.IKey;
 import org.apache.wicket.util.lang.Args;
 
 /**
@@ -29,13 +30,13 @@ public class ClosedMessage implements IWebSocketMessage
 {
 	private final Application application;
 	private final String sessionId;
-	private final Integer pageId;
+	private final IKey key;
 
-	public ClosedMessage(Application application, String sessionId, Integer pageId)
+	public ClosedMessage(Application application, String sessionId, IKey key)
 	{
 		this.application = Args.notNull(application, "application");
 		this.sessionId = Args.notNull(sessionId, "sessionId");
-		this.pageId = Args.notNull(pageId, "pageId");
+		this.key = Args.notNull(key, "key");
 	}
 
 	public Application getApplication()
@@ -48,9 +49,9 @@ public class ClosedMessage implements IWebSocketMessage
 		return sessionId;
 	}
 
-	public Integer getPageId()
+	public IKey getKey()
 	{
-		return pageId;
+		return key;
 	}
 
 	@Override

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ConnectedMessage.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ConnectedMessage.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ConnectedMessage.java
index 17a142e..ab085ce 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ConnectedMessage.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/message/ConnectedMessage.java
@@ -17,6 +17,7 @@
 package org.apache.wicket.protocol.ws.api.message;
 
 import org.apache.wicket.Application;
+import org.apache.wicket.protocol.ws.api.registry.IKey;
 import org.apache.wicket.util.lang.Args;
 
 /**
@@ -29,13 +30,13 @@ public class ConnectedMessage implements IWebSocketMessage
 {
 	private final Application application;
 	private final String sessionId;
-	private final Integer pageId;
+	private final IKey key;
 
-	public ConnectedMessage(Application application, String sessionId, Integer pageId)
+	public ConnectedMessage(Application application, String sessionId, IKey key)
 	{
 		this.application = Args.notNull(application, "application");
 		this.sessionId = Args.notNull(sessionId, "sessionId");
-		this.pageId = Args.notNull(pageId, "pageId");
+		this.key = Args.notNull(key, "key");
 	}
 
 	public Application getApplication()
@@ -48,9 +49,9 @@ public class ConnectedMessage implements IWebSocketMessage
 		return sessionId;
 	}
 
-	public Integer getPageId()
+	public IKey getKey()
 	{
-		return pageId;
+		return key;
 	}
 
 	@Override

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
new file mode 100644
index 0000000..cecda06
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
@@ -0,0 +1,24 @@
+/*
+ * 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.api.registry;
+
+/**
+ * A marker interface for keys that are used to find a web socket
+ * connection in {@link org.apache.wicket.protocol.ws.api.IWebSocketConnectionRegistry}
+ */
+public interface IKey
+{}

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java
new file mode 100644
index 0000000..84eee23
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java
@@ -0,0 +1,51 @@
+/*
+ * 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.api.registry;
+
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * A key based on page's id
+ */
+public class PageIdKey implements IKey
+{
+	private final Integer pageId;
+
+	public PageIdKey(Integer pageId)
+	{
+		this.pageId = Args.notNull(pageId, "pageId");
+	}
+
+	@Override
+	public boolean equals(Object o)
+	{
+		if (this == o) return true;
+		if (o == null || getClass() != o.getClass()) return false;
+
+		PageIdKey pageIdKey = (PageIdKey) o;
+
+		if (!pageId.equals(pageIdKey.pageId)) return false;
+
+		return true;
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return pageId.hashCode();
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameKey.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameKey.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameKey.java
new file mode 100644
index 0000000..4f45aed
--- /dev/null
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameKey.java
@@ -0,0 +1,51 @@
+/*
+ * 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.api.registry;
+
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * A key based on shared resource's name
+ */
+public class ResourceNameKey implements IKey
+{
+	private final String resourceName;
+
+	public ResourceNameKey(String resourceName)
+	{
+		this.resourceName = Args.notNull(resourceName, "resourceName");
+	}
+
+	@Override
+	public boolean equals(Object o)
+	{
+		if (this == o) return true;
+		if (o == null || getClass() != o.getClass()) return false;
+
+		ResourceNameKey that = (ResourceNameKey) o;
+
+		if (!resourceName.equals(that.resourceName)) return false;
+
+		return true;
+	}
+
+	@Override
+	public int hashCode()
+	{
+		return resourceName.hashCode();
+	}
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/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 7423c47..e879663 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
@@ -46,7 +46,12 @@
 
 				url = protocol + '//' + document.location.host + Wicket.WebSocket.contextPath + '/wicket/websocket';
 
-				url += '?pageId=' + Wicket.WebSocket.pageId;
+				if (Wicket.WebSocket.pageId) {
+					url += '?pageId=' + Wicket.WebSocket.pageId;
+				} else if (Wicket.WebSocket.resourceName) {
+					url += '?resourceName=' + Wicket.WebSocket.resourceName;
+				}
+
 				url += '&wicket-ajax-baseurl=' + Wicket.WebSocket.baseUrl;
 				self.ws = new WebSocket(url);
 

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/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 6d2f8a3..fe81fdc 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
@@ -1,8 +1,9 @@
 ;(function(undefined) {
 	'use strict';
 
-	if (!Wicket.WebSocket.pageId) {
-		jQuery.extend(Wicket.WebSocket, { pageId: ${pageId}, baseUrl: '${baseUrl}', contextPath: '${contextPath}' });
+	if (!Wicket.WebSocket.key) {
+		jQuery.extend(Wicket.WebSocket, { pageId: ${pageId}, resourceName: '${resourceName}',
+			baseUrl: '${baseUrl}', contextPath: '${contextPath}' });
 		Wicket.WebSocket.createDefaultConnection();
 	}
 })();

http://git-wip-us.apache.org/repos/asf/wicket/blob/0c97e75e/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterTest.java
----------------------------------------------------------------------
diff --git a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterTest.java b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterTest.java
index 995bd9d..cb66c0d 100644
--- a/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterTest.java
+++ b/wicket-experimental/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterTest.java
@@ -25,6 +25,7 @@ import org.apache.wicket.protocol.ws.api.WebSocketPushBroadcaster;
 import org.apache.wicket.protocol.ws.api.event.WebSocketPushPayload;
 import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
 import org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;
+import org.apache.wicket.protocol.ws.api.registry.PageIdKey;
 import org.apache.wicket.util.string.Strings;
 import org.apache.wicket.util.tester.WicketTester;
 import org.junit.After;
@@ -153,7 +154,7 @@ public class WebSocketTesterTest extends Assert
 		IWebSocketSettings webSocketSettings = IWebSocketSettings.Holder.get(tester.getApplication());
 		WebSocketPushBroadcaster broadcaster = new WebSocketPushBroadcaster(webSocketSettings.getConnectionRegistry());
 		ConnectedMessage wsMessage = new ConnectedMessage(tester.getApplication(),
-				tester.getHttpSession().getId(), page.getPageId());
+				tester.getHttpSession().getId(), new PageIdKey(page.getPageId()));
 		broadcaster.broadcast(wsMessage, new BroadcastMessage(message));
 
 		assertEquals(true, messageReceived.get());