blob: 981ec6ca028c1fba9c3832cc5e9187ecc0ee7e0b [file] [log] [blame]
= Camel Quarkus CXF SOAP example
:cq-example-description: An example that shows how to use Camel CXF SOAP component.
{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.
== WSDL first
The "WSDL first" approach presupposes writing the link:src/main/resources/wsdl/CustomerService.wsdl[WSDL file] manually at the beginning of the SOAP service design.
Then we can use link:pom.xml#L231[the `generate-code` goal] of `quarkus-maven-plugin` to generate the Java classes for us.
The `wsdl2java` tool is used under the hood and its configuration can be found in link:src/main/resources/application.properties#L28[application.properties].
The customer web service is exposed via Camel route endpoint `cxf:bean:customer`.
Its logic is implemented directly in the route by delegating to `org.acme.cxf.soap.wsdl.repository.CustomerRepository`.
The endpoint supports two SOAP operations: `getCustomersByName` and `updateCustomer`.
NOTE: Most modern IDEs will be able to discover the generared classes automatically.
You may want to check some occurrences of those in `org.acme.cxf.soap.wsdl.repository.CustomerRepository`.
TIP: More information about generating Java classes from WSDL can be found in https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/dev/user-guide/generate-java-from-wsdl.html[Java from WSDL] chapter of Quarkus CXF documentation.
=== Binding (Advanced)
For illustrating how other `wsdl2java` options could be applied via link:src/main/resources/application.properties#L29[`quarkus.cxf.codegen.wsdl2java.additional-params`], we have added a custom binding defined in link:src/main/resources/binding.xml[binding.xml].
It instructs CXF to use `LocalDate` (more common in Java world) instead of default XML Date representation `XMLGregorianCalendar`.
== Java first
If you don't have the WSDL file upfront, you can create your SOAP service from Java classes annotated with JAX-WS annotations.
Check the `org.acme.cxf.soap.pojo.service.ContactService` interface as an example.
Again, we implement the service interface in a Camel fashion, this time through a bean
- see `org.acme.cxf.soap.pojo.service.impl.ContactServiceInMemoryImpl`.
The exposed contact web service will enable five operations - `addContact`, `getContact`, `getContacts`, `updateContact` and `removeContact`.
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.
== Start in the Development mode
[source,shell]
----
$ mvn clean compile quarkus:dev
----
The above command compiles the project, starts the application and lets the Quarkus tooling watch for changes in your
workspace. Any modifications in your project will automatically take effect in the running application.
TIP: Please refer to the Development mode section of
https://camel.apache.org/camel-quarkus/latest/first-steps.html#_development_mode[Camel Quarkus User guide] for more details.
[[playground]]
== Playground
We can first try to add a contact with:
[source,shell]
----
curl -X POST -H "Content-Type: text/xml;charset=UTF-8" -d @src/main/resources/requests/contact/add.xml http://localhost:8080/cxf/services/contact
----
Then verify it was added with:
[source,shell]
----
$ curl -X POST -H "Content-Type: text/xml;charset=UTF-8" -d @src/main/resources/requests/contact/getAll.xml http://localhost:8080/cxf/services/contact
----
Which should return:
[source,xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns2:getContactsResponse xmlns:ns2="http://camel.apache.org/test/ContactService">
<return>
<contacts>
<name>Lukas</name>
<address>
<city>New York</city>
<street>Sky 1234</street>
</address>
<type>PERSONAL</type>
</contacts>
</return>
</ns2:getContactsResponse>
</soap:Body>
</soap:Envelope>
----
We can also test our customer service:
[source,shell]
----
$ curl -X POST -H "Content-Type: text/xml;charset=UTF-8" -d @src/main/resources/requests/customer/getByName.xml http://localhost:8080/cxf/services/customer
----
You can observe that we have hardcoded `test` as the name in the `SOAPBody` part in `src/main/resources/requests/customer/getByName.xml` as follows:
[source, xml]
----
<cus:getCustomersByName>
<name>test</name>
</cus:getCustomersByName>
----
We can try to alter it to non-valid request (the validation is enabled with `schema-validation-enabled=true` in `org.acme.cxf.soap.wsdl.MyWsdlRouteBuilder`).
For example, you can change `test` to `t`.
Once you invoke the service again, you should see the following exception:
[source, xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>Unmarshalling Error: cvc-minLength-valid: Value 't' with length = '1' is not facet-valid with respect to minLength '2' for type '#AnonType_namegetCustomersByName'.</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
----
The last thing which could be tested, is trying to get a non-existent customer (which `t` was obviously as well, but now we will pass it through schema validation). So change the name to `Non existent` and see result with `NoSuchCustomer`:
[source, xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Customer not found</faultstring>
<detail>
<ns2:NoSuchCustomer xmlns:ns2="http://customerservice.example.com/">
<customerName>Non existent</customerName>
</ns2:NoSuchCustomer>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
----
TIP: To obtain WSDLs for any exposed CXF service, you can query URL `http://<hostname>/<cxf-path>?wsdl`. It can be handy in tools like _SoapUI_.
To discover WSDLs of our services, you can use:
[source, shell]
----
$ curl "http://localhost:8080/cxf/services/contact?wsdl"
$ curl "http://localhost:8080/cxf/services/customer?wsdl"
----
== Package and run the application
Once you are done with playing/developing you may want to package and run the application for production usage.
TIP: Find more details about the JVM mode and Native mode in the Package and run section of
https://camel.apache.org/camel-quarkus/latest/first-steps.html#_package_and_run_the_application[Camel Quarkus User guide]
=== JVM mode
[source,shell]
----
$ mvn clean package
$ java -jar target/quarkus-app/quarkus-run.jar
----
=== Native mode
IMPORTANT: Native mode requires having GraalVM and other tools installed. Please check the Prerequisites section
of https://camel.apache.org/camel-quarkus/latest/first-steps.html#_prerequisites[Camel Quarkus User guide].
To prepare a native executable using GraalVM, run the following command:
[source,shell]
----
$ mvn clean package -Pnative
$ ./target/*-runner
----
== Kubernetes
==== Deploy
[source,shell]
----
$ mvn clean package -DskipTests -Dquarkus.kubernetes.deploy=true -Dkubernetes
----
You should see one pod running:
[source,shell]
----
camel-quarkus-examples-cxf-soap-cd9477f94-qb8vv 1/1 Running 0 43s
----
Then use following command to redirect the localhost network to the Kubernetes network:
[source,shell]
----
$ kubectl port-forward service/camel-quarkus-examples-cxf-soap 8080:8080
----
Open another terminal and then follow instructions from <<playground>>.
To stop it you can CTRL+C the process in the port-forwarding terminal and shutdown the Kubernetes cluster.
== Feedback
Please report bugs and propose improvements via https://github.com/apache/camel-quarkus/issues[GitHub issues of Camel Quarkus] project.