From d7618ab7369b04098c2bca9318474238d6ec9829 Mon Sep 17 00:00:00 2001 From: Andrea Patricelli Date: Thu, 28 Mar 2024 11:06:16 +0100 Subject: [PATCH] Ensure CXF WebClient to use async conduit (#664) --- .../syncope/client/console/pages/WA.java | 8 ++- .../console/rest/AMSessionRestClient.java | 12 ++--- .../console/rest/SRASessionRestClient.java | 11 ++-- .../console/rest/SRAStatisticsRestClient.java | 8 ++- .../console/rest/WASessionRestClient.java | 8 ++- .../console/rest/ConnectorRestClient.java | 4 +- .../console/rest/ResourceRestClient.java | 4 +- .../console/rest/LoggerConfRestClient.java | 26 ++++----- .../client/lib/SyncopeAnonymousClient.java | 2 +- .../syncope/client/lib/WebClientBuilder.java | 53 +++++++++++++++++++ common/keymaster/self/client-self/pom.xml | 4 ++ .../client/self/SelfKeymasterOps.java | 2 + 12 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/WebClientBuilder.java diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java index aaea9e5c87..43a9c9397d 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java @@ -29,7 +29,6 @@ import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.StringUtils; -import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.BookmarkablePageLinkBuilder; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.SyncopeWebApplication; @@ -49,6 +48,7 @@ import org.apache.syncope.client.console.rest.WAConfigRestClient; import org.apache.syncope.client.console.rest.WASessionRestClient; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.keymaster.client.api.ServiceOps; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.lib.types.AMEntitlement; @@ -128,12 +128,10 @@ public void onClick(final AjaxRequestTarget target) { if (!instances.isEmpty()) { String actuatorEndpoint = StringUtils.appendIfMissing(instances.get(0).getAddress(), "/") + "actuator/env"; try { - Response response = WebClient.create( - actuatorEndpoint, + Response response = WebClientBuilder.build(actuatorEndpoint, SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - accept(MediaType.APPLICATION_JSON_TYPE).get(); + List.of()).accept(MediaType.APPLICATION_JSON_TYPE).get(); if (response.getStatus() == Response.Status.OK.getStatusCode()) { JsonNode env = MAPPER.readTree((InputStream) response.getEntity()); if (env.has("propertySources")) { diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AMSessionRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AMSessionRestClient.java index 60b3a4cbf2..9d188054c7 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AMSessionRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AMSessionRestClient.java @@ -23,8 +23,8 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import java.util.List; -import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.client.ui.commons.rest.RestClient; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.lib.AMSession; @@ -56,13 +56,13 @@ public void delete(final String key) { SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unknown); try { - Response response = WebClient.create( - getActuatorEndpoint(), + Response response = WebClientBuilder.build(getActuatorEndpoint(), SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - path(key). - accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).delete(); + List.of()). + accept(MediaType.APPLICATION_JSON_TYPE). + type(MediaType.APPLICATION_JSON_TYPE). + path(key).delete(); if (response.getStatus() != Response.Status.OK.getStatusCode() && response.getStatus() != Response.Status.NO_CONTENT.getStatusCode()) { diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRASessionRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRASessionRestClient.java index 3d0341e109..81dcc44ad3 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRASessionRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRASessionRestClient.java @@ -22,8 +22,8 @@ import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import java.util.List; -import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.lib.AMSession; @@ -43,15 +43,10 @@ protected String getActuatorEndpoint() { @Override public List list() { try { - WebClient client = WebClient.create( - getActuatorEndpoint(), - JAX_RS_PROVIDERS, + Response response = WebClientBuilder.build(getActuatorEndpoint(), SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - accept(MediaType.APPLICATION_JSON_TYPE); - - Response response = client.get(); + JAX_RS_PROVIDERS).accept(MediaType.APPLICATION_JSON_TYPE).get(); if (response.getStatus() == Response.Status.OK.getStatusCode()) { return response.readEntity(new GenericType<>() { }); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java index 9af194022c..6bb8896f36 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java @@ -26,6 +26,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,13 +44,10 @@ protected String getActuatorEndpoint(final List instances) { public SRAStatistics get(final List instances, final List> selected) { try { - WebClient client = WebClient.create( - getActuatorEndpoint(instances), - JAX_RS_PROVIDERS, + WebClient client = WebClientBuilder.build(getActuatorEndpoint(instances), SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - accept(MediaType.APPLICATION_JSON_TYPE); + JAX_RS_PROVIDERS).accept(MediaType.APPLICATION_JSON_TYPE); if (!selected.isEmpty()) { client.query("tag", selected.stream().map(s -> s.getKey() + ":" + s.getValue()).toArray()); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java index 71b3f6817e..e1dbab7c48 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java @@ -26,8 +26,8 @@ import jakarta.ws.rs.core.Response; import java.io.InputStream; import java.util.List; -import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.lib.AMSession; @@ -50,12 +50,10 @@ protected String getActuatorEndpoint() { @Override public List list() { try { - Response response = WebClient.create( - getActuatorEndpoint(), + Response response = WebClientBuilder.build(getActuatorEndpoint(), SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - accept(MediaType.APPLICATION_JSON_TYPE).get(); + List.of()).accept(MediaType.APPLICATION_JSON_TYPE).get(); if (response.getStatus() == Response.Status.OK.getStatusCode()) { JsonNode node = MAPPER.readTree((InputStream) response.getEntity()); if (node.has("activeSsoSessions")) { diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ConnectorRestClient.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ConnectorRestClient.java index bc69f0bc1d..99623f8935 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ConnectorRestClient.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ConnectorRestClient.java @@ -32,6 +32,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.lib.SyncopeClientException; import org.apache.syncope.common.lib.to.ConnIdBundle; import org.apache.syncope.common.lib.to.ConnIdObjectClass; @@ -173,7 +174,8 @@ protected List filterProperties(final Collection list() { List loggerConfs = new ArrayList<>(); try { - Response response = webClient(instances.get(0)).get(); + Response response = WebClientBuilder.build(getActuatorEndpoint(instances.get(0)), + SyncopeWebApplication.get().getAnonymousUser(), + SyncopeWebApplication.get().getAnonymousKey(), + List.of()).accept(MediaType.APPLICATION_JSON_TYPE).get(); if (response.getStatus() == Response.Status.OK.getStatusCode()) { JsonNode node = MAPPER.readTree((InputStream) response.getEntity()); if (node.has("loggers")) { @@ -114,6 +107,13 @@ public List list() { @Override public void setLevel(final String key, final LogLevel level) { - instances.forEach(i -> webClient(i).path(key).post("{\"configuredLevel\": \"" + level.name() + "\"}")); + instances.forEach(i -> WebClientBuilder.build(getActuatorEndpoint(i), + SyncopeWebApplication.get().getAnonymousUser(), + SyncopeWebApplication.get().getAnonymousKey(), + List.of()) + .accept(MediaType.APPLICATION_JSON_TYPE) + .type(MediaType.APPLICATION_JSON_TYPE) + .path(key) + .post("{\"configuredLevel\": \"" + level.name() + "\"}")); } } diff --git a/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeAnonymousClient.java b/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeAnonymousClient.java index 74acf7c22a..cb2febbd4e 100644 --- a/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeAnonymousClient.java +++ b/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/SyncopeAnonymousClient.java @@ -60,7 +60,7 @@ public SyncopeAnonymousClient( } public JsonNode info() throws IOException { - WebClient webClient = WebClient.create( + WebClient webClient = WebClientBuilder.build( StringUtils.removeEnd(restClientFactory.getAddress().replace("/rest", "/actuator/info"), "/")). accept(MediaType.APPLICATION_JSON_TYPE). header(RESTHeaders.DOMAIN, getDomain()). diff --git a/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/WebClientBuilder.java b/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/WebClientBuilder.java new file mode 100644 index 0000000000..003a467134 --- /dev/null +++ b/client/idrepo/lib/src/main/java/org/apache/syncope/client/lib/WebClientBuilder.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.syncope.client.lib; + +import java.net.URI; +import java.util.List; +import org.apache.cxf.jaxrs.client.ClientConfiguration; +import org.apache.cxf.jaxrs.client.WebClient; +import org.apache.cxf.transport.http.asyncclient.AsyncHTTPConduit; + +public final class WebClientBuilder { + + private WebClientBuilder() { + } + + public static WebClient build(final String address, + final String username, + final String password, + final List providers) { + return setAsync(WebClient.create(address, providers, username, password, null)); + } + + public static WebClient build(final String address) { + return setAsync(WebClient.create(address)); + } + + public static WebClient build(final URI uri) { + return setAsync(WebClient.create(uri)); + } + + protected static WebClient setAsync(final WebClient webClient) { + ClientConfiguration config = WebClient.getConfig(webClient); + config.getRequestContext().put(AsyncHTTPConduit.USE_ASYNC, Boolean.TRUE); + + return webClient; + } +} diff --git a/common/keymaster/self/client-self/pom.xml b/common/keymaster/self/client-self/pom.xml index 21c0cdaac1..bd07a65755 100644 --- a/common/keymaster/self/client-self/pom.xml +++ b/common/keymaster/self/client-self/pom.xml @@ -58,6 +58,10 @@ under the License. org.apache.cxf cxf-rt-features-logging + + org.apache.cxf + cxf-rt-transports-http-hc + com.fasterxml.jackson.jakarta.rs diff --git a/common/keymaster/self/client-self/src/main/java/org/apache/syncope/common/keymaster/client/self/SelfKeymasterOps.java b/common/keymaster/self/client-self/src/main/java/org/apache/syncope/common/keymaster/client/self/SelfKeymasterOps.java index 6cc5ec259b..8b98c77e90 100644 --- a/common/keymaster/self/client-self/src/main/java/org/apache/syncope/common/keymaster/client/self/SelfKeymasterOps.java +++ b/common/keymaster/self/client-self/src/main/java/org/apache/syncope/common/keymaster/client/self/SelfKeymasterOps.java @@ -31,6 +31,7 @@ import org.apache.cxf.transport.common.gzip.GZIPInInterceptor; import org.apache.cxf.transport.common.gzip.GZIPOutInterceptor; import org.apache.cxf.transport.http.HTTPConduit; +import org.apache.cxf.transport.http.asyncclient.AsyncHTTPConduit; import org.apache.cxf.transports.http.configuration.ConnectionType; import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; @@ -66,6 +67,7 @@ public T client(final Class serviceClass, final Map heade client.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON); ClientConfiguration config = WebClient.getConfig(client); + config.getRequestContext().put(AsyncHTTPConduit.USE_ASYNC, Boolean.TRUE); config.getInInterceptors().add(new GZIPInInterceptor()); config.getOutInterceptors().add(new GZIPOutInterceptor());