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

reiern70 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/wicket.git


The following commit(s) were added to refs/heads/master by this push:
     new f707376  WICKET-6930: This commit adds: 1) allow to skip sending empty 
WS messages 2) pass page class as a kind of context that can be used to send a 
web socket to different pages + example of updating a component in a given page 
(not dependent on page ID)
f707376 is described below

commit f7073760881dbac26e7c94a6f9a67d09bb599cf6
Author: ernestosemedy <[email protected]>
AuthorDate: Thu May 20 12:00:23 2021 +0300

    WICKET-6930: This commit adds: 1) allow to skip sending empty WS messages 
2) pass page class as a kind of context that can be used to send a web socket 
to different pages + example of updating a component in a given page (not 
dependent on page ID)
---
 .../org/apache/wicket/page/PartialPageUpdate.java  |   8 +
 .../apache/wicket/examples/websocket/HomePage.html |   1 +
 .../examples/websocket/JSR356Application.java      |  12 +-
 .../wicket/examples/websocket/JSR356Session.java   |  66 ++++++++
 .../websocket/WebSocketBehaviorDemoPage.java       |   2 -
 .../WebSocketMultiTabResourceDemoPage.java         |   2 -
 .../WebSocketPushUpdateProgressDemoPage.html       |   8 +
 ...va => WebSocketPushUpdateProgressDemoPage.java} |  15 +-
 .../websocket/WebSocketResourceDemoPage.java       |   2 -
 .../ProgressBarTogglePanel.html}                   |  30 ++--
 .../websocket/progress/ProgressBarTogglePanel.java | 111 +++++++++++++
 .../websocket/progress/ProgressUpdater.java        | 177 +++++++++++++++++++++
 .../ws/api/AbstractWebSocketConnection.java        |   2 +-
 .../ws/api/AbstractWebSocketProcessor.java         |  33 ++--
 .../protocol/ws/api/BaseWebSocketBehavior.java     |  12 ++
 .../protocol/ws/api/WebSocketPushBroadcaster.java  |  68 ++++++++
 .../protocol/ws/api/WebSocketRequestHandler.java   |  17 +-
 .../api/registry/{IKey.java => AbstractKey.java}   |  21 ++-
 .../wicket/protocol/ws/api/registry/IKey.java      |   8 +-
 .../api/registry/IWebSocketConnectionRegistry.java |  26 ++-
 .../wicket/protocol/ws/api/registry/PageIdKey.java |  13 +-
 .../protocol/ws/api/registry/ResourceNameKey.java  |   8 +-
 .../ws/api/registry/ResourceNameTokenKey.java      |   9 +-
 .../SimpleWebSocketConnectionRegistry.java         |  26 +++
 .../ws/api/res/js/wicket-websocket-jquery.js       |   4 +
 .../ws/api/res/js/wicket-websocket-setup.js.tmpl   |   2 +-
 .../ws/util/tester/TestWebSocketProcessor.java     |  17 +-
 .../util/tester/WebSocketTesterBehaviorTest.java   |   2 +-
 .../ws/javax/JavaxWebSocketConnection.java         |   2 +-
 .../wicket/protocol/ws/javax/WicketEndpoint.java   |   1 -
 30 files changed, 633 insertions(+), 72 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 d9c3ca3..2c8e282 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-examples/src/main/java/org/apache/wicket/examples/websocket/HomePage.html
 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/HomePage.html
index 3821f67..0207e52 100644
--- 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/HomePage.html
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/HomePage.html
@@ -29,6 +29,7 @@
                                        <li><a 
href="WebSocketBehaviorDemoPage.html">demo with WebSocketBehavior</a></li>
                                        <li><a 
href="WebSocketResourceDemoPage.html">demo with WebSocketResource</a></li>
                                        <li><a 
href="WebSocketMultiTabResourceDemoPage.html">demo with WebSocketResource and 
multiple tabs</a></li>
+                                       <li><a 
href="WebSocketPushUpdateProgressDemoPage.html">Update a component via 
server-side initiated notifications</a></li>
                                </ul>
                        </wicket:link>
                </wicket:extend>
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 bb38205..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;
@@ -50,6 +53,7 @@ public class JSR356Application extends 
WicketExampleApplication
                setRootRequestMapper(new HttpsMapper(getRootRequestMapper(), 
new HttpsConfig(8080, 8443)));
 
                mountPage("/behavior", WebSocketBehaviorDemoPage.class);
+               mountPage("/push", WebSocketPushUpdateProgressDemoPage.class);
                mountPage("/resource", WebSocketResourceDemoPage.class);
                mountPage("/resource-multi-tab", 
WebSocketMultiTabResourceDemoPage.class);
 
@@ -69,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..71910a2
--- /dev/null
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Session.java
@@ -0,0 +1,66 @@
+/*
+ * 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;
+    }
+
+    private synchronized void startTask() {
+        if (progressUpdateTask != null && progressUpdateTask.isRunning())
+        {
+            return;
+        }
+
+        JSR356Application application = JSR356Application.get();
+        ScheduledExecutorService service = 
application.getScheduledExecutorService();
+        progressUpdateTask = ProgressUpdater.start(application, getId(), 
service);
+    }
+
+    public synchronized void startOrCancelTask() {
+        if (progressUpdateTask != null && progressUpdateTask.isRunning() && 
!progressUpdateTask.isCanceled())
+        {
+            progressUpdateTask.cancel();
+        }
+        else
+        {
+            startTask();
+        }
+    }
+
+    public static JSR356Session get() {
+        return (JSR356Session)WebSession.get();
+    }
+}
diff --git 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketBehaviorDemoPage.java
 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketBehaviorDemoPage.java
index 8d038aa..c6bff98 100644
--- 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketBehaviorDemoPage.java
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketBehaviorDemoPage.java
@@ -25,7 +25,6 @@ import 
org.apache.wicket.examples.websocket.charts.ChartUpdater;
 import org.apache.wicket.examples.websocket.charts.WebSocketChart;
 import org.apache.wicket.extensions.ajax.AjaxDownloadBehavior;
 import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.protocol.https.RequireHttps;
 import org.apache.wicket.protocol.ws.api.WebSocketBehavior;
 import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler;
 import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
@@ -36,7 +35,6 @@ import 
org.apache.wicket.request.resource.ResourceStreamResource;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.resource.StringResourceStream;
 
-@RequireHttps
 public class WebSocketBehaviorDemoPage extends WicketExamplePage
 {
        private static final long serialVersionUID = 1L;
diff --git 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketMultiTabResourceDemoPage.java
 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketMultiTabResourceDemoPage.java
index 03ec5d6..534906c 100644
--- 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketMultiTabResourceDemoPage.java
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketMultiTabResourceDemoPage.java
@@ -19,12 +19,10 @@ package org.apache.wicket.examples.websocket;
 import org.apache.wicket.examples.WicketExamplePage;
 import org.apache.wicket.examples.websocket.charts.ChartWebSocketResource;
 import org.apache.wicket.examples.websocket.charts.WebSocketChart;
-import org.apache.wicket.protocol.https.RequireHttps;
 import org.apache.wicket.protocol.ws.api.BaseWebSocketBehavior;
 
 import java.util.UUID;
 
-@RequireHttps
 public class WebSocketMultiTabResourceDemoPage extends WicketExamplePage
 {
        public WebSocketMultiTabResourceDemoPage()
diff --git 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.html
 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.html
new file mode 100644
index 0000000..55210d3
--- /dev/null
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.html
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<html xmlns="http://www.w3.org/1999/xhtml"; 
xmlns:wicket="http://wicket.apache.org";>
+<body>
+<wicket:extend>
+    <div wicket:id="progressPanel"></div>
+</wicket:extend>
+</body>
+</html>
\ No newline at end of file
diff --git 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketResourceDemoPage.java
 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.java
similarity index 63%
copy from 
wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketResourceDemoPage.java
copy to 
wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.java
index d8aef4d..a61ed66 100644
--- 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketResourceDemoPage.java
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketPushUpdateProgressDemoPage.java
@@ -17,18 +17,13 @@
 package org.apache.wicket.examples.websocket;
 
 import org.apache.wicket.examples.WicketExamplePage;
-import org.apache.wicket.examples.websocket.charts.ChartWebSocketResource;
-import org.apache.wicket.examples.websocket.charts.WebSocketChart;
-import org.apache.wicket.protocol.https.RequireHttps;
-import org.apache.wicket.protocol.ws.api.BaseWebSocketBehavior;
+import org.apache.wicket.examples.websocket.progress.ProgressBarTogglePanel;
+import org.apache.wicket.examples.websocket.progress.ProgressUpdater;
 
-@RequireHttps
-public class WebSocketResourceDemoPage extends WicketExamplePage
+public class WebSocketPushUpdateProgressDemoPage extends WicketExamplePage 
implements ProgressUpdater.ITaskProgressListener
 {
-       public WebSocketResourceDemoPage()
+       public WebSocketPushUpdateProgressDemoPage()
        {
-               WebSocketChart chartPanel = new WebSocketChart("chartPanel");
-               chartPanel.add(new 
BaseWebSocketBehavior(ChartWebSocketResource.NAME));
-               add(chartPanel);
+               add(new ProgressBarTogglePanel("progressPanel"));
        }
 }
diff --git 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketResourceDemoPage.java
 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketResourceDemoPage.java
index d8aef4d..079bff9 100644
--- 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketResourceDemoPage.java
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketResourceDemoPage.java
@@ -19,10 +19,8 @@ package org.apache.wicket.examples.websocket;
 import org.apache.wicket.examples.WicketExamplePage;
 import org.apache.wicket.examples.websocket.charts.ChartWebSocketResource;
 import org.apache.wicket.examples.websocket.charts.WebSocketChart;
-import org.apache.wicket.protocol.https.RequireHttps;
 import org.apache.wicket.protocol.ws.api.BaseWebSocketBehavior;
 
-@RequireHttps
 public class WebSocketResourceDemoPage extends WicketExamplePage
 {
        public WebSocketResourceDemoPage()
diff --git 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/HomePage.html
 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.html
similarity index 56%
copy from 
wicket-examples/src/main/java/org/apache/wicket/examples/websocket/HomePage.html
copy to 
wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.html
index 3821f67..971f7f2 100644
--- 
a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/HomePage.html
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.html
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8" ?>
+<?xml version="1.0" encoding="UTF-8"?>
 <!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -15,22 +15,12 @@
    See the License for the specific language governing permissions and
    limitations under the License.
 -->
-<!DOCTYPE html>
-<html xmlns:wicket="http://wicket.apache.org";>
-       <head>
-               <meta charset="utf-8" />
-        <title>Apache Wicket Native WebSocket demos</title>
-       </head>
-       <body>
-               <wicket:extend>
-
-                       <wicket:link>
-                               <ul>
-                                       <li><a 
href="WebSocketBehaviorDemoPage.html">demo with WebSocketBehavior</a></li>
-                                       <li><a 
href="WebSocketResourceDemoPage.html">demo with WebSocketResource</a></li>
-                                       <li><a 
href="WebSocketMultiTabResourceDemoPage.html">demo with WebSocketResource and 
multiple tabs</a></li>
-                               </ul>
-                       </wicket:link>
-               </wicket:extend>
-       </body>
-</html>
+<html xmlns="http://www.w3.org/1999/xhtml"; 
xmlns:wicket="http://wicket.apache.org";>
+<body>
+<wicket:panel>
+    <div><a wicket:id="hideShowProgress"></a></div>
+    <div><a wicket:id="cancelRestartTask"></a></div>
+    <div wicket:id="progressBar"></div>
+</wicket:panel>
+</body>
+</html>
\ No newline at end of file
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
new file mode 100644
index 0000000..dc7078e
--- /dev/null
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.java
@@ -0,0 +1,111 @@
+/*
+ * 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.progress;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+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;
+import org.apache.wicket.protocol.ws.api.WebSocketBehavior;
+import org.apache.wicket.protocol.ws.api.event.WebSocketPushPayload;
+import org.apache.wicket.protocol.ws.api.message.ConnectedMessage;
+
+public class ProgressBarTogglePanel extends Panel
+{
+
+    private int progress = 0;
+    private boolean showProgress = true;
+
+
+    public ProgressBarTogglePanel(String id)
+    {
+        super(id);
+
+        setOutputMarkupId(true);
+
+        add(new WebSocketBehavior()
+        {
+        });
+
+        add(new AjaxLink<Void>("hideShowProgress")
+        {
+            @Override
+            public void onClick(AjaxRequestTarget target)
+            {
+                showProgress = !showProgress;
+                target.add(ProgressBarTogglePanel.this);
+            }
+        }.setBody((IModel<String>) () -> showProgress ? "Hide progress" : 
"Show progress"));
+
+        add(new AjaxLink<Void>("cancelRestartTask")
+        {
+            @Override
+            public void onClick(AjaxRequestTarget target)
+            {
+                JSR356Session.get().startOrCancelTask();
+                target.add(ProgressBarTogglePanel.this);
+            }
+        }.setBody((IModel<String>) () -> {
+            ProgressUpdater.ProgressUpdateTask progressUpdateTask = 
JSR356Session.get().getProgressUpdateTask();
+            return progressUpdateTask != null && 
progressUpdateTask.isRunning() && !progressUpdateTask.isCanceled()
+                    ? "Cancel task" :
+                    "Restart task";
+        }));
+
+        add(new Label("progressBar", (IModel<String>) () -> {
+            ProgressUpdater.ProgressUpdateTask progressUpdateTask = 
JSR356Session.get().getProgressUpdateTask();
+            return progressUpdateTask != null && progressUpdateTask.isRunning()
+                    ? "Background Task is " + progress + "% completed"
+                    : "No task is running";
+        })
+        {
+            @Override
+            protected void onConfigure()
+            {
+                super.onConfigure();
+                setVisible(showProgress);
+            }
+        });
+    }
+
+
+    @Override
+    public void onEvent(IEvent<?> event)
+    {
+        if (event.getPayload() instanceof WebSocketPushPayload)
+        {
+            WebSocketPushPayload wsEvent = (WebSocketPushPayload) 
event.getPayload();
+            if (wsEvent.getMessage() instanceof ProgressUpdater.ProgressUpdate)
+            {
+                ProgressUpdater.ProgressUpdate progressUpdate = 
(ProgressUpdater.ProgressUpdate)wsEvent.getMessage();
+                progress = progressUpdate.getProgress();
+                wsEvent.getHandler().add(this);
+            }
+            else if (wsEvent.getMessage() instanceof 
ProgressUpdater.TaskCanceled)
+            {
+                // task was canceled
+                wsEvent.getHandler().add(this);
+            }
+        }
+    }
+}
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
new file mode 100644
index 0000000..48f9848
--- /dev/null
+++ 
b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressUpdater.java
@@ -0,0 +1,177 @@
+/*
+ * 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.progress;
+
+import java.io.Serializable;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.wicket.Application;
+import org.apache.wicket.WicketRuntimeException;
+import org.apache.wicket.application.IClassResolver;
+import org.apache.wicket.page.IManageablePage;
+import org.apache.wicket.protocol.ws.WebSocketSettings;
+import org.apache.wicket.protocol.ws.api.IWebSocketConnection;
+import org.apache.wicket.protocol.ws.api.WebSocketPushBroadcaster;
+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;
+
+/**
+ * A helper class that uses the web connection to push components updates to 
the client.
+ */
+public class ProgressUpdater
+{
+       /**
+        * Marks a page as a listener to task progress.
+        */
+       public interface ITaskProgressListener {
+
+       }
+
+       private static final Logger LOGGER = 
LoggerFactory.getLogger(ProgressUpdater.class);
+
+       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(application, session);
+               scheduledExecutorService.schedule(progressUpdateTask, 1, 
TimeUnit.SECONDS);
+               return progressUpdateTask;
+       }
+
+       /**
+        * Signal task was canceled.
+        */
+       public static class TaskCanceled implements IWebSocketPushMessage
+       {
+       }
+
+       /**
+        * A push message used to update progress.
+        */
+       public static class ProgressUpdate implements IWebSocketPushMessage
+       {
+
+               private final int progress;
+
+               public ProgressUpdate(int progress)
+               {
+                       this.progress = progress;
+               }
+
+               public int getProgress()
+               {
+                       return progress;
+               }
+       }
+
+       /**
+        * A task that sends data to the client by pushing it to the web socket 
connection
+        */
+       public static class ProgressUpdateTask implements Runnable, Serializable
+       {
+               /**
+                * The following fields are needed to be able to lookup the 
IWebSocketConnection from
+                * IWebSocketConnectionRegistry
+                */
+               private final String applicationName;
+               private final String sessionId;
+
+               private volatile boolean canceled = false;
+               private volatile boolean running = false;
+
+               private ProgressUpdateTask(Application application, String 
sessionId)
+               {
+                       this.applicationName = application.getName();
+                       this.sessionId = sessionId;
+               }
+
+               @Override
+               public void run()
+               {
+                       running = true;
+                       Application application = 
Application.get(applicationName);
+                       WebSocketSettings webSocketSettings = 
WebSocketSettings.Holder.get(application);
+
+                       int progress = 0;
+
+                       while (progress <= 100)
+                       {
+                               try
+                               {
+                                       WebSocketPushBroadcaster broadcaster =
+                                                       new 
WebSocketPushBroadcaster(webSocketSettings.getConnectionRegistry());
+
+                                       if (canceled)
+                                       {
+                                               canceled = false;
+                                               running = false;
+                                               
broadcaster.broadcastAllMatchingFilter(application, (sessionId, key) ->
+                                                               
ProgressUpdateTask.this.sessionId.equals(sessionId) && key instanceof PageIdKey
+                                                                               
&& ITaskProgressListener.class.isAssignableFrom(getPageClass(application, key)),
+                                                               new 
TaskCanceled());
+                                               return;
+                                       }
+                                       
broadcaster.broadcastAllMatchingFilter(application, (sessionId, key) ->
+                                                       
ProgressUpdateTask.this.sessionId.equals(sessionId) && key instanceof PageIdKey 
&&
+                                                                       
ITaskProgressListener.class.isAssignableFrom(getPageClass(application, key)),
+                                                       new 
ProgressUpdate(progress));
+
+                                       // sleep for a while to simulate work
+                                       TimeUnit.SECONDS.sleep(1);
+                                       progress++;
+                               }
+                               catch (InterruptedException x)
+                               {
+                                       Thread.currentThread().interrupt();
+                                       break;
+                               }
+                               catch (Exception e)
+                               {
+                                       LOGGER.error("unexpected exception", e);
+                                       break;
+                               }
+                       }
+                       running = false;
+               }
+
+               protected Class<?> getPageClass(Application application, IKey 
iKey) {
+                       try {
+                               return 
application.getApplicationSettings().getClassResolver().resolveClass(iKey.getContext());
+                       } catch (ClassNotFoundException e) {
+                               throw new WicketRuntimeException(e);
+                       }
+               }
+
+               public boolean isRunning() {
+                       return running;
+               }
+
+               public boolean isCanceled() {
+                       return canceled;
+               }
+
+               public void cancel() {
+                       this.canceled = true;
+                       this.running = false;
+               }
+       }
+}
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 19982fa..f2a3a93 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 context;
        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");
+               this.context = request.getParameter("context");
                this.resourceName = request.getParameter("resourceName");
                this.connectionToken = request.getParameter("connectionToken");
                if (Strings.isEmpty(pageId) && Strings.isEmpty(resourceName))
@@ -181,7 +184,7 @@ public abstract class AbstractWebSocketProcessor implements 
IWebSocketProcessor
                        }
                }
 
-               broadcastMessage(new ConnectedMessage(getApplication(), 
getSessionId(), key));
+               broadcastMessage(new ConnectedMessage(getApplication(), 
getSessionId(), key), connection);
        }
 
        @Override
@@ -203,6 +206,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 +225,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 +256,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;
                                }
 
@@ -261,7 +268,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 +363,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);
@@ -399,15 +406,15 @@ public abstract class AbstractWebSocketProcessor 
implements IWebSocketProcessor
                IKey key;
                if (Strings.isEmpty(resourceName))
                {
-                       key = new PageIdKey(pageId);
+                       key = new PageIdKey(pageId, context);
                }
                else
                {
                        if (Strings.isEmpty(connectionToken))
                        {
-                               key = new ResourceNameKey(resourceName);
+                               key = new ResourceNameKey(resourceName, 
context);
                        } else {
-                               key = new ResourceNameTokenKey(resourceName, 
connectionToken);
+                               key = new ResourceNameTokenKey(resourceName, 
connectionToken, context);
                        }
                }
                return key;
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 b773ef3..420393e 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
@@ -121,9 +121,21 @@ public class BaseWebSocketBehavior extends Behavior
                return webSocketSetupTemplate.asString(parameters);
        }
 
+       /**
+        * Override to return a context. By default, this is the page class 
name.
+        *
+        * @param component the {@link org.apache.wicket.Component}
+        * @return the context for this websocket behavior.
+        */
+       protected String getContext(Component component) {
+               return component.getPage().getClass().getName();
+       }
+
        private Map<String, Object> getParameters(Component component) {
                Map<String, Object> variables = Generics.newHashMap();
 
+               variables.put("context", getContext(component));
+
                // set falsy JS values for the non-used parameter
                if (Strings.isEmpty(resourceName))
                {
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..c5f6d78 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,74 @@ 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");
+               Args.notNull(sessionId, "sessionId");
+
+               Collection<IWebSocketConnection> wsConnections = 
registry.getConnections(application, sessionId);
+               if (wsConnections == null || wsConnections.isEmpty())
+               {
+                       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");
+               Args.notNull(connectionsFilter, "connectionsFilter");
+
+               Collection<IWebSocketConnection> wsConnections = 
registry.getConnections(application, connectionsFilter);
+               if (wsConnections == null  || wsConnections.isEmpty())
+               {
+                       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/WebSocketRequestHandler.java
 
b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketRequestHandler.java
index 7df3735..7ce1f62 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,17 @@ public class WebSocketRequestHandler extends 
AbstractPartialPageRequestHandler i
                }
        }
 
-
+       /**
+        * @return if <code>true</code> then EMPTY partial updates will se 
send. If <code>false</code> then EMPTY
+        *    partial updates will be skipped. A possible use case is: a page 
receives and a push event but no one is
+        *    listening to it, and nothing is added to {@link 
org.apache.wicket.protocol.ws.api.WebSocketRequestHandler}
+        *    thus no real push to client is needed. For compatibilities this 
is set to true. Thus EMPTY updates are sent
+        *    by default.
+        */
+       protected boolean shouldPushWhenEmpty()
+       {
+               return true;
+       }
 
        protected PartialPageUpdate getUpdate() {
                if (update == null) {
@@ -129,7 +139,10 @@ public class WebSocketRequestHandler extends 
AbstractPartialPageRequestHandler i
        {
                if (update != null)
                {
-                       update.writeTo(requestCycle.getResponse(), "UTF-8");
+                       if (shouldPushWhenEmpty() || !update.isEmpty())
+                       {
+                               update.writeTo(requestCycle.getResponse(), 
"UTF-8");
+                       }
                }
        }
 
diff --git 
a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
 
b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/AbstractKey.java
similarity index 78%
copy from 
wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
copy to 
wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/AbstractKey.java
index b0774dc..afe2eaf 100644
--- 
a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
+++ 
b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/AbstractKey.java
@@ -16,11 +16,18 @@
  */
 package org.apache.wicket.protocol.ws.api.registry;
 
-import org.apache.wicket.util.io.IClusterable;
+public class AbstractKey implements IKey
+{
 
-/**
- * A marker interface for keys that are used to find a web socket
- * connection in {@link IWebSocketConnectionRegistry}
- */
-public interface IKey extends IClusterable
-{}
+    private final String context;
+
+    public AbstractKey(String context)
+    {
+        this.context = context;
+    }
+
+    @Override
+    public String getContext() {
+        return context;
+    }
+}
diff --git 
a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
 
b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
index b0774dc..25a5196 100644
--- 
a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
+++ 
b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IKey.java
@@ -23,4 +23,10 @@ import org.apache.wicket.util.io.IClusterable;
  * connection in {@link IWebSocketConnectionRegistry}
  */
 public interface IKey extends IClusterable
-{}
+{
+    /**
+     * @return return a context for the key. This could be, for instance, a 
page class name or a resource class name.
+     *    I.e. something that allow to discriminate keys along different pages.
+     */
+    String getContext();
+}
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..7665608 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,18 @@ import 
org.apache.wicket.protocol.ws.api.IWebSocketConnection;
 public interface IWebSocketConnectionRegistry
 {
        /**
+        * Interface allowing to filter web-sockets connections. This could be 
used for use cases like the
+        * following: you need to deliver messages to all page instances 
satisfying certain conditions (e.g.
+        * they contain some progress reporting component).
+        */
+       interface IConnectionsFilter
+       {
+
+               boolean accept(String sessionId, IKey key);
+
+       }
+
+       /**
         * @param application
         *      the web application to look in
         * @param sessionId
@@ -44,12 +56,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..2aa7de0 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,20 +16,29 @@
  */
 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;
 
 /**
  * A key based on page's id
  */
-public class PageIdKey implements IKey
+public class PageIdKey extends AbstractKey
 {
        private final Integer pageId;
 
        public PageIdKey(Integer pageId)
        {
-               this.pageId = Args.notNull(pageId, "pageId");
+               this(pageId, null);
        }
 
+       public PageIdKey(Integer pageId, String context)
+       {
+               super(context);
+               this.pageId = Args.notNull(pageId, "pageId");
+       }
+       
        @Override
        public boolean equals(Object o)
        {
diff --git 
a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameKey.java
 
b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameKey.java
index 4f45aed..c5f4bc4 100644
--- 
a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameKey.java
+++ 
b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameKey.java
@@ -21,12 +21,18 @@ import org.apache.wicket.util.lang.Args;
 /**
  * A key based on shared resource's name
  */
-public class ResourceNameKey implements IKey
+public class ResourceNameKey extends AbstractKey
 {
        private final String resourceName;
 
        public ResourceNameKey(String resourceName)
        {
+               this(resourceName, null);
+       }
+
+       public ResourceNameKey(String resourceName, String context)
+       {
+               super(context);
                this.resourceName = Args.notNull(resourceName, "resourceName");
        }
 
diff --git 
a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameTokenKey.java
 
b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameTokenKey.java
index be76c12..e4b890a 100644
--- 
a/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameTokenKey.java
+++ 
b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameTokenKey.java
@@ -23,13 +23,20 @@ import org.apache.wicket.util.lang.Args;
 /**
  * A key based on shared resource's name and a token
  */
-public class ResourceNameTokenKey implements IKey
+public class ResourceNameTokenKey extends AbstractKey
 {
        private final String resourceName;
        private final String connectionToken;
 
+
        public ResourceNameTokenKey(String resourceName, String connectionToken)
        {
+               this(resourceName, connectionToken, null);
+       }
+
+       public ResourceNameTokenKey(String resourceName, String 
connectionToken, String context)
+       {
+               super(context);
                this.resourceName = Args.notNull(resourceName, "resourceName");
                this.connectionToken = Args.notNull(connectionToken, 
"connectionToken");
        }
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..1a17590 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.accept(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..93b7386 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
@@ -81,6 +81,10 @@
                                        }
                                }
 
+                               if (WWS.context) {
+                                       url += '&context=' + 
encodeURIComponent(WWS.context);
+                               }
+
                                url += '&wicket-ajax-baseurl=' + 
encodeURIComponent(WWS.baseUrl);
                                url += '&wicket-app-name=' + 
encodeURIComponent(WWS.appName);
 
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..98e9bc8 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},  context: 
'${context}', 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 cf88c30..6e70466 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
@@ -67,9 +67,20 @@ abstract class TestWebSocketProcessor extends 
AbstractWebSocketProcessor
         * @param resourceName
         *      the name of the shared resource that will handle the web socket 
messages
         */
+       public TestWebSocketProcessor(final WicketTester wicketTester, final 
String resourceName, Page page)
+       {
+               super(createRequest(wicketTester, resourceName, page),  
wicketTester.getApplication());
+       }
+
+       /**
+        * 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());
+               super(createRequest(wicketTester, resourceName, null),  
wicketTester.getApplication());
        }
 
        /**
@@ -84,6 +95,7 @@ abstract class TestWebSocketProcessor extends 
AbstractWebSocketProcessor
                Args.notNull(page, "page");
                MockHttpServletRequest request = createRequest(wicketTester);
                request.addParameter("pageId", page.getId());
+               request.addParameter("context", page.getClass().getName());
                return request;
        }
 
@@ -94,11 +106,12 @@ abstract class TestWebSocketProcessor extends 
AbstractWebSocketProcessor
         *      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)
+       private static HttpServletRequest createRequest(final WicketTester 
wicketTester, final String resourceName, final Page page)
        {
                Args.notNull(resourceName, "resourceName");
                MockHttpServletRequest request = createRequest(wicketTester);
                request.addParameter("resourceName", resourceName);
+               request.addParameter("context", page != null ? 
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 236c64c..b9f6419 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 98c64d0..b5b0b2b 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)
                {

Reply via email to