This is an automated email from the ASF dual-hosted git repository. ilgrosso pushed a commit to branch 4_0_X in repository https://gitbox.apache.org/repos/asf/syncope.git
commit ded84c04c988704a9528c386d816a9037163324b Author: Francesco Chicchiriccò <[email protected]> AuthorDate: Fri Mar 27 15:07:34 2026 +0100 [SYNCOPE-1945] A single WebSocketBejavior per Page --- .../client/console/topology/TabularTopology.java | 3 - .../syncope/client/console/topology/Topology.java | 16 ++- .../topology/TopologyWebSocketBehavior.java | 48 +++---- .../client/console/SyncopeConsoleSession.java | 4 +- .../syncope/client/console/pages/BasePage.java | 12 +- .../syncope/client/console/pages/Dashboard.java | 2 +- .../console/panels/DashboardOverviewPanel.java | 11 +- .../console/reports/ReportDirectoryPanel.java | 15 +-- .../tasks/ProvisioningTaskDirectoryPanel.java | 14 --- .../console/tasks/SchedTaskDirectoryPanel.java | 10 +- .../wicket/ws/BasePageWebSocketBehavior.java | 139 +++++++++++++++++++++ .../wicket/ws/RefreshWebSocketBehavior.java | 85 ------------- .../client/console/widgets/ExtAlertWidget.java | 10 +- .../syncope/client/console/widgets/JobWidget.java | 10 +- 14 files changed, 218 insertions(+), 161 deletions(-) diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TabularTopology.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TabularTopology.java index 94b99b07cc..5e4960478e 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TabularTopology.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TabularTopology.java @@ -39,9 +39,6 @@ public class TabularTopology extends BasePage { private static final long serialVersionUID = -4434385801124981824L; public TabularTopology() { - TopologyWebSocketBehavior websocket = new TopologyWebSocketBehavior(); - body.add(websocket); - WebMarkupContainer content = new WebMarkupContainer("content"); body.add(content.setOutputMarkupId(true)); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java index a7cbcbf759..8a42ee6dbf 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java @@ -46,6 +46,8 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.console.wizards.resources.AbstractResourceWizardBuilder.CreateEvent; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.annotations.IdMPage; +import org.apache.syncope.common.keymaster.client.api.ConfParamOps; +import org.apache.syncope.common.keymaster.client.api.ServiceOps; import org.apache.syncope.common.lib.to.ConnInstanceTO; import org.apache.syncope.common.lib.to.ResourceTO; import org.apache.syncope.common.lib.types.IdMEntitlement; @@ -71,6 +73,12 @@ public class Topology extends BasePage { public static final String CONNECTOR_SERVER_LOCATION_PREFIX = "connid://"; + @SpringBean + protected ServiceOps serviceOps; + + @SpringBean + protected ConfParamOps confParamOps; + @SpringBean protected ResourceRestClient resourceRestClient; @@ -158,8 +166,9 @@ public class Topology extends BasePage { body.add(modal.size(Modal.Size.Large)); modal.setWindowClosedCallback(target -> modal.show(false)); - TopologyWebSocketBehavior websocket = new TopologyWebSocketBehavior(); - body.add(websocket); + TopologyWebSocketBehavior websocket = new TopologyWebSocketBehavior( + serviceOps, confParamOps, connectorRestClient, resourceRestClient); + webSocketBehavior.add(websocket); togglePanel = new TopologyTogglePanel("toggle", getPageReference()); body.add(togglePanel); @@ -574,8 +583,7 @@ public class Topology extends BasePage { payload.getTarget().appendJavaScript(String.format( "window.Wicket.WebSocket.send('" - + "{\"kind\":\"%s\",\"target\":\"%s\",\"source\":\"%s\",\"scope\":\"%s\"}" - + "');", + + "{\"kind\":\"%s\",\"target\":\"%s\",\"source\":\"%s\",\"scope\":\"%s\"}');", SupportedOperation.ADD_ENDPOINT, payload.getKey(), payload.getParent(), diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyWebSocketBehavior.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyWebSocketBehavior.java index 1c81d023b6..5004f4d4e3 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyWebSocketBehavior.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyWebSocketBehavior.java @@ -34,18 +34,16 @@ import java.util.concurrent.TimeoutException; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.rest.ConnectorRestClient; import org.apache.syncope.client.console.rest.ResourceRestClient; +import org.apache.syncope.client.console.wicket.ws.BasePageWebSocketBehavior; import org.apache.syncope.common.keymaster.client.api.ConfParamOps; import org.apache.syncope.common.keymaster.client.api.ServiceOps; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; -import org.apache.wicket.protocol.ws.api.WebSocketBehavior; import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler; import org.apache.wicket.protocol.ws.api.message.TextMessage; -import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.task.SimpleAsyncTaskExecutor; -public class TopologyWebSocketBehavior extends WebSocketBehavior { +public class TopologyWebSocketBehavior extends BasePageWebSocketBehavior.OnMessageChild { private static final long serialVersionUID = -1653665542635275551L; @@ -57,17 +55,13 @@ public class TopologyWebSocketBehavior extends WebSocketBehavior { protected static final String RESOURCE_TEST_TIMEOUT_PARAMETER = "resource.test.timeout"; - @SpringBean - protected ServiceOps serviceOps; + protected final ServiceOps serviceOps; - @SpringBean - protected ConfParamOps confParamOps; + protected final ConfParamOps confParamOps; - @SpringBean - protected ConnectorRestClient connectorRestClient; + protected final ConnectorRestClient connectorRestClient; - @SpringBean - protected ResourceRestClient resourceRestClient; + protected final ResourceRestClient resourceRestClient; protected final Map<String, String> connectors = Collections.synchronizedMap(new HashMap<>()); @@ -77,8 +71,6 @@ public class TopologyWebSocketBehavior extends WebSocketBehavior { protected final Set<String> runningResCheck = Collections.synchronizedSet(new HashSet<>()); - protected final transient SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(); - protected String coreAddress; protected String domain; @@ -89,8 +81,16 @@ public class TopologyWebSocketBehavior extends WebSocketBehavior { protected Integer resourceTestTimeout = null; - public TopologyWebSocketBehavior() { - executor.setVirtualThreads(true); + public TopologyWebSocketBehavior( + final ServiceOps serviceOps, + final ConfParamOps confParamOps, + final ConnectorRestClient connectorRestClient, + final ResourceRestClient resourceRestClient) { + + this.serviceOps = serviceOps; + this.confParamOps = confParamOps; + this.connectorRestClient = connectorRestClient; + this.resourceRestClient = resourceRestClient; coreAddress = serviceOps.get(NetworkService.Type.CORE).getAddress(); domain = SyncopeConsoleSession.get().getDomain(); @@ -119,7 +119,7 @@ public class TopologyWebSocketBehavior extends WebSocketBehavior { response = checker.call(); } else { LOG.debug("Timeouts provided for resource connection checking ... "); - response = executor.submit(checker).get(timeout, TimeUnit.SECONDS); + response = SyncopeConsoleSession.get().execute(checker).get(timeout, TimeUnit.SECONDS); } } catch (InterruptedException | TimeoutException e) { LOG.warn("Connection with {} timed out", checker.key); @@ -141,7 +141,7 @@ public class TopologyWebSocketBehavior extends WebSocketBehavior { try { JsonNode obj = MAPPER.readTree(message.getText()); switch (Topology.SupportedOperation.valueOf(obj.get("kind").asText())) { - case CHECK_CONNECTOR: + case CHECK_CONNECTOR -> { String ckey = obj.get("target").asText(); if (connectors.containsKey(ckey)) { @@ -163,9 +163,9 @@ public class TopologyWebSocketBehavior extends WebSocketBehavior { LOG.error("Unexpected error", e); } } - break; + } - case CHECK_RESOURCE: + case CHECK_RESOURCE -> { String rkey = obj.get("target").asText(); if (resources.containsKey(rkey)) { @@ -187,16 +187,16 @@ public class TopologyWebSocketBehavior extends WebSocketBehavior { LOG.error("Unexpected error", e); } } - break; + } - case ADD_ENDPOINT: + case ADD_ENDPOINT -> handler.appendJavaScript(String.format("addEndpoint('%s', '%s', '%s');", obj.get("source").asText(), obj.get("target").asText(), obj.get("scope").asText())); - break; - default: + default -> { + } } } catch (IOException e) { LOG.error("Error managing websocket message", e); diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java index 6188919e4a..e4c8fdabaa 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java @@ -64,7 +64,6 @@ import org.apache.wicket.authroles.authorization.strategies.role.Roles; import org.apache.wicket.request.Request; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskRejectedException; import org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler; import org.springframework.util.CollectionUtils; @@ -106,7 +105,7 @@ public class SyncopeConsoleSession extends AuthenticatedWebSession implements Ba protected final Map<Class<?>, Object> services = Collections.synchronizedMap(new HashMap<>()); - protected final SimpleAsyncTaskExecutor executor; + protected final SimpleAsyncTaskScheduler executor = new SimpleAsyncTaskScheduler(); protected String domain; @@ -133,7 +132,6 @@ public class SyncopeConsoleSession extends AuthenticatedWebSession implements Ba clientFactory = SyncopeWebApplication.get().newClientFactory(); - executor = new SimpleAsyncTaskScheduler(); executor.setVirtualThreads(true); } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java index cc93e9196c..1498751090 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java @@ -33,7 +33,7 @@ import org.apache.syncope.client.console.panels.SessionExpirationModalPanel; import org.apache.syncope.client.console.rest.SyncopeRestClient; import org.apache.syncope.client.console.wicket.markup.head.MetaHeaderItem; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; -import org.apache.syncope.client.console.wicket.ws.RefreshWebSocketBehavior; +import org.apache.syncope.client.console.wicket.ws.BasePageWebSocketBehavior; import org.apache.syncope.client.console.widgets.ExtAlertWidget; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.annotations.AMPage; @@ -92,6 +92,8 @@ public class BasePage extends BaseWebPage { protected final BaseModal<Serializable> sessionExpiration = new BaseModal<>("sessionExpirationModal"); + protected final BasePageWebSocketBehavior webSocketBehavior = new BasePageWebSocketBehavior(); + public BasePage() { this(null); } @@ -119,9 +121,11 @@ public class BasePage extends BaseWebPage { sessionExpiration.setWindowClosedCallback(target -> sessionExpiration.show(false)); body.add(sessionExpiration); - add(new RefreshWebSocketBehavior() { + add(webSocketBehavior); + webSocketBehavior.add(new BasePageWebSocketBehavior.OnTimerChild( + SyncopeWebApplication.get().getJwtExpirationMinutesThreshold() - 1, TimeUnit.MINUTES) { - private static final long serialVersionUID = 8165980028271428241L; + private static final long serialVersionUID = 532119924423529449L; @Override protected void onTimer(final WebSocketRequestHandler handler) { @@ -133,7 +137,7 @@ public class BasePage extends BaseWebPage { handler.add(sessionExpiration); } } - }.schedule(SyncopeWebApplication.get().getJwtExpirationMinutesThreshold() - 1, TimeUnit.MINUTES)); + }); Serializable leftMenuCollapse = SyncopeConsoleSession.get().getAttribute(Constants.MENU_COLLAPSE); if ((leftMenuCollapse instanceof final Boolean b) && b) { diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Dashboard.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Dashboard.java index 45b9fafcd9..06fda93a53 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Dashboard.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/Dashboard.java @@ -57,7 +57,7 @@ public class Dashboard extends BasePage { @Override public Panel getPanel(final String panelId) { - return new DashboardOverviewPanel(panelId); + return new DashboardOverviewPanel(panelId, getPageReference()); } }); diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DashboardOverviewPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DashboardOverviewPanel.java index 7d0aa7e89f..7be76656a7 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DashboardOverviewPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DashboardOverviewPanel.java @@ -20,13 +20,14 @@ package org.apache.syncope.client.console.panels; import java.util.concurrent.TimeUnit; import org.apache.syncope.client.console.SyncopeConsoleSession; -import org.apache.syncope.client.console.wicket.ws.RefreshWebSocketBehavior; +import org.apache.syncope.client.console.wicket.ws.BasePageWebSocketBehavior; import org.apache.syncope.client.console.widgets.AnyByRealmWidget; import org.apache.syncope.client.console.widgets.CompletenessWidget; import org.apache.syncope.client.console.widgets.LoadWidget; import org.apache.syncope.client.console.widgets.NumberWidget; import org.apache.syncope.client.console.widgets.UsersByStatusWidget; import org.apache.syncope.common.lib.info.NumbersInfo; +import org.apache.wicket.PageReference; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.ResourceModel; @@ -88,7 +89,7 @@ public class DashboardOverviewPanel extends Panel { private final LoadWidget load; - public DashboardOverviewPanel(final String id) { + public DashboardOverviewPanel(final String id, final PageReference pageRef) { super(id); NumbersInfo numbers = SyncopeConsoleSession.get().getAnonymousClient().numbers(); @@ -134,7 +135,9 @@ public class DashboardOverviewPanel extends Panel { load = new LoadWidget("load", SyncopeConsoleSession.get().getAnonymousClient().system()); container.add(load); - container.add(new RefreshWebSocketBehavior() { + pageRef.getPage().getBehaviors().stream(). + filter(BasePageWebSocketBehavior.class::isInstance).map(BasePageWebSocketBehavior.class::cast). + findFirst().ifPresent(wsb -> wsb.add(new BasePageWebSocketBehavior.OnTimerChild(60, TimeUnit.SECONDS) { private static final long serialVersionUID = -7095269057058900157L; @@ -180,6 +183,6 @@ public class DashboardOverviewPanel extends Panel { load.refresh(SyncopeConsoleSession.get().getAnonymousClient().system()); handler.add(load); } - }.schedule(60, TimeUnit.SECONDS)); + })); } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java index b4718e18cc..ab6a8afa86 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java @@ -40,7 +40,7 @@ import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater. import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; -import org.apache.syncope.client.console.wicket.ws.RefreshWebSocketBehavior; +import org.apache.syncope.client.console.wicket.ws.BasePageWebSocketBehavior; import org.apache.syncope.client.console.widgets.JobActionPanel; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.MIMETypesLoader; @@ -99,7 +99,9 @@ public abstract class ReportDirectoryPanel modal.size(Modal.Size.Large); initResultTable(); - container.add(new RefreshWebSocketBehavior() { + pageRef.getPage().getBehaviors().stream(). + filter(BasePageWebSocketBehavior.class::isInstance).map(BasePageWebSocketBehavior.class::cast). + findFirst().ifPresent(wsb -> wsb.add(new BasePageWebSocketBehavior.OnTimerChild(10, TimeUnit.SECONDS) { private static final long serialVersionUID = -4661303265651934868L; @@ -108,7 +110,7 @@ public abstract class ReportDirectoryPanel container.modelChanged(); handler.add(container); } - }.schedule(10, TimeUnit.SECONDS)); + })); startAt = new ReportStartAtTogglePanel(container, pageRef); addInnerObject(startAt); @@ -221,8 +223,7 @@ public abstract class ReportDirectoryPanel public void onClick(final AjaxRequestTarget target, final ReportTO ignore) { final ReportTO clone = SerializationUtils.clone(model.getObject()); clone.setKey(null); - send(ReportDirectoryPanel.this, Broadcast.EXACT, - new AjaxWizard.EditItemActionEvent<>(clone, target)); + send(ReportDirectoryPanel.this, Broadcast.EXACT, new AjaxWizard.EditItemActionEvent<>(clone, target)); } }, ActionLink.ActionType.CLONE, IdRepoEntitlement.REPORT_CREATE); @@ -232,8 +233,8 @@ public abstract class ReportDirectoryPanel @Override public void onClick(final AjaxRequestTarget target, final ReportTO ignore) { - startAt.setExecutionDetail( - model.getObject().getKey(), model.getObject().getName(), target); + ReportDirectoryPanel.this.getTogglePanel().close(target); + startAt.setExecutionDetail(model.getObject().getKey(), model.getObject().getName(), target); startAt.toggle(target, true); } }, ActionLink.ActionType.EXECUTE, IdRepoEntitlement.REPORT_EXECUTE); diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java index 11bcf5fe61..9ab7e8b95e 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java @@ -21,11 +21,9 @@ package org.apache.syncope.client.console.tasks; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.concurrent.TimeUnit; import org.apache.syncope.client.console.panels.MultilevelPanel; import org.apache.syncope.client.console.rest.TaskRestClient; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; -import org.apache.syncope.client.console.wicket.ws.RefreshWebSocketBehavior; import org.apache.syncope.client.console.widgets.JobActionPanel; import org.apache.syncope.common.lib.to.InboundTaskTO; import org.apache.syncope.common.lib.to.ProvisioningTaskTO; @@ -36,7 +34,6 @@ import org.apache.wicket.event.IEvent; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; import org.apache.wicket.model.StringResourceModel; -import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler; /** * Tasks page. @@ -75,17 +72,6 @@ public abstract class ProvisioningTaskDirectoryPanel<T extends ProvisioningTaskT // super in order to call the parent implementation enableUtilityButton(); super.initResultTable(); - - container.add(new RefreshWebSocketBehavior() { - - private static final long serialVersionUID = -4661303265651934868L; - - @Override - protected void onTimer(final WebSocketRequestHandler handler) { - container.modelChanged(); - handler.add(container); - } - }.schedule(10, TimeUnit.SECONDS)); } @Override diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java index 76104b0d1b..d67afcecd6 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java @@ -41,7 +41,7 @@ import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.Bas import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; -import org.apache.syncope.client.console.wicket.ws.RefreshWebSocketBehavior; +import org.apache.syncope.client.console.wicket.ws.BasePageWebSocketBehavior; import org.apache.syncope.client.console.widgets.JobActionPanel; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.panels.ModalPanel; @@ -121,16 +121,18 @@ public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO> initResultTable(); - container.add(new RefreshWebSocketBehavior() { + pageRef.getPage().getBehaviors().stream(). + filter(BasePageWebSocketBehavior.class::isInstance).map(BasePageWebSocketBehavior.class::cast). + findFirst().ifPresent(wsb -> wsb.add(new BasePageWebSocketBehavior.OnTimerChild(10, TimeUnit.SECONDS) { - private static final long serialVersionUID = -4661303265651934868L; + private static final long serialVersionUID = 532119924423529449L; @Override protected void onTimer(final WebSocketRequestHandler handler) { container.modelChanged(); handler.add(container); } - }.schedule(10, TimeUnit.SECONDS)); + })); startAt = new TaskStartAtTogglePanel(container, pageRef); addInnerObject(startAt); diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/ws/BasePageWebSocketBehavior.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/ws/BasePageWebSocketBehavior.java new file mode 100644 index 0000000000..99a0a5cfd6 --- /dev/null +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/ws/BasePageWebSocketBehavior.java @@ -0,0 +1,139 @@ +/* + * 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.syncope.client.console.wicket.ws; + +import com.giffing.wicket.spring.boot.starter.web.WicketWebInitializer; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ScheduledThreadPoolExecutor; +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.WebSocketBehavior; +import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler; +import org.apache.wicket.protocol.ws.api.message.ClosedMessage; +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.message.TextMessage; +import org.apache.wicket.protocol.ws.api.registry.IKey; + +public class BasePageWebSocketBehavior extends WebSocketBehavior { + + private static final long serialVersionUID = -2572183403109560579L; + + protected abstract static class Child implements Serializable { + + private static final long serialVersionUID = -8242819397698846428L; + + protected final String nonce = UUID.randomUUID().toString(); + + } + + public abstract static class OnTimerChild extends Child { + + private static final long serialVersionUID = -2368062250910082871L; + + protected final long period; + + protected final TimeUnit unit; + + public OnTimerChild(final long period, final TimeUnit unit) { + this.period = period; + this.unit = unit; + } + + protected abstract void onTimer(WebSocketRequestHandler handler); + } + + public abstract static class OnMessageChild extends Child { + + private static final long serialVersionUID = 2306119214592765956L; + + protected abstract void onMessage(WebSocketRequestHandler handler, TextMessage message); + } + + protected record WSConnectionInfo(String sessionId, IKey ikey) implements Serializable { + + } + + protected record RefreshMessage(String nonce) implements IWebSocketPushMessage { + + } + + protected final List<Child> children = new ArrayList<>(); + + protected WSConnectionInfo wsConnectionInfo; + + public void add(final Child child) { + if (children.stream().noneMatch(c -> c.nonce.equals(child.nonce))) { + children.add(child); + + if (child instanceof OnTimerChild onTimerChild && wsConnectionInfo != null) { + schedule(onTimerChild, wsConnectionInfo.sessionId(), wsConnectionInfo.ikey()); + } + } + } + + protected void schedule(final OnTimerChild child, final String sessionId, final IKey ikey) { + ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, Thread.ofVirtual().factory()); + executor.scheduleAtFixedRate(() -> { + Application application = Application.get(WicketWebInitializer.WICKET_FILTERNAME); + IWebSocketConnection wsConnection = WebSocketSettings.Holder.get(application). + getConnectionRegistry().getConnection(application, sessionId, ikey); + Optional.ofNullable(wsConnection).filter(IWebSocketConnection::isOpen).ifPresentOrElse( + wsc -> wsc.sendMessage(new RefreshMessage(child.nonce)), + () -> executor.shutdownNow()); + }, 0, child.period, child.unit); + } + + @Override + protected void onConnect(final ConnectedMessage message) { + wsConnectionInfo = new WSConnectionInfo(message.getSessionId(), message.getKey()); + + children.stream(). + filter(OnTimerChild.class::isInstance).map(OnTimerChild.class::cast). + forEach(child -> schedule(child, message.getSessionId(), message.getKey())); + } + + @Override + protected void onMessage(final WebSocketRequestHandler handler, final TextMessage message) { + children.stream(). + filter(OnMessageChild.class::isInstance).map(OnMessageChild.class::cast).findFirst(). + ifPresent(child -> child.onMessage(handler, message)); + } + + @Override + protected void onPush(final WebSocketRequestHandler handler, final IWebSocketPushMessage message) { + if (message instanceof RefreshMessage refreshMessage) { + children.stream(). + filter(OnTimerChild.class::isInstance).map(OnTimerChild.class::cast). + filter(child -> child.nonce.equals(refreshMessage.nonce())).findFirst(). + ifPresent(child -> child.onTimer(handler)); + } + } + + @Override + protected void onClose(final ClosedMessage message) { + children.clear(); + } +} diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/ws/RefreshWebSocketBehavior.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/ws/RefreshWebSocketBehavior.java deleted file mode 100644 index 9485212b34..0000000000 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/ws/RefreshWebSocketBehavior.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.syncope.client.console.wicket.ws; - -import com.giffing.wicket.spring.boot.starter.web.WicketWebInitializer; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import org.apache.commons.lang3.mutable.Mutable; -import org.apache.commons.lang3.mutable.MutableObject; -import org.apache.commons.lang3.tuple.Pair; -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.WebSocketBehavior; -import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler; -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; - -public abstract class RefreshWebSocketBehavior extends WebSocketBehavior { - - private record RefreshMessage(String nonce) implements IWebSocketPushMessage { - - } - - private static final long serialVersionUID = 5636572627689425575L; - - protected final Mutable<Pair<String, IKey>> websocketInfo = new MutableObject<>(); - - protected final String nonce; - - public RefreshWebSocketBehavior() { - nonce = UUID.randomUUID().toString(); - } - - @Override - protected void onConnect(final ConnectedMessage message) { - websocketInfo.setValue(Pair.of(message.getSessionId(), message.getKey())); - } - - protected abstract void onTimer(WebSocketRequestHandler handler); - - @Override - protected void onPush(final WebSocketRequestHandler handler, final IWebSocketPushMessage message) { - if (message instanceof RefreshMessage refreshMessage && nonce.equals(refreshMessage.nonce())) { - onTimer(handler); - } - } - - public RefreshWebSocketBehavior schedule(final long period, final TimeUnit unit) { - ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, Thread.ofVirtual().factory()); - executor.scheduleAtFixedRate(() -> { - if (websocketInfo.get() == null) { - return; - } - - Application application = Application.get(WicketWebInitializer.WICKET_FILTERNAME); - IWebSocketConnection wsConnection = WebSocketSettings.Holder.get(application).getConnectionRegistry(). - getConnection(application, websocketInfo.get().getLeft(), websocketInfo.get().getRight()); - Optional.ofNullable(wsConnection).filter(IWebSocketConnection::isOpen).ifPresentOrElse( - wsc -> wsc.sendMessage(new RefreshMessage(nonce)), - () -> executor.shutdownNow()); - }, 0, period, unit); - - return this; - } -} diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/ExtAlertWidget.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/ExtAlertWidget.java index d2fcd97485..20d1d65412 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/ExtAlertWidget.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/ExtAlertWidget.java @@ -19,7 +19,7 @@ package org.apache.syncope.client.console.widgets; import java.util.concurrent.TimeUnit; -import org.apache.syncope.client.console.wicket.ws.RefreshWebSocketBehavior; +import org.apache.syncope.client.console.wicket.ws.BasePageWebSocketBehavior; import org.apache.wicket.PageReference; import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler; @@ -33,9 +33,11 @@ public abstract class ExtAlertWidget extends AlertWidget { super(id); this.pageRef = pageRef; - add(new RefreshWebSocketBehavior() { + pageRef.getPage().getBehaviors().stream(). + filter(BasePageWebSocketBehavior.class::isInstance).map(BasePageWebSocketBehavior.class::cast). + findFirst().ifPresent(wsb -> wsb.add(new BasePageWebSocketBehavior.OnTimerChild(30, TimeUnit.SECONDS) { - private static final long serialVersionUID = -7095269057058900157L; + private static final long serialVersionUID = 532119924423529449L; @Override protected void onTimer(final WebSocketRequestHandler handler) { @@ -48,6 +50,6 @@ public abstract class ExtAlertWidget extends AlertWidget { handler.add(headerAlertsNumber); } } - }.schedule(30, TimeUnit.SECONDS)); + })); } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java index 635a45017f..7e666fac7f 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/widgets/JobWidget.java @@ -49,7 +49,7 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksTogglePanel; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; -import org.apache.syncope.client.console.wicket.ws.RefreshWebSocketBehavior; +import org.apache.syncope.client.console.wicket.ws.BasePageWebSocketBehavior; import org.apache.syncope.client.console.wizards.WizardMgtPanel; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.MIMETypesLoader; @@ -174,7 +174,9 @@ public class JobWidget extends BaseWidget { recent = getUpdatedRecent(); container = new WebMarkupContainer("jobContainer"); - container.add(new RefreshWebSocketBehavior() { + pageRef.getPage().getBehaviors().stream(). + filter(BasePageWebSocketBehavior.class::isInstance).map(BasePageWebSocketBehavior.class::cast). + findFirst().ifPresent(wsb -> wsb.add(new BasePageWebSocketBehavior.OnTimerChild(10, TimeUnit.SECONDS) { private static final long serialVersionUID = 7298597675929755960L; @@ -200,7 +202,7 @@ public class JobWidget extends BaseWidget { } } } - }.schedule(10, TimeUnit.SECONDS)); + })); add(container); container.add(new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList(pageRef))); @@ -559,7 +561,7 @@ public class JobWidget extends BaseWidget { } } - private class RecentExecPanel + public class RecentExecPanel extends DirectoryPanel<ExecTO, ExecTO, RecentExecPanel.RecentExecProvider, BaseRestClient> { private static final long serialVersionUID = -8214546246301342868L;
