You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by re...@apache.org on 2021/11/07 08:38:57 UTC

[wicket] branch WICKET-6930-websocket-improvements created (now c48a23a)

This is an automated email from the ASF dual-hosted git repository.

reiern70 pushed a change to branch WICKET-6930-websocket-improvements
in repository https://gitbox.apache.org/repos/asf/wicket.git.


      at c48a23a  WICKET-6930: pass page class as a kind of context

This branch includes the following new commits:

     new 7a4e4b2  introduce isEmpty() for partial update
     new c48a23a  WICKET-6930: pass page class as a kind of context

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[wicket] 01/02: introduce isEmpty() for partial update

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

reiern70 pushed a commit to branch WICKET-6930-websocket-improvements
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit 7a4e4b204ab0f9c95c89b87e35152ab5a47276d5
Author: ernestosemedy <ba...@semedy.com>
AuthorDate: Sat Nov 6 10:41:57 2021 +0300

    introduce isEmpty() for partial update
---
 .../java/org/apache/wicket/page/PartialPageUpdate.java     |  8 ++++++++
 .../wicket/protocol/ws/api/AbstractWebSocketProcessor.java |  6 +++---
 .../wicket/protocol/ws/api/WebSocketRequestHandler.java    | 14 ++++++++++++--
 .../apache/wicket/protocol/ws/javax/WicketEndpoint.java    |  1 -
 4 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/wicket-core/src/main/java/org/apache/wicket/page/PartialPageUpdate.java b/wicket-core/src/main/java/org/apache/wicket/page/PartialPageUpdate.java
index f95c959..f5cef02 100644
--- a/wicket-core/src/main/java/org/apache/wicket/page/PartialPageUpdate.java
+++ b/wicket-core/src/main/java/org/apache/wicket/page/PartialPageUpdate.java
@@ -150,6 +150,14 @@ public abstract class PartialPageUpdate
 	}
 
 	/**
+	 * @return returns true if and only if nothing has being added to partial update.
+	 */
+	public boolean isEmpty()
+	{
+		return prependJavaScripts.isEmpty() && appendJavaScripts.isEmpty() && domReadyJavaScripts.isEmpty() && markupIdToComponent.isEmpty();
+	}
+
+	/**
 	 * Serializes this object to the response.
 	 *
 	 * @param response
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
index f891751..82cd21a 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
@@ -261,7 +261,7 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 				{
 					WebSocketRequestHandler requestHandler = webSocketSettings.newWebSocketRequestHandler(page, connection);
 
-					WebSocketPayload payload = createEventPayload(message, requestHandler);
+					WebSocketPayload<?> payload = createEventPayload(message, requestHandler);
 
 					if (!(message instanceof ConnectedMessage || isSpecialMessage(message))) {
 						requestCycle.scheduleRequestHandlerAfterCurrent(requestHandler);
@@ -356,9 +356,9 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 		return sessionId;
 	}
 
-	private WebSocketPayload createEventPayload(IWebSocketMessage message, WebSocketRequestHandler handler)
+	private WebSocketPayload<?> createEventPayload(IWebSocketMessage message, WebSocketRequestHandler handler)
 	{
-		final WebSocketPayload payload;
+		final WebSocketPayload<?> payload;
 		if (message instanceof TextMessage)
 		{
 			payload = new WebSocketTextPayload((TextMessage) message, handler);
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketRequestHandler.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketRequestHandler.java
index 7df3735..70a2603 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketRequestHandler.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketRequestHandler.java
@@ -97,7 +97,13 @@ public class WebSocketRequestHandler extends AbstractPartialPageRequestHandler i
 		}
 	}
 
-
+	/**
+	 * @return if true then EMPTY partial updates will be ignored.
+	 */
+	protected boolean pushOnEmptyUpdate()
+	{
+		return true;
+	}
 
 	protected PartialPageUpdate getUpdate() {
 		if (update == null) {
@@ -129,7 +135,11 @@ public class WebSocketRequestHandler extends AbstractPartialPageRequestHandler i
 	{
 		if (update != null)
 		{
-			update.writeTo(requestCycle.getResponse(), "UTF-8");
+			// if the update is not empty or empty updates will be pushed anyway then write to response.
+			if (pushOnEmptyUpdate() || !update.isEmpty())
+			{
+				update.writeTo(requestCycle.getResponse(), "UTF-8");
+			}
 		}
 	}
 
diff --git a/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java b/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
index 0636831..4808dbd 100644
--- a/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
+++ b/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
@@ -123,7 +123,6 @@ public class WicketEndpoint extends Endpoint
 	{
 		String appName = null;
 
-		@SuppressWarnings("unchecked")
 		Map<String, List<String>> parameters = session.getRequestParameterMap();
 		if (parameters != null)
 		{

[wicket] 02/02: WICKET-6930: pass page class as a kind of context

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

reiern70 pushed a commit to branch WICKET-6930-websocket-improvements
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit c48a23a903426eb329b45a690a464fde751b1405
Author: reiern70 <re...@gmail.com>
AuthorDate: Sun Nov 7 11:38:39 2021 +0300

    WICKET-6930: pass page class as a kind of context
---
 .../examples/websocket/JSR356Application.java      | 11 +++-
 .../wicket/examples/websocket/JSR356Session.java   | 51 +++++++++++++++++
 .../WebSocketPushUpdateProgressDemoPage.java       |  3 +-
 .../websocket/progress/ProgressBarTogglePanel.java | 36 ++++--------
 .../websocket/progress/ProgressUpdater.java        | 36 ++++++------
 .../ws/api/AbstractWebSocketConnection.java        |  2 +-
 .../ws/api/AbstractWebSocketProcessor.java         | 25 +++++---
 .../protocol/ws/api/BaseWebSocketBehavior.java     |  2 +
 .../protocol/ws/api/WebSocketPushBroadcaster.java  | 66 ++++++++++++++++++++++
 .../api/registry/IWebSocketConnectionRegistry.java | 25 +++++++-
 .../wicket/protocol/ws/api/registry/PageIdKey.java | 24 ++++++++
 .../SimpleWebSocketConnectionRegistry.java         | 26 +++++++++
 .../ws/api/res/js/wicket-websocket-jquery.js       |  1 +
 .../ws/api/res/js/wicket-websocket-setup.js.tmpl   |  2 +-
 .../ws/util/tester/TestWebSocketProcessor.java     |  1 +
 .../util/tester/WebSocketTesterBehaviorTest.java   |  2 +-
 .../ws/javax/JavaxWebSocketConnection.java         |  2 +-
 .../wicket/protocol/ws/javax/WicketEndpoint.java   |  2 +
 18 files changed, 259 insertions(+), 58 deletions(-)

diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Application.java b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Application.java
index 98a9779..e178f7c 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Application.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Application.java
@@ -16,12 +16,15 @@
  */
 package org.apache.wicket.examples.websocket;
 
+import org.apache.wicket.Session;
 import org.apache.wicket.examples.WicketExampleApplication;
 import org.apache.wicket.examples.websocket.charts.ChartWebSocketResource;
 import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.protocol.https.HttpsConfig;
 import org.apache.wicket.protocol.https.HttpsMapper;
 import org.apache.wicket.protocol.ws.WebSocketSettings;
+import org.apache.wicket.request.Request;
+import org.apache.wicket.request.Response;
 
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
@@ -70,7 +73,13 @@ public class JSR356Application extends WicketExampleApplication
 		getCspSettings().blocking().disabled();
 	}
 
-    @Override
+	@Override
+	public Session newSession(Request request, Response response)
+	{
+		return new JSR356Session(request);
+	}
+
+	@Override
     protected void onDestroy() {
         scheduledExecutorService.shutdownNow();
 
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Session.java b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Session.java
new file mode 100644
index 0000000..e45ecde
--- /dev/null
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Session.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.examples.websocket;
+
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.apache.wicket.examples.websocket.progress.ProgressUpdater;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.request.Request;
+
+public class JSR356Session extends WebSession {
+
+
+    private ProgressUpdater.ProgressUpdateTask progressUpdateTask;
+
+    public JSR356Session(Request request) {
+        super(request);
+    }
+
+    public ProgressUpdater.ProgressUpdateTask getProgressUpdateTask() {
+        return progressUpdateTask;
+    }
+
+    public synchronized void startTask() {
+        if (progressUpdateTask != null && progressUpdateTask.isRunning()) {
+            return;
+        }
+        ScheduledExecutorService service = JSR356Application.get().getScheduledExecutorService();
+        progressUpdateTask = ProgressUpdater.start(getApplication(), getId(), service);
+    }
+
+    public static JSR356Session getInstance() {
+        return (JSR356Session)get();
+    }
+}
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.java b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.java
index 01d16b2..bbf923d 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.java
@@ -18,10 +18,11 @@ package org.apache.wicket.examples.websocket;
 
 import org.apache.wicket.examples.WicketExamplePage;
 import org.apache.wicket.examples.websocket.progress.ProgressBarTogglePanel;
+import org.apache.wicket.examples.websocket.progress.ProgressUpdater;
 import org.apache.wicket.protocol.https.RequireHttps;
 
 @RequireHttps
-public class WebSocketPushUpdateProgressDemoPage extends WicketExamplePage
+public class WebSocketPushUpdateProgressDemoPage extends WicketExamplePage implements ProgressUpdater.ITaskProgressListener
 {
 	public WebSocketPushUpdateProgressDemoPage()
 	{
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.java b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.java
index 03e7733..71e389c 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.java
@@ -22,6 +22,7 @@ import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.markup.html.AjaxLink;
 import org.apache.wicket.event.IEvent;
 import org.apache.wicket.examples.websocket.JSR356Application;
+import org.apache.wicket.examples.websocket.JSR356Session;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
@@ -34,7 +35,7 @@ public class ProgressBarTogglePanel extends Panel
 
     private int progress = 0;
     private boolean showProgress = true;
-    private ProgressUpdater.ProgressUpdateTask progressUpdateTask;
+
 
     public ProgressBarTogglePanel(String id)
     {
@@ -46,7 +47,7 @@ public class ProgressBarTogglePanel extends Panel
         {
             @Override
             protected void onConnect(ConnectedMessage message) {
-                progressUpdateTask = ProgressBarTogglePanel.startProgressTask(message);
+
             }
         });
 
@@ -65,33 +66,25 @@ public class ProgressBarTogglePanel extends Panel
             @Override
             public void onClick(AjaxRequestTarget target)
             {
-                if (progressUpdateTask.isRunning() && !progressUpdateTask.isCanceled())
+                ProgressUpdater.ProgressUpdateTask progressUpdateTask = JSR356Session.getInstance().getProgressUpdateTask();
+                if (progressUpdateTask != null && progressUpdateTask.isRunning() && !progressUpdateTask.isCanceled())
                 {
                     progressUpdateTask.cancel();
                 }
                 else
                 {
-                    ScheduledExecutorService service = JSR356Application.get().getScheduledExecutorService();
-                    ProgressUpdater.restart(progressUpdateTask, service);
+                    JSR356Session.getInstance().startTask();
                 }
                 target.add(ProgressBarTogglePanel.this);
             }
-        }.setBody(new IModel<String>()
-        {
-            @Override
-            public String getObject()
-            {
-                return progressUpdateTask != null && progressUpdateTask.isRunning() && !progressUpdateTask.isCanceled() ? "Cancel task" : "Restart task";
-            }
+        }.setBody((IModel<String>) () -> {
+            ProgressUpdater.ProgressUpdateTask progressUpdateTask = JSR356Session.getInstance().getProgressUpdateTask();
+            return progressUpdateTask != null && progressUpdateTask.isRunning() && !progressUpdateTask.isCanceled() ? "Cancel task" : "Restart task";
         }));
 
-        add(new Label("progressBar", new IModel<String>()
-        {
-            @Override
-            public String getObject()
-            {
-                return progressUpdateTask != null && progressUpdateTask.isRunning() ? "Background Task is " + progress + "% completed" : "No task is running";
-            }
+        add(new Label("progressBar", (IModel<String>) () -> {
+            ProgressUpdater.ProgressUpdateTask progressUpdateTask = JSR356Session.getInstance().getProgressUpdateTask();
+            return progressUpdateTask != null && progressUpdateTask.isRunning() ? "Background Task is " + progress + "% completed" : "No task is running";
         })
         {
             @Override
@@ -103,11 +96,6 @@ public class ProgressBarTogglePanel extends Panel
         });
     }
 
-    public static ProgressUpdater.ProgressUpdateTask startProgressTask(ConnectedMessage message)
-    {
-        ScheduledExecutorService service = JSR356Application.get().getScheduledExecutorService();
-        return ProgressUpdater.start(message, service);
-    }
 
     @Override
     public void onEvent(IEvent<?> event)
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressUpdater.java b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressUpdater.java
index 60a3e94..aa928cb 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressUpdater.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressUpdater.java
@@ -28,6 +28,7 @@ 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.api.registry.PageIdKey;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,20 +37,23 @@ import org.slf4j.LoggerFactory;
  */
 public class ProgressUpdater
 {
+	/**
+	 * Marks a page as listening to task progress.
+	 */
+	public interface ITaskProgressListener {
+
+	}
+
 	private static final Logger LOGGER = LoggerFactory.getLogger(ProgressUpdater.class);
 
-	public static ProgressUpdateTask start(ConnectedMessage message, ScheduledExecutorService scheduledExecutorService)
+	public static ProgressUpdateTask start(Application application, String session, ScheduledExecutorService scheduledExecutorService)
 	{
 		// create an asynchronous task that will write the data to the client
-		ProgressUpdateTask progressUpdateTask = new ProgressUpdateTask(message.getApplication(), message.getSessionId(), message.getKey());
+		ProgressUpdateTask progressUpdateTask = new ProgressUpdateTask(application, session);
 		scheduledExecutorService.schedule(progressUpdateTask, 1, TimeUnit.SECONDS);
 		return progressUpdateTask;
 	}
 
-	public static void restart(ProgressUpdateTask progressUpdateTask, ScheduledExecutorService scheduledExecutorService) {
-		scheduledExecutorService.schedule(progressUpdateTask, 1, TimeUnit.SECONDS);
-	}
-
 	/**
 	 * A push message used to update progress.
 	 */
@@ -80,16 +84,14 @@ public class ProgressUpdater
 		 */
 		private final String applicationName;
 		private final String sessionId;
-		private final IKey key;
 
 		private boolean canceled = false;
 		private boolean running = false;
 
-		private ProgressUpdateTask(Application application, String sessionId, IKey key)
+		private ProgressUpdateTask(Application application, String sessionId)
 		{
 			this.applicationName = application.getName();
 			this.sessionId = sessionId;
-			this.key = key;
 		}
 
 		@Override
@@ -98,22 +100,13 @@ public class ProgressUpdater
 			running = true;
 			Application application = Application.get(applicationName);
 			WebSocketSettings webSocketSettings = WebSocketSettings.Holder.get(application);
-			IWebSocketConnectionRegistry webSocketConnectionRegistry = webSocketSettings.getConnectionRegistry();
 
 			int progress = 0;
 
 			while (progress <= 100)
 			{
-				IWebSocketConnection connection = webSocketConnectionRegistry.getConnection(application, sessionId, key);
 				try
 				{
-					if (connection == null || !connection.isOpen())
-					{
-						running = false;
-						// stop if the web socket connection is closed
-						return;
-					}
-
 					if (canceled)
 					{
 						canceled = false;
@@ -123,7 +116,12 @@ public class ProgressUpdater
 
 					WebSocketPushBroadcaster broadcaster =
 							new WebSocketPushBroadcaster(webSocketSettings.getConnectionRegistry());
-					broadcaster.broadcast(new ConnectedMessage(application, sessionId, key), new ProgressUpdate(progress));
+					broadcaster.broadcastAllMatchingFilter(application,  new IWebSocketConnectionRegistry.IConnectionsFilter() {
+						@Override
+						public boolean acceptConnection(String sessionId, IKey key) {
+							return ProgressUpdateTask.this.sessionId.equals(sessionId) && key instanceof PageIdKey && ITaskProgressListener.class.isAssignableFrom(((PageIdKey) key).getPageClass());
+						}
+					}, new ProgressUpdate(progress));
 
 					// sleep for a while to simulate work
 					TimeUnit.SECONDS.sleep(1);
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketConnection.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketConnection.java
index 8726d56..3cd0f62 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketConnection.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketConnection.java
@@ -50,7 +50,7 @@ public abstract class AbstractWebSocketConnection implements IWebSocketConnectio
 	@Override
 	public void sendMessage(IWebSocketPushMessage message)
 	{
-		webSocketProcessor.broadcastMessage(message);
+		webSocketProcessor.broadcastMessage(message, this);
 	}
 
 	@Override
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
index 82cd21a..d6d35b0 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/AbstractWebSocketProcessor.java
@@ -81,9 +81,11 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 	 * A pageId indicating that the endpoint is WebSocketResource
 	 */
 	static final int NO_PAGE_ID = -1;
+	static final String NO_PAGE_CLASS = "_NO_PAGE";
 
 	private final WebRequest webRequest;
 	private final int pageId;
+	private final String pageClass;
 	private final String resourceName;
 	private final String connectionToken;
 	private final Url baseUrl;
@@ -112,6 +114,7 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 		}
 		this.sessionId = httpSession.getId();
 		String pageId = request.getParameter("pageId");
+		String pageClass = request.getParameter("pageClass");
 		this.resourceName = request.getParameter("resourceName");
 		this.connectionToken = request.getParameter("connectionToken");
 		if (Strings.isEmpty(pageId) && Strings.isEmpty(resourceName))
@@ -121,10 +124,12 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 		if (Strings.isEmpty(pageId) == false)
 		{
 			this.pageId = Integer.parseInt(pageId, 10);
+			this.pageClass = pageClass;
 		}
 		else
 		{
 			this.pageId = NO_PAGE_ID;
+			this.pageClass = NO_PAGE_CLASS;
 		}
 
 		String baseUrl = request.getParameter(WebRequest.PARAM_AJAX_BASE_URL);
@@ -181,7 +186,7 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 			}
 		}
 
-		broadcastMessage(new ConnectedMessage(getApplication(), getSessionId(), key));
+		broadcastMessage(new ConnectedMessage(getApplication(), getSessionId(), key), connection);
 	}
 
 	@Override
@@ -203,6 +208,13 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 		}
 	}
 
+	public final void broadcastMessage(final IWebSocketMessage message)
+	{
+		IKey key = getRegistryKey();
+		IWebSocketConnection connection = connectionRegistry.getConnection(application, sessionId, key);
+		broadcastMessage(message, connection);
+	}
+
 	/**
 	 * Exports the Wicket thread locals and broadcasts the received message from the client to all
 	 * interested components and behaviors in the page with id {@code #pageId}
@@ -215,11 +227,8 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 	 * @param message
 	 *      the message to broadcast
 	 */
-	public final void broadcastMessage(final IWebSocketMessage message)
+	public final void broadcastMessage(final IWebSocketMessage message, IWebSocketConnection connection)
 	{
-		IKey key = getRegistryKey();
-		IWebSocketConnection connection = connectionRegistry.getConnection(application, sessionId, key);
-
 		if (connection != null && (connection.isOpen() || isSpecialMessage(message)))
 		{
 			Application oldApplication = ThreadContext.getApplication();
@@ -249,8 +258,8 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 
 				if (session == null)
 				{
-					connectionRegistry.removeConnection(application, sessionId, key);
-					LOG.debug("No Session could be found for session id '{}' and key '{}'!", sessionId, key);
+					connectionRegistry.removeConnection(application, sessionId, connection.getKey());
+					LOG.debug("No Session could be found for session id '{}' and key '{}'!", sessionId, connection.getKey());
 					return;
 				}
 
@@ -399,7 +408,7 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
 		IKey key;
 		if (Strings.isEmpty(resourceName))
 		{
-			key = new PageIdKey(pageId);
+			key = new PageIdKey(pageId, pageClass);
 		}
 		else
 		{
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/BaseWebSocketBehavior.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/BaseWebSocketBehavior.java
index c0a1f18..7ff8d80 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/BaseWebSocketBehavior.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/BaseWebSocketBehavior.java
@@ -128,6 +128,7 @@ public class BaseWebSocketBehavior extends Behavior
 		{
 			int pageId = component.getPage().getPageId();
 			variables.put("pageId", pageId);
+			variables.put("pageClass", component.getPage().getClass().getName());
 			variables.put("resourceName", "");
 			variables.put("connectionToken", "");
 		}
@@ -136,6 +137,7 @@ public class BaseWebSocketBehavior extends Behavior
 			variables.put("resourceName", resourceName);
 			variables.put("connectionToken", connectionToken);
 			variables.put("pageId", false);
+			variables.put("pageClass", "");
 		}
 
 		WebSocketSettings webSocketSettings = WebSocketSettings.Holder.get(component.getApplication());
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
index db653d2..fc37a7f 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
@@ -109,6 +109,72 @@ public class WebSocketPushBroadcaster
 		process(application, wsConnections, message);
 	}
 
+	/**
+	 * Processes the given message in all pages in a given session that have active Web Socket connections.
+	 * The message is sent as an event to the Page and components of the session allowing the components
+	 * to be updated.
+	 *
+	 * This method can be invoked from any thread, even a non-wicket thread. By default all processing
+	 * is done in the caller thread. Use
+	 * {@link WebSocketSettings#setWebSocketPushMessageExecutor(org.apache.wicket.protocol.ws.concurrent.Executor)}
+	 * to move processing to background threads.
+	 *
+	 * If some connections are not in valid state they are silently ignored.
+	 *
+	 * @param application
+	 *			The wicket application
+	 *
+	 * @param sessionId
+	 *         The session ID
+	 * @param message
+	 *			The push message event
+	 */
+	public void broadcastAllInSession(Application application, String sessionId, IWebSocketPushMessage message)
+	{
+		Args.notNull(application, "application");
+		Args.notNull(message, "message");
+
+		Collection<IWebSocketConnection> wsConnections = registry.getConnections(application, sessionId);
+		if (wsConnections == null)
+		{
+			return;
+		}
+		process(application, wsConnections, message);
+	}
+
+	/**
+	 * Processes the given message in all pages in a given session that have active Web Socket connections and match
+	 * the given filter. The message is sent as an event to the Page and components of the session allowing the components
+	 * to be updated.
+	 *
+	 * This method can be invoked from any thread, even a non-wicket thread. By default all processing
+	 * is done in the caller thread. Use
+	 * {@link WebSocketSettings#setWebSocketPushMessageExecutor(org.apache.wicket.protocol.ws.concurrent.Executor)}
+	 * to move processing to background threads.
+	 *
+	 * If some connections are not in valid state they are silently ignored.
+	 *
+	 * @param application
+	 *			The wicket application
+	 *
+	 * @param connectionsFilter
+	 *         the {@link org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry.IConnectionsFilter}
+	 * @param message
+	 *			The push message event
+	 */
+	public void broadcastAllMatchingFilter(Application application, IWebSocketConnectionRegistry.IConnectionsFilter connectionsFilter, IWebSocketPushMessage message)
+	{
+		Args.notNull(application, "application");
+		Args.notNull(message, "message");
+
+		Collection<IWebSocketConnection> wsConnections = registry.getConnections(application, connectionsFilter);
+		if (wsConnections == null)
+		{
+			return;
+		}
+		process(application, wsConnections, message);
+	}
+
 	private void process(final Application application, final Collection<IWebSocketConnection> wsConnections,
 	                     final IWebSocketPushMessage message)
 	{
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java
index 2782a93..c4de9a5 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java
@@ -29,6 +29,17 @@ import org.apache.wicket.protocol.ws.api.IWebSocketConnection;
 public interface IWebSocketConnectionRegistry
 {
 	/**
+	 * Interface allowing to filter web-sockets connection. This could be used for use cases like the
+	 * following: you
+	 */
+	interface IConnectionsFilter
+	{
+
+		boolean acceptConnection(String sessionId, IKey key);
+
+	}
+
+	/**
 	 * @param application
 	 *      the web application to look in
 	 * @param sessionId
@@ -44,12 +55,24 @@ public interface IWebSocketConnectionRegistry
 	 *            the web application to look in
 	 * @param sessionId
 	 *            the http session id
-	 * @return collection of web socket connection used by a client with the given session id
+	 * @return collection of web socket connections used by a client with the given session id
 	 */
 	Collection<IWebSocketConnection> getConnections(Application application, String sessionId);
 
 
 	/**
+	 *
+	 * @param application
+	 * 			 the web application to look in
+	 * @param connectionsFilter
+	 * 			the {@link org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry.IConnectionsFilter}
+	 *
+	 * @return collection of web socket connections that match certain filter
+	 */
+	Collection<IWebSocketConnection> getConnections(Application application, IConnectionsFilter connectionsFilter);
+
+
+	/**
 	 * @param application
 	 *            the web application to look in
 	 * @return collection of web socket connection used by any client connected to specified application
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java
index 84eee23..ba50ed2 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java
@@ -16,6 +16,9 @@
  */
 package org.apache.wicket.protocol.ws.api.registry;
 
+import org.apache.wicket.Session;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.page.IManageablePage;
 import org.apache.wicket.util.lang.Args;
 
 /**
@@ -25,9 +28,30 @@ public class PageIdKey implements IKey
 {
 	private final Integer pageId;
 
+	private Class<? extends IManageablePage> pageClass;
+
 	public PageIdKey(Integer pageId)
 	{
+		this(pageId, null);
+	}
+
+	public PageIdKey(Integer pageId, String pageClass)
+	{
 		this.pageId = Args.notNull(pageId, "pageId");
+		Args.notNull(pageClass, "pageClass");
+		try {
+			this.pageClass = (Class<IManageablePage>)Thread.currentThread().getContextClassLoader().loadClass(pageClass);
+		} catch (ClassNotFoundException e) {
+			//throw new WicketRuntimeException(e);
+		}
+	}
+
+	/**
+	 * @return returns the page class.
+	 */
+	public Class<? extends IManageablePage> getPageClass()
+	{
+		return pageClass;
 	}
 
 	@Override
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/SimpleWebSocketConnectionRegistry.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/SimpleWebSocketConnectionRegistry.java
index b5005aa..e176a15 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/SimpleWebSocketConnectionRegistry.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/SimpleWebSocketConnectionRegistry.java
@@ -19,6 +19,7 @@ package org.apache.wicket.protocol.ws.api.registry;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Map;
 import java.util.concurrent.ConcurrentMap;
 
 import org.apache.wicket.Application;
@@ -79,6 +80,31 @@ public class SimpleWebSocketConnectionRegistry implements IWebSocketConnectionRe
 		return connections;
 	}
 
+	@Override
+	public Collection<IWebSocketConnection> getConnections(Application application, IConnectionsFilter connectionsFilter)
+	{
+		Args.notNull(application, "application");
+		Args.notNull(connectionsFilter, "connectionsFilter");
+
+		Collection<IWebSocketConnection> connections = new ArrayList<>();
+		ConcurrentMap<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsBySession = application.getMetaData(KEY);
+		if (connectionsBySession != null)
+		{
+			for (Map.Entry<String, ConcurrentMap<IKey, IWebSocketConnection>> connectionsByPage : connectionsBySession.entrySet())
+			{
+				for (Map.Entry<IKey, IWebSocketConnection> connectionEntry: connectionsByPage.getValue().entrySet())
+				{
+					if (connectionsFilter.acceptConnection(connectionsByPage.getKey(), connectionEntry.getKey()))
+					{
+						connections.add(connectionEntry.getValue());
+					}
+				}
+
+			}
+		}
+		return connections;
+	}
+
 	/**
 	 * Returns a collection of currently active websockets. The connections might close at any time.
 	 *
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-jquery.js b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-jquery.js
index cd06ad5..e398207 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-jquery.js
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-jquery.js
@@ -74,6 +74,7 @@
 
 				if (WWS.pageId !== false) {
 					url += '?pageId=' + encodeURIComponent(WWS.pageId);
+					url += '&pageClass=' + encodeURIComponent(WWS.pageClass);
 				} else if (WWS.resourceName) {
 					url += '?resourceName=' + encodeURIComponent(WWS.resourceName);
 					if (WWS.connectionToken) {
diff --git a/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-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-setup.js.tmpl
index 1533cbf..b73eb01 100644
--- a/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-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/res/js/wicket-websocket-setup.js.tmpl
@@ -2,7 +2,7 @@
 	'use strict';
 
 	if (typeof(Wicket.WebSocket.appName) === "undefined") {
-		jQuery.extend(Wicket.WebSocket, { pageId: ${pageId}, resourceName: '${resourceName}', connectionToken: '${connectionToken}',
+		jQuery.extend(Wicket.WebSocket, { pageId: ${pageId},  pageClass: '${pageClass}', resourceName: '${resourceName}', connectionToken: '${connectionToken}',
 			baseUrl: '${baseUrl}', contextPath: '${contextPath}', appName: '${applicationName}',
 			port: ${port}, securePort: ${securePort}, filterPrefix: '${filterPrefix}', sessionId: '${sessionId}' });
 		Wicket.WebSocket.createDefaultConnection();
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketProcessor.java b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketProcessor.java
index e48b908..6d6736d 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketProcessor.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/util/tester/TestWebSocketProcessor.java
@@ -84,6 +84,7 @@ abstract class TestWebSocketProcessor extends AbstractWebSocketProcessor
 		Args.notNull(page, "page");
 		MockHttpServletRequest request = createRequest(wicketTester);
 		request.addParameter("pageId", page.getId());
+		request.addParameter("pageClass", page.getClass().getName());
 		return request;
 	}
 
diff --git a/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterBehaviorTest.java b/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterBehaviorTest.java
index 29ec707..912cec5 100644
--- a/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterBehaviorTest.java
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/test/java/org/apache/wicket/protocol/ws/util/tester/WebSocketTesterBehaviorTest.java
@@ -131,7 +131,7 @@ public class WebSocketTesterBehaviorTest
 			}
 		};
 		webSocketTester.broadcast(tester.getApplication(), tester.getHttpSession().getId(),
-				new PageIdKey(page.getPageId()), broadcastMessage);
+				new PageIdKey(page.getPageId(), page.getClass().getName()), broadcastMessage);
 
 		assertTrue(messageReceived.get());
 		webSocketTester.destroy();
diff --git a/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketConnection.java b/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketConnection.java
index 41fa304..f7e4ca4 100644
--- a/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketConnection.java
+++ b/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/JavaxWebSocketConnection.java
@@ -49,7 +49,7 @@ public class JavaxWebSocketConnection extends AbstractWebSocketConnection
 	public JavaxWebSocketConnection(Session session, AbstractWebSocketProcessor webSocketProcessor)
 	{
 		super(webSocketProcessor);
-		this.session = Args.notNull(session, "connection");
+		this.session = Args.notNull(session, "session");
 	}
 
 	@Override
diff --git a/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java b/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
index 4808dbd..a73324b 100644
--- a/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
+++ b/wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
@@ -47,6 +47,7 @@ public class WicketEndpoint extends Endpoint
 	 * The name of the request parameter that holds the application name
 	 */
 	private static final String WICKET_APP_PARAM_NAME = "wicket-app-name";
+	private static final String WICKET_SESSION_ID = "jsessionid";
 
 	private final AtomicBoolean applicationDestroyed = new AtomicBoolean(false);
 
@@ -56,6 +57,7 @@ public class WicketEndpoint extends Endpoint
 	public void onOpen(Session session, EndpointConfig endpointConfig)
 	{
 		String appName = getApplicationName(session);
+		session.getId();
 
 		WebApplication app = (WebApplication) WebApplication.get(appName);
 		app.getApplicationListeners().add(new ApplicationListener(applicationDestroyed));