Within the project directory, create the src/generated/java
folder where the Java classes will be generated from XML files and schemas.
mkdir -p src/generated/java
Next, create the src/main/resources/wsdl
folder where the WSDL file will be stored.
mkdir -p src/main/resources/wsdl
Now, it's necessary to configure the pom.xml
file to generate the Java classes from the CalculatorService.wsdl
file.
<properties>
<cxf.version>4.0.2.fuse-redhat-00055</cxf.version>
</properties>
<build>
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<sourceRoot>${basedir}/src/generated/java</sourceRoot>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/wsdl/CalculatorService.wsdl</wsdl>
<faultSerialVersionUID>1</faultSerialVersionUID>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
This command uses Maven to automatically generate the necessary Java classes based on the provided WSDL in your project.
mvn generate-sources
Then, add the dependency camel-quarkus-cxf-soap
, which is a Camel Quarkus extension that provides capabilities to integrate SOAP web services using Apache CXF.
mvn quarkus:add-extension -Dextension=org.apache.camel.quarkus:camel-quarkus-cxf-soap
Finally, create the SoapClientConfiguration.java
class to automatically map the required configuration properties. This class will facilitate configuring the SOAP client in your application.
package com.redhat.quarkus.platform;
import io.smallrye.config.ConfigMapping;
@ConfigMapping(prefix = "soap")
public interface SoapClientConfiguration {
String operationName();
String operationNamespace();
String operationAddress();
String operationWsdlURL();
}
Update the application.properties
file with the corresponding values:
soap.operation-name=Add
soap.operation-namespace=http://tempuri.org/
soap.operation-address=http://www.dneonline.com/calculator.asmx
soap.operation-wsdl-url=wsdl/CalculatorService.wsdl
To enable the implementation of RESTful services using Apache Camel with Quarkus, it is necessary to add the camel-quarkus-rest
dependency. With this extension, you can easily create REST endpoints and efficiently handle HTTP requests in your Quarkus application.
mvn quarkus:add-extension -Dextension=org.apache.camel.quarkus:camel-quarkus-rest
Furthermore, to log important messages and events during your application's execution and effectively diagnose issues, it is recommended to add the camel-quarkus-log
dependency.
mvn quarkus:add-extension -Dextension=org.apache.camel.quarkus:camel-quarkus-log
If you want to enable message routing within the same JVM, you can add the camel-quarkus-direct
dependency.
mvn quarkus:add-extension -Dextension=org.apache.camel.quarkus:camel-quarkus-direct
Finally, to leverage existing CDI beans in your Quarkus application and use them within your Camel routes to process messages flexibly and efficiently, it is recommended to add the camel-quarkus-bean
dependency.
mvn quarkus:add-extension -Dextension=org.apache.camel.quarkus:camel-quarkus-bean
Create the SoapClientResource.java
class for consuming the SOAP service.
package com.redhat.quarkus.platform;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.cxf.common.message.CxfConstants;
import org.apache.camel.component.cxf.jaxws.CxfEndpoint;
import org.tempuri.CalculatorSoap;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.SessionScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@ApplicationScoped
public class SoapClientResource extends RouteBuilder {
@Inject
SoapClientConfiguration configuration;
@Override
public void configure() throws Exception {
rest()
.post("/add")
.routeId("RouteRest")
.consumes("application/json")
.produces("application/json")
.to("direct:consumeSoapService");
from("direct:consumeSoapService")
.routeId("RouteSoap")
.setBody(constant(new Object[] {10, 20}))
.log("[REQUEST] Received POST with parameters: [ ${body[0]} - ${body[1]} ]")
.setHeader(CxfConstants.OPERATION_NAME, constant(configuration.operationName()))
.setHeader(CxfConstants.OPERATION_NAMESPACE, constant(configuration.operationNamespace()))
.to("cxf:bean:calculatorSoapEndpoint?dataFormat=POJO")
.log("[RESPONSE] Received POST with parameters: ${body}");
}
@Produces
@SessionScoped
@Named("calculatorSoapEndpoint")
CxfEndpoint calculatorSoapEndpoint() throws Exception {
final CxfEndpoint result = new CxfEndpoint();
result.setServiceClass(CalculatorSoap.class);
result.setAddress(configuration.operationAddress());
result.setWsdlURL(configuration.operationWsdlURL());
return result;
}
}
Run the following command to consume a REST service that internally calls the SOAP service:
curl -s -X POST 'http://localhost:8080/add' --header 'Content-Type: application/json'
We review the logs:
INFO [RouteSoap] (vert.x-worker-thread-1) [REQUEST] Received POST with parameters: [ 10 - 20 ]
INFO [RouteSoap] (default-workqueue-1) [RESPONSE] Received POST with parameters: 30
To facilitate JSON serialization and deserialization, add the camel-quarkus-jackson
dependency.
mvn quarkus:add-extension -Dextension=org.apache.camel.quarkus:camel-quarkus-jackson
Create the RequestSoapDao.java
class to perform mapping of the fields that will be used as the request body.
package com.redhat.quarkus.platform;
import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection
public class RequestSoapDao {
public int param1;
public int param2;
public Object[] getOperation() {
return new Object[]{param1, param2};
}
}
Update the configure()
method to receive a JSON and convert it into a POJO using the RequestSoapDao.java
class. Respond with a JSON containing the sum of the values.
...output omitted...
@Override
public void configure() throws Exception {
rest()
.post("/add")
.routeId("RouteRest")
.consumes("application/json")
.produces("application/json")
.to("direct:consumeSoapService");
from("direct:consumeSoapService")
.routeId("RouteSoap")
//.setBody(constant(new Object[] {10, 20}))
.log("[REQUEST] Received POST with parameters: ${body}")
.unmarshal().json(JsonLibrary.Jackson, RequestSoapDao.class)
.log("[REQUEST] Data transformation: ${body}")
.setBody(simple("${body.getOperation}"))
.setHeader(CxfConstants.OPERATION_NAME, constant(configuration.operationName()))
.setHeader(CxfConstants.OPERATION_NAMESPACE, constant(configuration.operationNamespace()))
.to("cxf:bean:calculatorSoapEndpoint?dataFormat=POJO")
.log("[RESPONSE] Received POST with parameters: ${body}")
.convertBodyTo(String.class)
.marshal().json(JsonLibrary.Jackson)
.setBody(simple("{\"message\":${body}}"))
.log("[RESPONSE] Data transformation: ${body}");
}
...output omitted...
Run the following command to consume the REST service that internally calls the SOAP service:
curl -s -X POST 'http://localhost:8080/add' --header 'Content-Type: application/json' \
--data '{"param1": 10, "param2": 20}' | jq
The response from the service will be:
{
"message": "30"
}
We review the logs:
INFO [RouteSoap] (vert.x-worker-thread-1) [REQUEST] Received POST with parameters: {"param1": 10, "param2": 20}
INFO [RouteSoap] (vert.x-worker-thread-1) [REQUEST] Data transformation: com.redhat.quarkus.platform.RequestSoapDao@bbd0b26
INFO [RouteSoap] (default-workqueue-1) [RESPONSE] Received POST with parameters: 30
INFO [RouteSoap] (default-workqueue-1) [RESPONSE] Data transformation: {"message":"30"}
Conclusion
Configuring SOAP web services with Apache Camel on Quarkus offers a robust and efficient solution for integrating services into modern applications. Through the practices shared in this article, developers can effectively create Quarkus projects, consume SOAP services easily, and expose RESTful endpoints agilely. The combination of Apache Camel and Quarkus provides a versatile platform for building scalable and flexible applications. With integrated management of JSON data serialization and deserialization, developers can build comprehensive solutions that meet the needs of their projects.