Part 1
Prerequisites
This tutorial uses the following frameworks:
- Maven 23.0.94
- Apache Camel 12.10.50
- Apache CXF 2.16.1
- Spring 23.0.57
Note: The sample project can be downloaded, see the resources section.
...
Code Block | ||||
---|---|---|---|---|
| ||||
<properties> <cxf-version>2.16.1</cxf-version> </properties> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-core</artifactId> <version>${cxf-version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf-version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf-version}</version> </dependency> |
...
Then we integration the CXF wsdl2java generator in the pom.xml so we have CXF generate the needed POJO classes for our webservice contract.
However at first we must configure maven to live in the modern world of Java 1.5 6 so we must add this to the pom.xml
Code Block | ||||
---|---|---|---|---|
| ||||
<!-- to compile with 1.56 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5<6</source> <target>1.5<6</target> </configuration> </plugin> |
...
Code Block | ||||
---|---|---|---|---|
| ||||
<!-- CXF wsdl2java generator, will plugin to the compile goal --> <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}/target/generated/src/main/java</sourceRoot> <wsdlOptions> <wsdlOption> <wsdl>${basedir}/src/main/webapp/WEB-INF/wsdl/report_incident.xml<wsdl</wsdl> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin> </plugins> |
You are now setup and should be able to compile the project. So running the mvn compile
should run the CXF wsdl2java and generate the source code in the folder &{basedir}/target/generated/src/main/java
that we specified in the pom.xml above. Since its in the target/generated/src/main/java
maven will pick it up and include it in the build process.
...
Code Block | ||||
---|---|---|---|---|
| ||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/> <!-- implementation of the webservice --> <bean id="reportIncidentEndpoint" class="org.apache.camel.example.reportincident.ReportIncidentEndpointImpl"/> <!-- export the webservice using jaxws --> <jaxws:endpoint id="reportIncident" implementor="#reportIncidentEndpoint" address="/incident" wsdlLocation="/WEB-INF/wsdl/report_incident.xmlwsdl" endpointName="s:ReportIncidentPort" serviceName="s:ReportIncidentService" xmlns:s="http://reportincident.example.camel.apache.org"/> </beans> |
...
Noticed that we have a spring bean reportIncidentEndpoint that is the implementation of the webservice endpoint we let CXF expose.
Its linked from the jaxws element with the implementator attribute as we use the # mark to identify its a reference to a spring bean. We could have statet stated the classname directly as implementor="org.apache.camel.example.reportincident.ReportIncidentEndpoint"
but then we lose the ability to let the ReportIncidentEndpoint be configured by spring.
The address attribute defines the relative part of the URL of the exposed webservice. wsdlLocation is an optional parameter but for persons like me that likes contract-first we want to expose our own .wsdl contracts and not the auto generated by the frameworks, so with this attribute we can link to the real .wsdl file. The last stuff is needed by CXF as you could have several services so it needs to know which this one is. Configuring these is quite easy as all the information is in the wsdl already.
...
Now that the code compiles we would like to run it in inside a web container, so we add jetty to our pom.xml so we can run mvn retty:run
for this purpose we make use of Jetty which we will bootstrap using it's plugin org.mortbay.jetty:maven-jetty-plugin
:
Code Block | ||||
---|---|---|---|---|
| ||||
<properties> ... <jetty-version>6.1.1</jetty-version> </properties> <build> <plugins> ... <!-- so we can run mvn jetty:run --> <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId> <version>${jetty-version}</version> </plugin> |
Notice: We make use Jetty v6.1.1 as never versions has troubles on my laptop. Feel free to try a newer version on your system, but v6.1.1 works flawlessof the Jetty version being defined inside the Camel's Parent POM.
So to see if everything is in order we fire up jetty with mvn jetty:run
and if everything is okay you should be able to access http://localhost:8080
.
Jetty is smart that it will list the correct URI on the page to our web application, so just click on the link. This is smart as you don't have to remember the exact web context URI for your application - just fire up the default page and Jetty will help you.
So where is the damm damn webservice then? Well as we did configure the web.xml to instruct the CXF servlet to accept the pattern /webservices/*
we should hit this URL to get the attention of CXF: http://localhost:8080/mycamel-example-webappreportincident/webservices
.
Hitting the webservice
Now we have the webservice running in a standard .war application in a standard web container such as Jetty we would like to invoke the webservice and see if we get our code executed. Unfortunately this isn't the easiest task in the world - its not so easy as a REST URL, so we need tools for this. So we fire up our trusty webservice tool SoapUI and let it be the one to fire the webservice request and see the response.
Using SoapUI we sent a request to our webservice and we got the expected OK response and the console outputs the System.out so we are ready to code.
Remote Debugging
Okay a little sidestep but wouldn't it be cool to be able to debug your code when its fired up under Jetty? As Jetty is started from maven, we need to instruct maven to use debug mode.
Se we set the MAVEN_OPTS
environment to start in debug mode and listen on port 5005.
...
Then we can from our IDE attach a remote debugger and debug as we want.
First we configure IDEA to attach to a remote debugger on port 5005:
Then we set a breakpoint in our code ReportIncidentEndpoint
and hit the SoapUI once again and we are breaked at the breakpoint where we can inspect the parameters:
Adding a unit test
Oh so much hard work just to hit a webservice, why can't we just use an unit test to invoke our webservice? Yes of course we can do this, and that's the next step.
First we create the folder structure src/test/java
and src/test/resources
. We then create the unit test in the src/test/java
folder.
...
#Resources
- Apache CXF user guide
Attachments patterns .*part-one.zip