This is an automated email from the ASF dual-hosted git repository.

pvillard31 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new af81f18baab NIFI-15911 Add Web Client Service for Snowflake Ingest 
Service (#11369)
af81f18baab is described below

commit af81f18baabdeb987eafd344648a15d9ba60c936
Author: David Handermann <[email protected]>
AuthorDate: Thu Jun 25 09:40:45 2026 -0500

    NIFI-15911 Add Web Client Service for Snowflake Ingest Service (#11369)
---
 .../nifi-snowflake-services/pom.xml                |  14 +++
 .../snowflake/service/SnowpipeIngestClient.java    | 115 ++++++++++-----------
 ...ndardSnowflakeIngestManagerProviderService.java |  36 ++++---
 .../service/SnowpipeIngestClientTest.java          |   8 +-
 ...ndardSnowflakeIngestManagerProviderService.java |  25 ++++-
 5 files changed, 122 insertions(+), 76 deletions(-)

diff --git 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/pom.xml 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/pom.xml
index 1a2dd5e1e97..d6884454068 100644
--- 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/pom.xml
+++ 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/pom.xml
@@ -69,6 +69,14 @@
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-oauth2-provider-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-web-client-provider-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-web-client-api</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.nifi</groupId>
@@ -89,5 +97,11 @@
             <artifactId>mockwebserver3-junit5</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-web-client</artifactId>
+            <version>2.11.0-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/main/java/org/apache/nifi/snowflake/service/SnowpipeIngestClient.java
 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/main/java/org/apache/nifi/snowflake/service/SnowpipeIngestClient.java
index c9406556869..5e805a65bd9 100644
--- 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/main/java/org/apache/nifi/snowflake/service/SnowpipeIngestClient.java
+++ 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/main/java/org/apache/nifi/snowflake/service/SnowpipeIngestClient.java
@@ -22,23 +22,21 @@ import 
com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.nifi.processors.snowflake.snowpipe.InsertFiles;
 import org.apache.nifi.processors.snowflake.snowpipe.InsertReport;
+import org.apache.nifi.web.client.api.HttpResponseEntity;
+import org.apache.nifi.web.client.api.WebClientService;
+import org.apache.nifi.web.client.api.WebClientServiceException;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-import java.net.http.HttpResponse;
-import java.time.Duration;
 import java.util.Objects;
 import java.util.UUID;
 
 /**
  * Client for Snowflake Snowpipe REST API using Java HttpClient
  */
-class SnowpipeIngestClient implements AutoCloseable {
-
-    private static final Duration CONNECT_TIMEOUT = Duration.ofSeconds(10);
+class SnowpipeIngestClient {
 
     private static final String INSERT_FILES_PATH = 
"/v1/data/pipes/%s/insertFiles";
 
@@ -56,7 +54,7 @@ class SnowpipeIngestClient implements AutoCloseable {
 
     private static final ObjectMapper objectMapper = new 
ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
 
-    private final HttpClient httpClient;
+    private final WebClientService webClientService;
 
     private final URI insertFilesUri;
 
@@ -74,11 +72,13 @@ class SnowpipeIngestClient implements AutoCloseable {
     SnowpipeIngestClient(
             final URI baseUri,
             final String pipeName,
-            final RSAKeyAuthorizationProvider authorizationProvider
+            final RSAKeyAuthorizationProvider authorizationProvider,
+            final WebClientService webClientService
     ) {
         Objects.requireNonNull(baseUri, "Base URI required");
         Objects.requireNonNull(pipeName, "Pipe Name required");
         Objects.requireNonNull(authorizationProvider, "Authorization Provider 
required");
+        Objects.requireNonNull(webClientService, "Web Service Client 
required");
 
         final String insertFilesPath = INSERT_FILES_PATH.formatted(pipeName);
         this.insertFilesUri = baseUri.resolve(insertFilesPath);
@@ -87,14 +87,7 @@ class SnowpipeIngestClient implements AutoCloseable {
         this.insertReportUri = baseUri.resolve(insertReportPath);
 
         this.authorizationProvider = authorizationProvider;
-        this.httpClient = HttpClient.newBuilder()
-                .connectTimeout(CONNECT_TIMEOUT)
-                .build();
-    }
-
-    @Override
-    public void close() {
-        httpClient.close();
+        this.webClientService = webClientService;
     }
 
     /**
@@ -110,18 +103,25 @@ class SnowpipeIngestClient implements AutoCloseable {
         final URI requestUri = appendRequestId(insertFilesUri);
         final String authorization = 
authorizationProvider.getRequestAuthorization().authorization();
 
-        final HttpRequest request = HttpRequest.newBuilder()
-                .uri(requestUri)
-                .header(AUTHORIZATION_HEADER, authorization)
-                .header(CONTENT_TYPE_HEADER, APPLICATION_JSON)
-                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
-                .build();
-
-        final HttpResponse<String> response = sendRequest(request);
-        final int statusCode = response.statusCode();
-        if (statusCode != HttpURLConnection.HTTP_OK) {
-            final String message = "Insert Files POST [%s] HTTP %d Response 
[%s]".formatted(requestUri, statusCode, response.body());
-            throw new SnowpipeResponseException(message);
+        try (
+                HttpResponseEntity responseEntity = webClientService.post()
+                        .uri(requestUri)
+                        .header(AUTHORIZATION_HEADER, authorization)
+                        .header(CONTENT_TYPE_HEADER, APPLICATION_JSON)
+                        .body(requestBody)
+                        .retrieve();
+                InputStream responseBodyStream = responseEntity.body()
+        ) {
+            final int statusCode = responseEntity.statusCode();
+            if (statusCode != HttpURLConnection.HTTP_OK) {
+                final byte[] responseBodyBytes = 
responseBodyStream.readAllBytes();
+                final String responseBody = new String(responseBodyBytes);
+                final String message = "Insert Files POST [%s] HTTP %d 
Response [%s]".formatted(requestUri, statusCode, responseBody);
+                throw new SnowpipeResponseException(message);
+            }
+        } catch (final IOException | WebClientServiceException e) {
+            final String message = "Insert Files POST [%s] request 
failed".formatted(requestUri);
+            throw new SnowpipeResponseException(message, e);
         }
     }
 
@@ -135,26 +135,34 @@ class SnowpipeIngestClient implements AutoCloseable {
         final URI requestUri = appendRequestId(insertReportUri);
         final String authorization = 
authorizationProvider.getRequestAuthorization().authorization();
 
-        final HttpRequest request = HttpRequest.newBuilder()
-                .uri(requestUri)
-                .header(AUTHORIZATION_HEADER, authorization)
-                .header(ACCEPT_HEADER, APPLICATION_JSON)
-                .GET()
-                .build();
-
-        final HttpResponse<String> response = sendRequest(request);
-        final int statusCode = response.statusCode();
-        final String responseBody = response.body();
-        if (statusCode == HttpURLConnection.HTTP_OK) {
-            try {
-                return objectMapper.readValue(responseBody, 
InsertReport.class);
-            } catch (final JsonProcessingException e) {
-                final String message = "Insert Report [%s] response parsing 
failed [%s]".formatted(requestUri, responseBody);
-                throw new SnowpipeResponseException(message, e);
+        try (
+                HttpResponseEntity responseEntity = webClientService.get()
+                        .uri(requestUri)
+                        .header(AUTHORIZATION_HEADER, authorization)
+                        .header(ACCEPT_HEADER, APPLICATION_JSON)
+                        .retrieve();
+                InputStream responseBodyStream = responseEntity.body()
+        ) {
+            final int statusCode = responseEntity.statusCode();
+
+            final byte[] responseBodyBytes = responseBodyStream.readAllBytes();
+            final String responseBody = new String(responseBodyBytes);
+
+            if (statusCode == HttpURLConnection.HTTP_OK) {
+                try {
+                    return objectMapper.readValue(responseBody, 
InsertReport.class);
+                } catch (final JsonProcessingException e) {
+                    final String message = "Insert Report [%s] response 
parsing failed [%s]".formatted(requestUri, responseBody);
+                    throw new SnowpipeResponseException(message, e);
+                }
+            } else {
+                final String message = "Insert Report failed GET [%s] HTTP %d 
Response [%s]".formatted(requestUri, statusCode, responseBody);
+                throw new SnowpipeResponseException(message);
             }
-        } else {
-            final String message = "Insert Report failed GET [%s] HTTP %d 
Response [%s]".formatted(requestUri, statusCode, responseBody);
-            throw new SnowpipeResponseException(message);
+
+        } catch (final IOException | WebClientServiceException e) {
+            final String message = "Insert Report [%s] request 
failed".formatted(requestUri);
+            throw new SnowpipeResponseException(message, e);
         }
     }
 
@@ -166,17 +174,6 @@ class SnowpipeIngestClient implements AutoCloseable {
         }
     }
 
-    private HttpResponse<String> sendRequest(final HttpRequest request) {
-        try {
-            return httpClient.send(request, 
HttpResponse.BodyHandlers.ofString());
-        } catch (final IOException e) {
-            throw new SnowpipeResponseException("Request failed for URI 
[%s]".formatted(request.uri()), e);
-        } catch (final InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new SnowpipeResponseException("Request interrupted for URI 
[%s]".formatted(request.uri()), e);
-        }
-    }
-
     private URI appendRequestId(final URI baseUri) {
         final String requestId = UUID.randomUUID().toString();
         final String uriString = REQUEST_ID_FORMAT.formatted(baseUri, 
requestId);
diff --git 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/main/java/org/apache/nifi/snowflake/service/StandardSnowflakeIngestManagerProviderService.java
 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/main/java/org/apache/nifi/snowflake/service/StandardSnowflakeIngestManagerProviderService.java
index d7d0b049f86..a703cff2928 100644
--- 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/main/java/org/apache/nifi/snowflake/service/StandardSnowflakeIngestManagerProviderService.java
+++ 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/main/java/org/apache/nifi/snowflake/service/StandardSnowflakeIngestManagerProviderService.java
@@ -19,7 +19,6 @@ package org.apache.nifi.snowflake.service;
 
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
-import org.apache.nifi.annotation.lifecycle.OnDisabled;
 import org.apache.nifi.annotation.lifecycle.OnEnabled;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.controller.AbstractControllerService;
@@ -36,11 +35,15 @@ import org.apache.nifi.reporting.InitializationException;
 import org.apache.nifi.snowflake.service.util.AccountIdentifierFormat;
 import 
org.apache.nifi.snowflake.service.util.AccountIdentifierFormatParameters;
 import org.apache.nifi.snowflake.service.util.ConnectionUrlFormat;
+import org.apache.nifi.web.client.api.WebClientService;
+import org.apache.nifi.web.client.provider.api.WebClientServiceProvider;
 
 import java.net.URI;
 import java.security.PrivateKey;
 import java.security.interfaces.RSAPrivateCrtKey;
 import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 
 @Tags({"snowflake", "snowpipe", "database", "connection"})
 @CapabilityDescription("Provides a Snowflake Ingest Manager for Snowflake pipe 
processors")
@@ -106,6 +109,13 @@ public class StandardSnowflakeIngestManagerProviderService 
extends AbstractContr
             .required(true)
             .build();
 
+    public static final PropertyDescriptor WEB_CLIENT_SERVICE_PROVIDER = new 
PropertyDescriptor.Builder()
+            .name("Web Client Service Provider")
+            .description("Provider implementation for Web Client Service 
supporting HTTP request and response handling")
+            .identifiesControllerService(WebClientServiceProvider.class)
+            .required(true)
+            .build();
+
     public static final PropertyDescriptor DATABASE = new 
PropertyDescriptor.Builder()
             .fromPropertyDescriptor(SnowflakeProperties.DATABASE)
             .required(true)
@@ -134,6 +144,7 @@ public class StandardSnowflakeIngestManagerProviderService 
extends AbstractContr
             ACCOUNT_NAME,
             USER_NAME,
             PRIVATE_KEY_SERVICE,
+            WEB_CLIENT_SERVICE_PROVIDER,
             DATABASE,
             SCHEMA,
             PIPE
@@ -147,13 +158,13 @@ public class 
StandardSnowflakeIngestManagerProviderService extends AbstractContr
 
     private static final char HYPHEN = '-';
 
+    private volatile SnowpipeIngestClient ingestClient;
+
     @Override
     protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
         return PROPERTY_DESCRIPTORS;
     }
 
-    private volatile SnowpipeIngestClient ingestClient;
-
     @OnEnabled
     public void onEnabled(final ConfigurationContext context) throws 
InitializationException {
         final String user = 
context.getProperty(USER_NAME).evaluateAttributeExpressions().getValue();
@@ -173,20 +184,15 @@ public class 
StandardSnowflakeIngestManagerProviderService extends AbstractContr
 
             final URI baseUri = 
URI.create(HTTPS_URI_FORMAT.formatted(hostNormalized));
             final RSAKeyAuthorizationProvider authorizationProvider = new 
RSAKeyAuthorizationProvider(account, user, rsaPrivateKey);
-            ingestClient = new SnowpipeIngestClient(baseUri, 
qualifiedPipeName, authorizationProvider);
+
+            final WebClientServiceProvider webClientServiceProvider = 
context.getProperty(WEB_CLIENT_SERVICE_PROVIDER).asControllerService(WebClientServiceProvider.class);
+            final WebClientService webClientService = 
webClientServiceProvider.getWebClientService();
+            ingestClient = new SnowpipeIngestClient(baseUri, 
qualifiedPipeName, authorizationProvider, webClientService);
         } else {
             throw new InitializationException("RSA Private Key not provided");
         }
     }
 
-    @OnDisabled
-    public void onDisabled() {
-        if (ingestClient != null) {
-            ingestClient.close();
-            ingestClient = null;
-        }
-    }
-
     @Override
     public void insertFiles(final InsertFiles insertFiles) {
         ingestClient.insertFiles(insertFiles);
@@ -211,6 +217,12 @@ public class StandardSnowflakeIngestManagerProviderService 
extends AbstractContr
         
config.renameProperty(SnowflakeProperties.OLD_ACCOUNT_NAME_PROPERTY_NAME, 
SnowflakeProperties.ACCOUNT_NAME.getName());
         config.renameProperty(SnowflakeProperties.OLD_DATABASE_PROPERTY_NAME, 
SnowflakeProperties.DATABASE.getName());
         config.renameProperty(SnowflakeProperties.OLD_SCHEMA_PROPERTY_NAME, 
SnowflakeProperties.SCHEMA.getName());
+
+        final Optional<String> webClientServiceProviderConfigured = 
config.getPropertyValue(WEB_CLIENT_SERVICE_PROVIDER);
+        if (webClientServiceProviderConfigured.isEmpty()) {
+            final String webClientServiceProviderId = 
config.createControllerService("org.apache.nifi.web.client.provider.service.StandardWebClientServiceProvider",
 Map.of());
+            config.setProperty(WEB_CLIENT_SERVICE_PROVIDER, 
webClientServiceProviderId);
+        }
     }
 
     private AccountIdentifierFormatParameters 
getAccountIdentifierFormatParameters(ConfigurationContext context) {
diff --git 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/test/java/org/apache/nifi/snowflake/service/SnowpipeIngestClientTest.java
 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/test/java/org/apache/nifi/snowflake/service/SnowpipeIngestClientTest.java
index 57cb5dd082b..bc01314d763 100644
--- 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/test/java/org/apache/nifi/snowflake/service/SnowpipeIngestClientTest.java
+++ 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/test/java/org/apache/nifi/snowflake/service/SnowpipeIngestClientTest.java
@@ -26,6 +26,7 @@ import 
org.apache.nifi.processors.snowflake.snowpipe.InsertFile;
 import org.apache.nifi.processors.snowflake.snowpipe.InsertFileStatus;
 import org.apache.nifi.processors.snowflake.snowpipe.InsertFiles;
 import org.apache.nifi.processors.snowflake.snowpipe.InsertReport;
+import org.apache.nifi.web.client.StandardWebClientService;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -128,6 +129,8 @@ class SnowpipeIngestClientTest {
     @StartStop
     public final MockWebServer mockWebServer = new MockWebServer();
 
+    private StandardWebClientService webClientService;
+
     private SnowpipeIngestClient client;
 
     @BeforeEach
@@ -135,12 +138,13 @@ class SnowpipeIngestClientTest {
         final URI baseUri = 
URI.create(HTTP_URI_FORMAT.formatted(mockWebServer.getHostName(), 
mockWebServer.getPort()));
         final RSAPrivateCrtKey privateKey = generatePrivateKey();
         final RSAKeyAuthorizationProvider authProvider = new 
RSAKeyAuthorizationProvider(ACCOUNT, USER, privateKey);
-        client = new SnowpipeIngestClient(baseUri, PIPE_NAME, authProvider);
+        webClientService = new StandardWebClientService();
+        client = new SnowpipeIngestClient(baseUri, PIPE_NAME, authProvider, 
webClientService);
     }
 
     @AfterEach
     void closeClient() {
-        client.close();
+        webClientService.close();
     }
 
     @Test
diff --git 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/test/java/org/apache/nifi/snowflake/service/TestStandardSnowflakeIngestManagerProviderService.java
 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/test/java/org/apache/nifi/snowflake/service/TestStandardSnowflakeIngestManagerProviderService.java
index cdb25ff4a02..c5defe1f11e 100644
--- 
a/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/test/java/org/apache/nifi/snowflake/service/TestStandardSnowflakeIngestManagerProviderService.java
+++ 
b/nifi-extension-bundles/nifi-snowflake-bundle/nifi-snowflake-services/src/test/java/org/apache/nifi/snowflake/service/TestStandardSnowflakeIngestManagerProviderService.java
@@ -28,6 +28,9 @@ import 
org.apache.nifi.processors.snowflake.snowpipe.InsertReport;
 import org.apache.nifi.processors.snowflake.util.SnowflakeProperties;
 import org.apache.nifi.util.MockPropertyConfiguration;
 import org.apache.nifi.util.PropertyMigrationResult;
+import org.apache.nifi.web.client.StandardWebClientService;
+import org.apache.nifi.web.client.api.WebClientService;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
@@ -40,8 +43,10 @@ import java.security.NoSuchAlgorithmException;
 import java.security.interfaces.RSAPrivateCrtKey;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -101,11 +106,19 @@ public class 
TestStandardSnowflakeIngestManagerProviderService {
     @StartStop
     public final MockWebServer mockWebServer = new MockWebServer();
 
+    private StandardWebClientService webClientService;
+
     private SnowpipeIngestClient client;
 
     @BeforeEach
     void setUp() throws NoSuchAlgorithmException {
-        client = createClient(mockWebServer);
+        webClientService = new StandardWebClientService();
+        client = createClient(mockWebServer, webClientService);
+    }
+
+    @AfterEach
+    void closeClient() {
+        webClientService.close();
     }
 
     @Test
@@ -134,6 +147,12 @@ public class 
TestStandardSnowflakeIngestManagerProviderService {
         final Map<String, String> propertiesRenamed = 
result.getPropertiesRenamed();
 
         assertEquals(expectedRenamed, propertiesRenamed);
+
+        final Set<MockPropertyConfiguration.CreatedControllerService> 
createdControllerServices = result.getCreatedControllerServices();
+        assertFalse(createdControllerServices.isEmpty());
+
+        final MockPropertyConfiguration.CreatedControllerService 
createdControllerService = createdControllerServices.iterator().next();
+        
assertTrue(createdControllerService.implementationClassName().endsWith("StandardWebClientServiceProvider"));
     }
 
     @Test
@@ -202,12 +221,12 @@ public class 
TestStandardSnowflakeIngestManagerProviderService {
         
assertTrue(exception.getMessage().contains(String.valueOf(HttpURLConnection.HTTP_NOT_FOUND)));
     }
 
-    private static SnowpipeIngestClient createClient(final MockWebServer 
mockWebServer) throws NoSuchAlgorithmException {
+    private static SnowpipeIngestClient createClient(final MockWebServer 
mockWebServer, final WebClientService webClientService) throws 
NoSuchAlgorithmException {
         final URI baseUri = 
URI.create(HTTP_URI_FORMAT.formatted(mockWebServer.getHostName(), 
mockWebServer.getPort()));
         final KeyPairGenerator keyPairGenerator = 
KeyPairGenerator.getInstance(KEY_ALGORITHM);
         final KeyPair keyPair = keyPairGenerator.generateKeyPair();
         final RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey) 
keyPair.getPrivate();
         final RSAKeyAuthorizationProvider authProvider = new 
RSAKeyAuthorizationProvider(ACCOUNT, USER, privateKey);
-        return new SnowpipeIngestClient(baseUri, PIPE_NAME, authProvider);
+        return new SnowpipeIngestClient(baseUri, PIPE_NAME, authProvider, 
webClientService);
     }
 }

Reply via email to