This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch camel-quarkus-main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus-examples.git
The following commit(s) were added to refs/heads/camel-quarkus-main by this
push:
new 0beca296 [resolves #7918] Demonstrate using CXF client producer
0beca296 is described below
commit 0beca296c9bb9711ce4fc9ad5cae283a9604fe42
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);