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();