[[creating-a-soap-client]]
= SOAP Clients

include::./includes/attributes.adoc[]

Quarkus-CXF supports SOAP clients. Assuming a given Service Endpoint Interface (SEI) like `FruitWebService`, Quarkus-CXF is able to inject a ready-to-use client proxy:

[source,java]
----
import org.acme.FruitWebService;                   // SEI
import javax.enterprise.context.ApplicationScoped;
import io.quarkiverse.cxf.annotation.CXFClient;

@ApplicationScoped  // or any other CDI scope
public class MySoapClient {

    @Inject @CXFClient
    FruitWebService clientService;

    public int getCount() {
        return this.clientService.count();
    }
}
----

Without any further configuration Quarkus-CXF assumes a service to be published at http://localhost:8080/{service-path}, where `{service-path}` is derived from

* config property `quarkus.cxf.path` (if present); and the
* SEI’s lowercased class name

Given `quarkus.cxf.path=/ws`, Quarkus-CXF would use http://localhost:8080/ws/org.acme.fruitwebservice as `FruitWebService` 's endpoint URL and otherwise just  http://localhost:8080/ws/org.acme.fruitwebservice.


Various SOAP client properties can be configured. To do so, prefix `quarkus.cxf.client.{name}` creates a logical client configuration unit. The name of such a unit, here denoted as `{name}`, can be arbitrarily choosen as long as not (whitespace) empty. The following properties are available on such a configuration unit:

* `client-endpoint-url`
* `endpoint-name`
* `endpoint-namespace`
* `features`
* `handlers`
* `in-fault-interceptors`
* `in-interceptors`
* `out-fault-interceptors`
* `out-interceptors`
* `password`
* `service-interface`
* `username`
* `wsdl`

A typical example configuration example is given below. Here unit name `my-fruitservice-client` is used. The goal of this configuration is the change the service endpoint address to http://localhost:8080/fruit:
[source,properties]
----
quarkus.cxf.client."my-fruitservice-client".service-interface=org.acme.FruitWebService
quarkus.cxf.client."my-fruitservice-client".client-endpoint-url=http://localhost:8080/fruit
----

Another way of applying a client configuration is to use it directly:
[source,java]
----
@Inject @CXFClient("my-fruitservice-client")
FruitWebService clientService;
----

Here Quarkus-CXF uses configuration unit `my-fruitservice-client` for setting up a SOAP client `clientService` by scanning configuration units for a unit with that name. It is an error to use a unit name which does not exist.

If `@CXFClient` is used without a unit name Quarkus-CXF identifies matching configuration by scanning for a unit where property `service-interface` _matches_ the SEI to be injected. Such a matching configuration is the _default_ configuration for that SEI. The purpose of property `service-interface` is therefore to identify the matching SEI.

Default configurations must be unique per SEI while it is otherwise perfectly valid to have multiple client configuration units per SEI. Consider this example:

[source,properties]
----
quarkus.cxf.client."my-fruitservice-client".service-interface=org.acme.FruitWebService
quarkus.cxf.client."my-fruitservice-client".client-endpoint-url=http://localhost:8080/fruit

quarkus.cxf.client."my-featured-fruitservice-client".client-endpoint-url=http://localhost:8080/fruit
quarkus.cxf.client."my-featured-fruitservice-client".features=org.apache.cxf.feature.LoggingFeature
----

Here a second configuration named `my-featured-fruitservice-client` has been defined in addition to
`my-fruitservice-client`. This second configuration applies a standard CXF logging feature which can
be useful for tracing or debugging. An example for the purpose of illustration:
[source,java]
----
import org.acme.FruitWebService;
import javax.enterprise.context.ApplicationScoped;
import io.quarkiverse.cxf.annotation.CXFClient;

@ApplicationScoped    // or any other CDI scope
public class MySoapClient {

    private boolean logging = ..  // depending on context, logging is on or off

    @Inject @CXFClient("my-featured-fruitservice-client")
    FruitWebService featuredClientService;

    @Inject @CXFClient
    FruitWebService clientService;

    public int getCount() {
        return (logging ? featuredClientService : clientService).count();
    }
}
----

Notice the absence of property `service-interface` in `quarkus.cxf.client."my-featured-fruitservice-client"` because this configuration is meant to be an alternative to the default configuration.

Eventually a word of warning before closing this chapter. You may expect to get a SOAP client injected at this injection point
as well:

[source,java]
----
    @Inject
    FruitWebService clientService;
----

This is wrong. If your CDI container contains an implementation of `FruitWebService` then such an instance will be injected. If not, then CDI will complain about not suitable beans. Injection of an implementation can happen because Quarkus-CXF automatically adds CDI scope `@Dependent` on every class annotated
with `@WebService`, thus turing every webservice it encounters automatically into a CDI bean.

[[basic-auth]]
== Basic Auth

Basic auth for clients is supported by default. Just add the following properties to your `application.properties` file:

[source,properties]
----
quarkus.cxf.client."my-fruitservice-client".username=user
quarkus.cxf.client."my-fruitservice-client".password=password
----

[[async-support]]
== Asynchronous Client HTTP Transport

By default, the CXF client uses `HttpURLConnection` to perform HTTP requests.

In order to have non-blocking (asynchronous) invocations you can add the  `quarkus-cxf-rt-transports-http-hc5` dependency to your project.  This module provides full support for native mode.

[source,xml,subs=attributes+]
----
    <dependency>
      <groupId>io.quarkiverse.cxf</groupId>
      <artifactId>quarkus-cxf-rt-transports-http-hc5</artifactId>
      <version>{quarkus-cxf-version}</version>
    </dependency>
----

Once the dependency is available in the classpath, CXF will use `HttpAsyncClient` for asynchronous calls and will continue using `HttpURLConnection` for synchronous calls.

NOTE: You can see more details about the CXF asynchronous client and how to tune it further at https://cxf.apache.org/docs/asynchronous-client-http-transport.html[this link].

[[async-uni]]
== Asynchronous Clients and Unis

Asynchronous client invocations require stub code (dedicated asynchronous methods defined on the service endpoint interface). The stub code is not generated by default.

To switch on the asynchronous feature and generate the necessary stub code, you must use the JAX-WS `enableAsyncMapping` binding declaration.  A JAX-WS binding file can be created containing this customization, which can then be referenced in your wsdl2java code generation process.

Once the asynchronous stubs are available, it is possible to wrap a client call in a Uni as shown below:

[source,java]
----
    @Inject @CXFClient
    CalculatorSoap calculatorSoap;

    public Uni<AddResponse> addNumbers(Integer num1, Integer num2) {
        return Uni.createFrom().future(() ->
                (Future<AddResponse>)calculatorSoap.addAsync(num1, num2, res -> {}));
    }
----

NOTE: A sample application demonstrating this flow is provided https://github.com/quarkiverse/quarkus-cxf/issues/4#issuecomment-1106487964[here].


[[code-config]]
== Advanced Client Configurations

To globally configure all clients in your application, you can use the example snippet below to configure the https://cxf.apache.org/docs/client-http-transport-including-ssl-support.html#ClientHTTPTransport(includingSSLsupport)-Usingjavacode[`HttpConduit`].  This allows you to set the `HTTPClientPolicy`, `AuthorizationPolicy`, `ProxyAuthorizationPolicy` or even `TLSClientParameters` for your clients.
[source,java]
----
void onStart(@Observes StartupEvent ev) {

     HTTPConduitConfigurer httpConduitConfigurer = new HTTPConduitConfigurer() {
         public void configure(String name, String address, HTTPConduit c) {
             AsyncHTTPConduit conduit = (AsyncHTTPConduit)c;
             // use setter to configure client
             conduit.getHttpAsyncClient().getCredentialsProvider().setCredentials( AuthScope.ANY,
              new NTCredentials( USER,PWD, "", DOM ) );
             conduit.getClient().setAllowChunking( false );
             conduit.getClient().setAutoRedirect( true );
         }
     };

     final Bus bus = BusFactory.getThreadDefaultBus();
     bus.setExtension(httpConduitConfigurer, HTTPConduitConfigurer.class);
 }
----

To configure the `HttpConduit` for a single client in your application, use the example snippet below:

[source,java]
----
    @Inject
    @CXFClient
    SomePortType portType;

    @PostConstruct
    void configurePortType() throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
        final var httpConduit = (HTTPConduit) ClientProxy.getClient(portType).getConduit();
        final var tlsClientParameters = Optional.ofNullable(httpConduit.getTlsClientParameters()).orElseGet(TLSClientParameters::new);
        tlsClientParameters.setCertAlias(config.clientCert().keyAlias());
        tlsClientParameters.setKeyManagers(clientKeyManagers);
        tlsClientParameters.setTrustManagers(clientTrustManagers);
        httpConduit.setTlsClientParameters(tlsClientParameters);
    }
----


[[pure-client]]
== Pure Client Applications

Quarkus batch (e.g. periodically scheduled), or command line applications, may sometimes not require an HTTP server to be launched at startup.  To disable listenening on a `host:port`, you can use the property below:

[source,properties]
----
quarkus.http.host-enabled=false
----