You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by GitBox <gi...@apache.org> on 2021/11/08 10:06:38 UTC

[GitHub] [wicket] martin-g commented on a change in pull request #479: Wicket 6930 websocket improvements

martin-g commented on a change in pull request #479:
URL: https://github.com/apache/wicket/pull/479#discussion_r744544608



##########
File path: wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Session.java
##########
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.wicket.examples.websocket;
+
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.apache.wicket.examples.websocket.progress.ProgressUpdater;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.request.Request;
+
+public class JSR356Session extends WebSession {
+
+
+    private ProgressUpdater.ProgressUpdateTask progressUpdateTask;
+
+    public JSR356Session(Request request) {
+        super(request);
+    }
+
+    public ProgressUpdater.ProgressUpdateTask getProgressUpdateTask() {
+        return progressUpdateTask;
+    }
+
+    public synchronized void startTask() {
+        if (progressUpdateTask != null && progressUpdateTask.isRunning()) {
+            return;
+        }
+        ScheduledExecutorService service = JSR356Application.get().getScheduledExecutorService();
+        progressUpdateTask = ProgressUpdater.start(getApplication(), getId(), service);
+    }
+
+    public synchronized void cancel() {

Review comment:
       s/cancel/cancelTask/

##########
File path: wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Session.java
##########
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.wicket.examples.websocket;
+
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.apache.wicket.examples.websocket.progress.ProgressUpdater;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.request.Request;
+
+public class JSR356Session extends WebSession {
+
+
+    private ProgressUpdater.ProgressUpdateTask progressUpdateTask;
+
+    public JSR356Session(Request request) {
+        super(request);
+    }
+
+    public ProgressUpdater.ProgressUpdateTask getProgressUpdateTask() {
+        return progressUpdateTask;
+    }
+
+    public synchronized void startTask() {
+        if (progressUpdateTask != null && progressUpdateTask.isRunning()) {
+            return;
+        }
+        ScheduledExecutorService service = JSR356Application.get().getScheduledExecutorService();
+        progressUpdateTask = ProgressUpdater.start(getApplication(), getId(), service);
+    }
+
+    public synchronized void cancel() {
+        if (progressUpdateTask == null || !progressUpdateTask.isRunning()) {
+            return;
+        }
+        progressUpdateTask.cancel();
+    }
+
+    public static JSR356Session getInstance() {

Review comment:
       s/getInstance/get/

##########
File path: wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java
##########
@@ -28,6 +28,18 @@
  */
 public interface IWebSocketConnectionRegistry
 {
+	/**
+	 * Interface allowing to filter web-sockets connection. This could be used for use cases like the

Review comment:
       web socket connection`s`

##########
File path: wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
##########
@@ -47,6 +47,7 @@
 	 * The name of the request parameter that holds the application name
 	 */
 	private static final String WICKET_APP_PARAM_NAME = "wicket-app-name";
+	private static final String WICKET_SESSION_ID = "jsessionid";

Review comment:
       this is not used

##########
File path: wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketRequestHandler.java
##########
@@ -97,7 +97,13 @@ public void push(byte[] message, int offset, int length)
 		}
 	}
 
-
+	/**
+	 * @return if true then EMPTY partial updates will be ignored.

Review comment:
       if `false` ... ?!

##########
File path: wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketRequestHandler.java
##########
@@ -129,7 +135,11 @@ public void respond(IRequestCycle requestCycle)
 	{
 		if (update != null)
 		{
-			update.writeTo(requestCycle.getResponse(), "UTF-8");
+			// if the update is not empty or empty updates will be pushed anyway then write to response.

Review comment:
       no need of the comment

##########
File path: wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressUpdater.java
##########
@@ -0,0 +1,163 @@
+/*
+ * 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.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 listening 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;
+	}
+
+	public static class TaskCanceled implements IWebSocketPushMessage
+	{
+
+		public TaskCanceled()
+		{
+		}
+	}
+
+	/**
+	 * 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 boolean canceled = false;
+		private 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(((PageIdKey) key).getPageClass()), new TaskCanceled());
+						return;
+					}
+					broadcaster.broadcastAllMatchingFilter(application, (sessionId, key) ->
+							ProgressUpdateTask.this.sessionId.equals(sessionId) && key instanceof PageIdKey && ITaskProgressListener.class.isAssignableFrom(((PageIdKey) key).getPageClass()), new ProgressUpdate(progress));

Review comment:
       this one too

##########
File path: wicket-examples/src/main/java/org/apache/wicket/examples/websocket/JSR356Session.java
##########
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.wicket.examples.websocket;
+
+
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.apache.wicket.examples.websocket.progress.ProgressUpdater;
+import org.apache.wicket.protocol.http.WebSession;
+import org.apache.wicket.request.Request;
+
+public class JSR356Session extends WebSession {
+
+
+    private ProgressUpdater.ProgressUpdateTask progressUpdateTask;
+
+    public JSR356Session(Request request) {
+        super(request);
+    }
+
+    public ProgressUpdater.ProgressUpdateTask getProgressUpdateTask() {
+        return progressUpdateTask;
+    }
+
+    public synchronized void startTask() {
+        if (progressUpdateTask != null && progressUpdateTask.isRunning()) {
+            return;
+        }
+        ScheduledExecutorService service = JSR356Application.get().getScheduledExecutorService();
+        progressUpdateTask = ProgressUpdater.start(getApplication(), getId(), service);

Review comment:
       You can cache the value of `JSR356Application.get()` and reuse it instead of calling `getApplication()`

##########
File path: wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressUpdater.java
##########
@@ -0,0 +1,163 @@
+/*
+ * 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.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 listening to task progress.

Review comment:
       ...as a listener ...

##########
File path: wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.java
##########
@@ -0,0 +1,119 @@
+/*
+ * 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()
+        {
+            @Override
+            protected void onConnect(ConnectedMessage message) {
+
+            }
+        });
+
+        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)
+            {
+                ProgressUpdater.ProgressUpdateTask progressUpdateTask = JSR356Session.getInstance().getProgressUpdateTask();
+                if (progressUpdateTask != null && progressUpdateTask.isRunning() && !progressUpdateTask.isCanceled())
+                {
+                    progressUpdateTask.cancel();

Review comment:
       You can simplify it to `JSR356Session.getInstance().cancelTask();`

##########
File path: wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressUpdater.java
##########
@@ -0,0 +1,163 @@
+/*
+ * 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.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 listening 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;
+	}
+
+	public static class TaskCanceled implements IWebSocketPushMessage
+	{
+
+		public TaskCanceled()

Review comment:
       This constructor is implicit. It could be removed

##########
File path: wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketPushBroadcaster.java
##########
@@ -109,6 +109,72 @@ public void broadcastAll(Application application, IWebSocketPushMessage message)
 		process(application, wsConnections, message);
 	}
 
+	/**
+	 * Processes the given message in all pages in a given session that have active Web Socket connections.
+	 * The message is sent as an event to the Page and components of the session allowing the components
+	 * to be updated.
+	 *
+	 * This method can be invoked from any thread, even a non-wicket thread. By default all processing
+	 * is done in the caller thread. Use
+	 * {@link WebSocketSettings#setWebSocketPushMessageExecutor(org.apache.wicket.protocol.ws.concurrent.Executor)}
+	 * to move processing to background threads.
+	 *
+	 * If some connections are not in valid state they are silently ignored.
+	 *
+	 * @param application
+	 *			The wicket application
+	 *
+	 * @param sessionId
+	 *         The session ID
+	 * @param message
+	 *			The push message event
+	 */
+	public void broadcastAllInSession(Application application, String sessionId, IWebSocketPushMessage message)
+	{
+		Args.notNull(application, "application");
+		Args.notNull(message, "message");
+
+		Collection<IWebSocketConnection> wsConnections = registry.getConnections(application, sessionId);
+		if (wsConnections == null)
+		{
+			return;
+		}
+		process(application, wsConnections, message);
+	}
+
+	/**
+	 * Processes the given message in all pages in a given session that have active Web Socket connections and match
+	 * the given filter. The message is sent as an event to the Page and components of the session allowing the components
+	 * to be updated.
+	 *
+	 * This method can be invoked from any thread, even a non-wicket thread. By default all processing
+	 * is done in the caller thread. Use
+	 * {@link WebSocketSettings#setWebSocketPushMessageExecutor(org.apache.wicket.protocol.ws.concurrent.Executor)}
+	 * to move processing to background threads.
+	 *
+	 * If some connections are not in valid state they are silently ignored.
+	 *
+	 * @param application
+	 *			The wicket application
+	 *
+	 * @param connectionsFilter
+	 *         the {@link org.apache.wicket.protocol.ws.api.registry.IWebSocketConnectionRegistry.IConnectionsFilter}
+	 * @param message
+	 *			The push message event
+	 */
+	public void broadcastAllMatchingFilter(Application application, IWebSocketConnectionRegistry.IConnectionsFilter connectionsFilter, IWebSocketPushMessage message)
+	{
+		Args.notNull(application, "application");
+		Args.notNull(message, "message");
+
+		Collection<IWebSocketConnection> wsConnections = registry.getConnections(application, connectionsFilter);
+		if (wsConnections == null)

Review comment:
       `... || wsConnections.isEmpty()`

##########
File path: wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/IWebSocketConnectionRegistry.java
##########
@@ -28,6 +28,18 @@
  */
 public interface IWebSocketConnectionRegistry
 {
+	/**
+	 * Interface allowing to filter web-sockets connection. 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 acceptConnection(String sessionId, IKey key);

Review comment:
       rename to `accept(...)` ?

##########
File path: wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressBarTogglePanel.java
##########
@@ -0,0 +1,119 @@
+/*
+ * 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()
+        {
+            @Override
+            protected void onConnect(ConnectedMessage message) {

Review comment:
       this override is not really needed here

##########
File path: wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/WebSocketRequestHandler.java
##########
@@ -97,7 +97,13 @@ public void push(byte[] message, int offset, int length)
 		}
 	}
 
-
+	/**
+	 * @return if true then EMPTY partial updates will be ignored.

Review comment:
       rename it to `shouldPushWhenEmpty()` ?

##########
File path: wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java
##########
@@ -25,9 +28,30 @@
 {
 	private final Integer pageId;
 
+	private Class<? extends IManageablePage> pageClass;
+
 	public PageIdKey(Integer pageId)
+	{
+		this(pageId, null);
+	}
+
+	public PageIdKey(Integer pageId, String pageClass)
 	{
 		this.pageId = Args.notNull(pageId, "pageId");
+		Args.notNull(pageClass, "pageClass");
+		try {
+			this.pageClass = (Class<IManageablePage>)Thread.currentThread().getContextClassLoader().loadClass(pageClass);
+		} catch (ClassNotFoundException e) {
+			//throw new WicketRuntimeException(e);

Review comment:
       This does not look good! Most probably we should not ignore the problem.

##########
File path: wicket-examples/src/main/java/org/apache/wicket/examples/websocket/progress/ProgressUpdater.java
##########
@@ -0,0 +1,163 @@
+/*
+ * 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.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 listening 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;
+	}
+
+	public static class TaskCanceled implements IWebSocketPushMessage
+	{
+
+		public TaskCanceled()
+		{
+		}
+	}
+
+	/**
+	 * 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 boolean canceled = false;
+		private 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(((PageIdKey) key).getPageClass()), new TaskCanceled());

Review comment:
       Please split this line into several shorter ones

##########
File path: wicket-native-websocket/wicket-native-websocket-core/src/main/java/org/apache/wicket/protocol/ws/api/registry/PageIdKey.java
##########
@@ -25,9 +28,30 @@
 {
 	private final Integer pageId;
 
+	private Class<? extends IManageablePage> pageClass;
+
 	public PageIdKey(Integer pageId)
+	{
+		this(pageId, null);
+	}
+
+	public PageIdKey(Integer pageId, String pageClass)
 	{
 		this.pageId = Args.notNull(pageId, "pageId");
+		Args.notNull(pageClass, "pageClass");
+		try {
+			this.pageClass = (Class<IManageablePage>)Thread.currentThread().getContextClassLoader().loadClass(pageClass);

Review comment:
       This should use `IClassResolver`

##########
File path: wicket-native-websocket/wicket-native-websocket-javax/src/main/java/org/apache/wicket/protocol/ws/javax/WicketEndpoint.java
##########
@@ -56,6 +57,7 @@
 	public void onOpen(Session session, EndpointConfig endpointConfig)
 	{
 		String appName = getApplicationName(session);
+		session.getId();

Review comment:
       Why ?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@wicket.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org