You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by mg...@apache.org on 2020/03/31 07:32:36 UTC
[wicket] branch wicket-8.x updated: WICKET-6761 Multiple websocket
connections from the same session (#417)
This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch wicket-8.x
in repository https://gitbox.apache.org/repos/asf/wicket.git
The following commit(s) were added to refs/heads/wicket-8.x by this push:
new 904371d WICKET-6761 Multiple websocket connections from the same session (#417)
904371d is described below
commit 904371dccc5921b42813fe15ae59c21880301419
Author: Thomas <th...@gmail.com>
AuthorDate: Tue Mar 31 09:25:55 2020 +0200
WICKET-6761 Multiple websocket connections from the same session (#417)
* WICKET-6761 Add optional `resourceToken` to support multiple websocket connections from the same session
* WICKET-6761 Add demo page for websocket resources with multiple tabs
* WICKET-6761 Fetch websocket connection on each iteration to showcase issue with multiple tabs
* WICKET-6761 Mount demo page and increase executor pool size for multi tab demo
* WICKET-6761 Rename `resourceToken` to `connectionToken`
(cherry picked from commit 5cce0b148a0cac9cc4d8eb685d8569e84e32eab0)
---
.../apache/wicket/examples/websocket/HomePage.html | 1 +
.../examples/websocket/JSR356Application.java | 3 +-
...html => WebSocketMultiTabResourceDemoPage.html} | 9 +---
.../WebSocketMultiTabResourceDemoPage.java | 36 +++++++++++++++
.../examples/websocket/charts/ChartUpdater.java | 2 +-
.../ws/api/AbstractWebSocketProcessor.java | 10 +++-
.../protocol/ws/api/BaseWebSocketBehavior.java | 28 ++++++++++++
.../ws/api/registry/ResourceNameTokenKey.java | 53 ++++++++++++++++++++++
.../ws/api/res/js/wicket-websocket-jquery.js | 3 ++
.../ws/api/res/js/wicket-websocket-setup.js.tmpl | 2 +-
10 files changed, 136 insertions(+), 11 deletions(-)
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 55758a4..3821f67 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
@@ -28,6 +28,7 @@
<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>
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 1d35e42..062d0d6 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
@@ -44,12 +44,13 @@ public class JSR356Application extends WebApplication
{
super.init();
- scheduledExecutorService = Executors.newScheduledThreadPool(1);
+ scheduledExecutorService = Executors.newScheduledThreadPool(5);
setRootRequestMapper(new HttpsMapper(getRootRequestMapper(), new HttpsConfig(8080, 8443)));
mountPage("/behavior", WebSocketBehaviorDemoPage.class);
mountPage("/resource", WebSocketResourceDemoPage.class);
+ mountPage("/resource-multi-tab", WebSocketMultiTabResourceDemoPage.class);
getSharedResources().add(ChartWebSocketResource.NAME, new ChartWebSocketResource());
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/WebSocketMultiTabResourceDemoPage.html
similarity index 77%
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/WebSocketMultiTabResourceDemoPage.html
index 55758a4..7414e2d 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/WebSocketMultiTabResourceDemoPage.html
@@ -19,17 +19,12 @@
<html xmlns:wicket="http://wicket.apache.org">
<head>
<meta charset="utf-8" />
- <title>Apache Wicket Native WebSocket demos</title>
+ <title>WebSocketResource demo - Apache Wicket Native WebSocket</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>
- </ul>
- </wicket:link>
+ <div wicket:id="chartPanel"></div>
</wicket:extend>
</body>
</html>
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
new file mode 100644
index 0000000..03ec5d6
--- /dev/null
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/WebSocketMultiTabResourceDemoPage.java
@@ -0,0 +1,36 @@
+/*
+ * 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 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()
+ {
+ WebSocketChart chartPanel = new WebSocketChart("chartPanel");
+ chartPanel.add(new BaseWebSocketBehavior(ChartWebSocketResource.NAME, UUID.randomUUID().toString()));
+ add(chartPanel);
+ }
+}
diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/charts/ChartUpdater.java b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/charts/ChartUpdater.java
index 29f11dc..0b586a0 100644
--- a/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/charts/ChartUpdater.java
+++ b/wicket-examples/src/main/java/org/apache/wicket/examples/websocket/charts/ChartUpdater.java
@@ -100,12 +100,12 @@ public class ChartUpdater
Application application = Application.get(applicationName);
WebSocketSettings webSocketSettings = WebSocketSettings.Holder.get(application);
IWebSocketConnectionRegistry webSocketConnectionRegistry = webSocketSettings.getConnectionRegistry();
- IWebSocketConnection connection = webSocketConnectionRegistry.getConnection(application, sessionId, key);
int dataIndex = 0;
while (dataIndex < data.length)
{
+ IWebSocketConnection connection = webSocketConnectionRegistry.getConnection(application, sessionId, key);
try
{
Record record = data[dataIndex++];
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 490a5bc..551aac9 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
@@ -50,6 +50,7 @@ import org.apache.wicket.protocol.ws.api.registry.IKey;
import org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry;
import org.apache.wicket.protocol.ws.api.registry.PageIdKey;
import org.apache.wicket.protocol.ws.api.registry.ResourceNameKey;
+import org.apache.wicket.protocol.ws.api.registry.ResourceNameTokenKey;
import org.apache.wicket.request.IRequestHandler;
import org.apache.wicket.request.Url;
import org.apache.wicket.request.cycle.IRequestCycleListener;
@@ -84,6 +85,7 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
private final WebRequest webRequest;
private final int pageId;
private final String resourceName;
+ private final String connectionToken;
private final Url baseUrl;
private final WebApplication application;
private final String sessionId;
@@ -111,6 +113,7 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
this.sessionId = httpSession.getId();
String pageId = request.getParameter("pageId");
this.resourceName = request.getParameter("resourceName");
+ this.connectionToken = request.getParameter("connectionToken");
if (Strings.isEmpty(pageId) && Strings.isEmpty(resourceName))
{
throw new IllegalArgumentException("The request should have either 'pageId' or 'resourceName' parameter!");
@@ -395,7 +398,12 @@ public abstract class AbstractWebSocketProcessor implements IWebSocketProcessor
}
else
{
- key = new ResourceNameKey(resourceName);
+ if (Strings.isEmpty(connectionToken))
+ {
+ key = new ResourceNameKey(resourceName);
+ } else {
+ key = new ResourceNameTokenKey(resourceName, connectionToken);
+ }
}
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 f334aab..c0a1f18 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
@@ -40,6 +40,7 @@ import org.apache.wicket.util.template.PackageTextTemplate;
public class BaseWebSocketBehavior extends Behavior
{
private final String resourceName;
+ private final String connectionToken;
/**
* Constructor.
@@ -50,6 +51,7 @@ public class BaseWebSocketBehavior extends Behavior
protected BaseWebSocketBehavior()
{
this.resourceName = null;
+ this.connectionToken = null;
}
/**
@@ -70,7 +72,31 @@ public class BaseWebSocketBehavior extends Behavior
*/
public BaseWebSocketBehavior(String resourceName)
{
+ this(resourceName, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * Contributes WebSocket initialization code that will
+ * work with {@link org.apache.wicket.protocol.ws.api.WebSocketResource}
+ *
+ * To use WebSocketResource the application have to setup the
+ * resource as a shared one in its {@link org.apache.wicket.Application#init()}
+ * method:
+ * <code><pre>
+ * getSharedResources().add(resourceName, new MyWebSocketResource())
+ * </pre></code>
+ *
+ * @param resourceName
+ * the name of the shared {@link org.apache.wicket.protocol.ws.api.WebSocketResource}
+ * @param connectionToken
+ * an optional token to support connections to the same resource from multiple browser tabs
+ */
+ public BaseWebSocketBehavior(String resourceName, String connectionToken)
+ {
this.resourceName = Args.notEmpty(resourceName, "resourceName");
+ this.connectionToken = connectionToken;
}
@Override
@@ -103,10 +129,12 @@ public class BaseWebSocketBehavior extends Behavior
int pageId = component.getPage().getPageId();
variables.put("pageId", pageId);
variables.put("resourceName", "");
+ variables.put("connectionToken", "");
}
else
{
variables.put("resourceName", resourceName);
+ variables.put("connectionToken", connectionToken);
variables.put("pageId", false);
}
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
new file mode 100644
index 0000000..be76c12
--- /dev/null
+++ b/wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/ResourceNameTokenKey.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.protocol.ws.api.registry;
+
+import java.util.Objects;
+
+import org.apache.wicket.util.lang.Args;
+
+/**
+ * A key based on shared resource's name and a token
+ */
+public class ResourceNameTokenKey implements IKey
+{
+ private final String resourceName;
+ private final String connectionToken;
+
+ public ResourceNameTokenKey(String resourceName, String connectionToken)
+ {
+ this.resourceName = Args.notNull(resourceName, "resourceName");
+ this.connectionToken = Args.notNull(connectionToken, "connectionToken");
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ return true;
+ if (o == null || getClass() != o.getClass())
+ return false;
+ final ResourceNameTokenKey that = (ResourceNameTokenKey)o;
+ return resourceName.equals(that.resourceName) && connectionToken.equals(that.connectionToken);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(resourceName, connectionToken);
+ }
+}
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 ef5f343..cd06ad5 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
@@ -76,6 +76,9 @@
url += '?pageId=' + encodeURIComponent(WWS.pageId);
} else if (WWS.resourceName) {
url += '?resourceName=' + encodeURIComponent(WWS.resourceName);
+ if (WWS.connectionToken) {
+ url += '&connectionToken=' + encodeURIComponent(WWS.connectionToken);
+ }
}
url += '&wicket-ajax-baseurl=' + encodeURIComponent(WWS.baseUrl);
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 4804232..1533cbf 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}',
+ jQuery.extend(Wicket.WebSocket, { pageId: ${pageId}, resourceName: '${resourceName}', connectionToken: '${connectionToken}',
baseUrl: '${baseUrl}', contextPath: '${contextPath}', appName: '${applicationName}',
port: ${port}, securePort: ${securePort}, filterPrefix: '${filterPrefix}', sessionId: '${sessionId}' });
Wicket.WebSocket.createDefaultConnection();