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

jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus-examples.git

commit 18b935d4142dcbb85a6e177ea9fe5b7dd9b7f88e
Author: Lukas Lowinger <[email protected]>
AuthorDate: Tue Dec 2 13:03:25 2025 +0100

    [resolves #7918] Demonstrate using CXF client producer
---
 cxf-soap/README.adoc                               | 37 +++++++++++
 cxf-soap/pom.xml                                   |  8 +++
 ...ilder.java => PojoCxfConsumerRouteBuilder.java} |  2 +-
 .../cxf/soap/pojo/PojoCxfProducerRouteBuilder.java | 70 ++++++++++++++++++++
 .../org/acme/cxf/soap/pojo/service/Contact.java    |  3 +
 .../org/acme/cxf/soap/pojo/service/Contacts.java   |  7 +-
 .../org/acme/cxf/soap/utils/CxfServerUtils.java}   | 11 ++--
 .../soap/{PojoClientTest.java => PojoTest.java}    | 74 +++++++++++++++++-----
 .../{PojoClientTestIT.java => PojoTestIT.java}     |  2 +-
 .../java/org/acme/cxf/soap/WsdlClientTest.java     |  5 +-
 10 files changed, 192 insertions(+), 27 deletions(-)

diff --git a/cxf-soap/README.adoc b/cxf-soap/README.adoc
index 981ec6ca..72b4b552 100644
--- a/cxf-soap/README.adoc
+++ b/cxf-soap/README.adoc
@@ -4,6 +4,8 @@
 {cq-description}
 
 In this example we will create two SOAP webservices with two different 
approaches. Both services will use Camel routes as service implementation 
exposed via CXF component.
+We will then communicate with the SOAP webservices (Camel consumer) directly 
via SOAP messages (ie. with `curl`).
+Later we will also leverage Camel producer to send SOAP messages to our 
exposed SOAP webservices.
 
 == WSDL first
 
@@ -36,6 +38,20 @@ The exposed contact web service will enable five operations 
- `addContact`, `get
 
 TIP: If you would like to only generate WSDL from Java, you can follow the 
https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/dev/user-guide/generate-wsdl-from-java.html[WSDL
 from Java] chapter of Quarkus CXF documentation.
 
+== Camel producer
+The approach mentioned above concerned the creation of SOAP webservices.
+We will also describe how to create a client using the Camel Quarkus CXF SOAP 
producer.
+You can observe `org.acme.cxf.soap.pojo.PojoCxfProducerRouteBuilder` where we 
are creating the `CxfEndpoint` which is used in the route in form of Camel 
producer.
+
+It can typically looks like:
+[source,java]
+----
+from("direct:contact")
+    .to("cxf:bean:soapClientEndpointPojo");
+----
+
+For purpose of easier testing this approach we also added Camel Quarkus REST 
endpoint which will be used as external entry point for invoking the producer.
+
 == Start in the Development mode
 
 [source,shell]
@@ -52,6 +68,7 @@ 
https://camel.apache.org/camel-quarkus/latest/first-steps.html#_development_mode
 [[playground]]
 
 == Playground
+=== Interacting directly via SOAP messages
 
 We can first try to add a contact with:
 
@@ -153,6 +170,26 @@ $ curl "http://localhost:8080/cxf/services/contact?wsdl";
 $ curl "http://localhost:8080/cxf/services/customer?wsdl";
 ----
 
+=== Interacting via Camel Quarkus CXF producer
+We can also use Camel producer to interact with our exposed SOAP webservice.
+For testing purpose, we've also exposed REST endpoints to easily approach it 
externally.
+
+Firstly we will add new contact with:
+[source, shell]
+----
+$ curl -X POST -H "Content-Type: application/json" --data 
'{"name":"Lukas","address":{"city":"Czech Republic","street":"Random 
Street"},"type":"OTHER"}' 
"http://localhost:8080/producer/contact?operationName=addContact";
+----
+Then we will request all contacts with:
+[source, shell]
+----
+$ curl -X GET 
"http://localhost:8080/producer/contacts?operationName=getContacts";
+----
+
+Which should return something like:
+```
+{"contacts":[{"name":"Lukas","address":{"city":"Czech 
Republic","street":"Random Street"},"type":"OTHER"}]}
+```
+
 == Package and run the application
 
 Once you are done with playing/developing you may want to package and run the 
application for production usage.
diff --git a/cxf-soap/pom.xml b/cxf-soap/pom.xml
index 97d82aed..625448b5 100644
--- a/cxf-soap/pom.xml
+++ b/cxf-soap/pom.xml
@@ -80,6 +80,14 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-direct</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-rest</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-jackson</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-bean</artifactId>
diff --git 
a/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/MyPojoRouteBuilder.java 
b/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/PojoCxfConsumerRouteBuilder.java
similarity index 96%
rename from 
cxf-soap/src/main/java/org/acme/cxf/soap/pojo/MyPojoRouteBuilder.java
rename to 
cxf-soap/src/main/java/org/acme/cxf/soap/pojo/PojoCxfConsumerRouteBuilder.java
index 37b26acf..dcec4cfa 100644
--- a/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/MyPojoRouteBuilder.java
+++ 
b/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/PojoCxfConsumerRouteBuilder.java
@@ -27,7 +27,7 @@ import org.apache.camel.component.cxf.jaxws.CxfEndpoint;
  * This class demonstrate how to expose a SOAP endpoint starting from java 
classes
  */
 @ApplicationScoped
-public class MyPojoRouteBuilder extends RouteBuilder {
+public class PojoCxfConsumerRouteBuilder extends RouteBuilder {
 
     @Produces
     @ApplicationScoped
diff --git 
a/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/PojoCxfProducerRouteBuilder.java
 
b/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/PojoCxfProducerRouteBuilder.java
new file mode 100644
index 00000000..8db54754
--- /dev/null
+++ 
b/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/PojoCxfProducerRouteBuilder.java
@@ -0,0 +1,70 @@
+/*
+ * 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.acme.cxf.soap.pojo;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.inject.Produces;
+import jakarta.inject.Named;
+import org.acme.cxf.soap.pojo.service.Contact;
+import org.acme.cxf.soap.pojo.service.ContactService;
+import org.acme.cxf.soap.pojo.service.Contacts;
+import org.acme.cxf.soap.utils.CxfServerUtils;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.cxf.common.DataFormat;
+import org.apache.camel.component.cxf.jaxws.CxfEndpoint;
+import org.apache.camel.model.dataformat.JsonLibrary;
+import org.apache.camel.model.rest.RestBindingMode;
+
+/**
+ * This class demonstrate how to use camel-quarkus-cxf-soap client
+ */
+@ApplicationScoped
+public class PojoCxfProducerRouteBuilder extends RouteBuilder {
+
+    @Produces
+    @ApplicationScoped
+    @Named
+    CxfEndpoint soapClientEndpointPojo() {
+        final CxfEndpoint result = new CxfEndpoint();
+        result.setDataFormat(DataFormat.POJO);
+        result.setServiceClass(ContactService.class);
+        
result.setAddress("%s/contact".formatted(CxfServerUtils.getServerUrl()));
+        return result;
+    }
+
+    @Override
+    public void configure() throws Exception {
+        restConfiguration()
+                .bindingMode(RestBindingMode.json);
+
+        rest("/producer/contact").post()
+                .type(Contact.class)
+                .to("direct:contact");
+        rest("/producer/contacts").get()
+                .bindingMode(RestBindingMode.off)
+                .produces("application/json")
+                .to("direct:contacts");
+
+        from("direct:contact")
+                .to("cxf:bean:soapClientEndpointPojo");
+
+        from("direct:contacts")
+                .to("cxf:bean:soapClientEndpointPojo")
+                .convertBodyTo(Contacts.class)
+                .marshal().json(JsonLibrary.Jackson);
+    }
+}
diff --git a/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/service/Contact.java 
b/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/service/Contact.java
index 6c02dbf1..9f2035d0 100644
--- a/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/service/Contact.java
+++ b/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/service/Contact.java
@@ -38,6 +38,9 @@ public class Contact {
     private Address address;
     private ContactType type;
 
+    public Contact() {
+    }
+
     public String getName() {
         return name;
     }
diff --git 
a/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/service/Contacts.java 
b/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/service/Contacts.java
index b633f779..df4612de 100644
--- a/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/service/Contacts.java
+++ b/cxf-soap/src/main/java/org/acme/cxf/soap/pojo/service/Contacts.java
@@ -16,6 +16,7 @@
  */
 package org.acme.cxf.soap.pojo.service;
 
+import java.util.ArrayList;
 import java.util.Collection;
 
 import jakarta.xml.bind.annotation.XmlAccessType;
@@ -28,14 +29,14 @@ import jakarta.xml.bind.annotation.XmlType;
 })
 public class Contacts {
 
-    private Collection<Contact> contacts;
+    private Collection<Contact> contacts = new ArrayList<>();
 
     public Contacts() {
     }
 
     public Contacts(Collection<Contact> contacts) {
         super();
-        this.contacts = contacts;
+        this.contacts = (contacts != null) ? contacts : new ArrayList<>();
     }
 
     public Collection<Contact> getContacts() {
@@ -43,6 +44,6 @@ public class Contacts {
     }
 
     public void setContacts(Collection<Contact> contacts) {
-        this.contacts = contacts;
+        this.contacts = (contacts != null) ? contacts : new ArrayList<>();
     }
 }
diff --git a/cxf-soap/src/test/java/org/acme/cxf/soap/BaseTest.java 
b/cxf-soap/src/main/java/org/acme/cxf/soap/utils/CxfServerUtils.java
similarity index 82%
rename from cxf-soap/src/test/java/org/acme/cxf/soap/BaseTest.java
rename to cxf-soap/src/main/java/org/acme/cxf/soap/utils/CxfServerUtils.java
index 445afe6e..dec296ad 100644
--- a/cxf-soap/src/test/java/org/acme/cxf/soap/BaseTest.java
+++ b/cxf-soap/src/main/java/org/acme/cxf/soap/utils/CxfServerUtils.java
@@ -14,17 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.acme.cxf.soap;
+package org.acme.cxf.soap.utils;
 
 import io.quarkus.runtime.LaunchMode;
 import org.eclipse.microprofile.config.Config;
 import org.eclipse.microprofile.config.ConfigProvider;
 
-public class BaseTest {
-    protected String getServerUrl() {
+public final class CxfServerUtils {
+    private CxfServerUtils() {
+    }
+
+    public static String getServerUrl() {
         Config config = ConfigProvider.getConfig();
         final int port = LaunchMode.current().equals(LaunchMode.TEST) ? 
config.getValue("quarkus.http.test-port", Integer.class)
                 : config.getValue("quarkus.http.port", Integer.class);
-        return String.format("http://localhost:%d";, port);
+        return "http://localhost:%d%s".formatted(port, 
config.getValue("quarkus.cxf.path", String.class));
     }
 }
diff --git a/cxf-soap/src/test/java/org/acme/cxf/soap/PojoClientTest.java 
b/cxf-soap/src/test/java/org/acme/cxf/soap/PojoTest.java
similarity index 53%
rename from cxf-soap/src/test/java/org/acme/cxf/soap/PojoClientTest.java
rename to cxf-soap/src/test/java/org/acme/cxf/soap/PojoTest.java
index 6d846ea5..c8cf04df 100644
--- a/cxf-soap/src/test/java/org/acme/cxf/soap/PojoClientTest.java
+++ b/cxf-soap/src/test/java/org/acme/cxf/soap/PojoTest.java
@@ -22,21 +22,49 @@ import java.net.URL;
 import javax.xml.namespace.QName;
 
 import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
 import jakarta.xml.ws.Service;
 import org.acme.cxf.soap.pojo.service.Address;
 import org.acme.cxf.soap.pojo.service.Contact;
 import org.acme.cxf.soap.pojo.service.ContactService;
 import org.acme.cxf.soap.pojo.service.ContactType;
 import org.acme.cxf.soap.pojo.service.NoSuchContactException;
+import org.acme.cxf.soap.utils.CxfServerUtils;
+import org.apache.camel.component.cxf.common.message.CxfConstants;
+import org.hamcrest.Matchers;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 @QuarkusTest
-public class PojoClientTest extends BaseTest {
+public class PojoTest {
+
+    protected static Contact createConsumerContact() {
+        Contact contact = new Contact();
+        contact.setName("Croway");
+        contact.setType(ContactType.OTHER);
+        Address address = new Address();
+        address.setCity("Rome");
+        address.setStreet("Test Street");
+        contact.setAddress(address);
+
+        return contact;
+    }
+
+    protected static Contact createProducerContact() {
+        Contact contact = new Contact();
+        contact.setName("Lukas");
+        contact.setType(ContactType.OTHER);
+        Address address = new Address();
+        address.setCity("Czech Republic");
+        address.setStreet("Random Street");
+        contact.setAddress(address);
+
+        return contact;
+    }
 
     protected ContactService createCXFClient() {
         try {
-            final URL serviceUrl = new URL(getServerUrl() + 
"/cxf/services/contact?wsdl");
+            final URL serviceUrl = new URL(CxfServerUtils.getServerUrl() + 
"/contact?wsdl");
             final QName qName = new QName(ContactService.TARGET_NS, 
ContactService.class.getSimpleName());
             final Service service = Service.create(serviceUrl, qName);
             return service.getPort(ContactService.class);
@@ -45,27 +73,41 @@ public class PojoClientTest extends BaseTest {
         }
     }
 
-    protected static Contact createContact() {
-        Contact contact = new Contact();
-        contact.setName("Croway");
-        contact.setType(ContactType.OTHER);
-        Address address = new Address();
-        address.setCity("Rome");
-        address.setStreet("Test Street");
-        contact.setAddress(address);
+    @Test
+    public void testPojoCamelConsumer() throws NoSuchContactException {
+        ContactService cxfClient = createCXFClient();
+        int countContactsStart = cxfClient.getContacts().getContacts().size();
+        cxfClient.addContact(createConsumerContact());
+        Assertions.assertSame(countContactsStart + 1, 
cxfClient.getContacts().getContacts().size(),
+                "We should have one contact added.");
 
-        return contact;
+        Assertions.assertNotNull(cxfClient.getContact("Croway"), "We haven't 
found contact.");
+
+        Assertions.assertThrows(NoSuchContactException.class, () -> 
cxfClient.getContact("Non existent"));
     }
 
     @Test
-    public void testBasic() throws NoSuchContactException {
+    public void testPojoCamelProducer() throws NoSuchContactException {
         ContactService cxfClient = createCXFClient();
+        int countContactsStart = cxfClient.getContacts().getContacts().size();
 
-        cxfClient.addContact(createContact());
-        Assertions.assertSame(1, cxfClient.getContacts().getContacts().size(), 
"We should have one contact.");
+        RestAssured.given()
+                .log().all()
+                .contentType("application/json")
+                .body(createProducerContact())
+                .queryParam(CxfConstants.OPERATION_NAME, "addContact")
+                .post("/producer/contact")
+                .then()
+                .statusCode(200);
 
-        Assertions.assertNotNull(cxfClient.getContact("Croway"), "We haven't 
found contact.");
+        RestAssured.given()
+                .contentType("application/json")
+                .queryParam(CxfConstants.OPERATION_NAME, "getContacts")
+                .get("/producer/contacts")
+                .then()
+                .statusCode(200)
+                .body("contacts.size()", Matchers.equalTo(countContactsStart + 
1));
 
-        Assertions.assertThrows(NoSuchContactException.class, () -> 
cxfClient.getContact("Non existent"));
+        Assertions.assertNotNull(cxfClient.getContact("Lukas"), "We haven't 
found contact.");
     }
 }
diff --git a/cxf-soap/src/test/java/org/acme/cxf/soap/PojoClientTestIT.java 
b/cxf-soap/src/test/java/org/acme/cxf/soap/PojoTestIT.java
similarity index 94%
rename from cxf-soap/src/test/java/org/acme/cxf/soap/PojoClientTestIT.java
rename to cxf-soap/src/test/java/org/acme/cxf/soap/PojoTestIT.java
index c57df864..e9e3f210 100644
--- a/cxf-soap/src/test/java/org/acme/cxf/soap/PojoClientTestIT.java
+++ b/cxf-soap/src/test/java/org/acme/cxf/soap/PojoTestIT.java
@@ -19,5 +19,5 @@ package org.acme.cxf.soap;
 import io.quarkus.test.junit.QuarkusIntegrationTest;
 
 @QuarkusIntegrationTest
-public class PojoClientTestIT extends PojoClientTest {
+public class PojoTestIT extends PojoTest {
 }
diff --git a/cxf-soap/src/test/java/org/acme/cxf/soap/WsdlClientTest.java 
b/cxf-soap/src/test/java/org/acme/cxf/soap/WsdlClientTest.java
index 78eafd99..6f4a7f77 100644
--- a/cxf-soap/src/test/java/org/acme/cxf/soap/WsdlClientTest.java
+++ b/cxf-soap/src/test/java/org/acme/cxf/soap/WsdlClientTest.java
@@ -25,6 +25,7 @@ import com.example.customerservice.CustomerService;
 import com.example.customerservice.NoSuchCustomerException;
 import io.quarkus.test.junit.QuarkusTest;
 import jakarta.xml.ws.soap.SOAPFaultException;
+import org.acme.cxf.soap.utils.CxfServerUtils;
 import org.apache.cxf.ext.logging.LoggingFeature;
 import org.apache.cxf.frontend.ClientProxyFactoryBean;
 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
@@ -37,12 +38,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 
 @QuarkusTest
-public class WsdlClientTest extends BaseTest {
+public class WsdlClientTest {
 
     CustomerService cxfClient;
 
     protected CustomerService createCustomerClient() {
-        String URL = getServerUrl() + "/cxf/services/customer";
+        String URL = CxfServerUtils.getServerUrl() + "/customer";
 
         ClientProxyFactoryBean factory = new JaxWsProxyFactoryBean();
         factory.setServiceClass(CustomerService.class);

Reply via email to