In the previous recipe, you learned how to expose a web service starting from the WSDL file. This recipe will guide you through the process of exposing a POJO instance as the web service with a WSDL contract automatically generated for you.
ServiceMix uses Apache CXF as an engine of its web service stack. In this recipe, we will create a Mavenized ServiceMix module, exposing Java code as a SOAP-based web service via the CXF endpoint. In order to generate such a module, we will use the Maven Archetype mechanism.
As you can see, Maven is an essential tool to complete this task, so make sure that you have this useful utility properly installed in your system. We will also assume that your ServiceMix instance is already installed and running.
Generate a new CXF code-first project using the Maven archetype.
Create the JAX-WS compatible class.
Build the module with the
mvn install
command.Deploy the generated artifact (
target/cxfcode-first-example-1.0-SNAPSHOT.jar
) to theSERVICEMIX_HOME/deploy
directory.
We will start the development of our code-first web service module by generating a new Apache CXF code-first project from the Maven Archetype (http:/maven.apache.org/archetype/maven-archetype-plugin). The following Maven command can be used to generate a new module from the archetype named org.apache.servicemix.tooling:servicemix-cxf-code-first-osgi-bundle
:
mvn archetype:generate -DarchetypeGroupId=org.apache.servicemix.tooling -DarchetypeArtifactId=servicemix-cxf-code-first-osgi-bundle -DgroupId=com.packtpub.servicemix -DartifactId=cxf-code-first-example-Dversion=1.0-SNAPSHOT
The generated project will contain the bootstrap configuration of the OSGI-based ServiceMix module with the Spring configuration, as well as the simple Person
web service written in JAX-WS:
package com.packtpub.servicemix; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebParam.Mode; import javax.jws.WebService; import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.ws.RequestWrapper; import javax.xml.ws.ResponseWrapper; @WebService @XmlSeeAlso({com.packtpub.servicemix.types.ObjectFactory.class}) public interface Person { @RequestWrapper(localName = "GetPerson", className = "com.packtpub.servicemix.types.GetPerson") @ResponseWrapper(localName = "GetPersonResponse", className = "com.packtpub.servicemix.types.GetPersonResponse") @WebMethod(operationName = "GetPerson") public void getPerson( @WebParam(mode = WebParam.Mode.INOUT, name = "personId") javax.xml.ws.Holder<java.lang.String> personId, @WebParam(mode = WebParam.Mode.OUT, name = "ssn") javax.xml.ws.Holder<java.lang.String> ssn, @WebParam(mode = WebParam.Mode.OUT, name = "name") javax.xml.ws.Holder<java.lang.String> name ) throws UnknownPersonFault; }
Maven Archetype also generates the stub implementation of the Person
service. The implementation class is responsible for handling the actual business logic of the service:
package com.packtpub.servicemix; import javax.jws.WebService; import javax.xml.ws.Holder; import com.packtpub.servicemix.types.GetPerson; import com.packtpub.servicemix.types.GetPersonResponse; @WebService(serviceName = "PersonService", endpointInterface = "com.packtpub.servicemix.Person") public class PersonImpl implements Person { public void getPerson(Holder<String> personId, Holder<String> ssn, Holder<String> name) throws UnknownPersonFault { if (personId.value == null || personId.value.length() == 0) { com.packtpub.servicemix.types.UnknownPersonFault fault = new com.packtpub.servicemix.types.UnknownPersonFault(); fault.setPersonId(personId.value); throw new UnknownPersonFault(null,fault); } name.value = "Guillaume"; ssn.value = "000-000-0000"; } }
We will not delve into the details of the JAX-WS annotations here. If you are interested in a good tutorial about JAX-WS web services, I recommend you read the excellent book from O'Reilly Publishing, called Java Web Services: Up and Running, authored by Martin Kalin.
The Person
service is exposed via the CXF JAX-WS endpoint in the bean.xml
file:
<jaxws:endpoint id="HTTPEndpoint" implementor="com.packtpub.servicemix.PersonImpl" address="/PersonServiceCF"/>
When you deploy the generated CXF module to ServiceMix, it starts a new Spring context defined in the beans.xml
file. In particular, the CXF endpoint is started and exposes the PersonImpl
instance to the outside world via the /cxf/PersonServiceCF
URL. If you add the ?WSDL
parameter at the end of the service URL (http://localhost:8181/cxf/PersonServiceCF?WSDL
), you will see the WSDL file generated by the CXF stack.
To validate that your CXF module has been successfully deployed to ServiceMix, open the URL mentioned above in the browser (as demonstrated in the following screenshot):
If you want to expose a new code-first service via ServiceMix and CXF, all you need to do is to create a new JAX-WS-compatible service and register it in cxf-code-first-example/src/main/resources/META-INF/spring/beans.xml
as the JAX-WS endpoint.
Code-first is probably the most popular approach to web services development. If you are interested in the code-first approach with JAX-WS, you might also be interested in the tips presented here.
When exploring the Java web service stack, you may encounter the JAX-RPC acronym. JAX-RPC is the ancestor of JAX-WS. It is the old web service stack from the J2EE 4 specifications. Java EE 5 introduced a new, annotation-based web service specification called JAX-WS. In general, you can think of JAX-RPC as a legacy technology that is not used in new projects.
The CXF endpoint configuration generated by Maven Archetype is a very basic one. If you want to learn more about CXF usage and configuration, please refer to the documentation on the project site at http://cxf.apache.org/docs/index.html. Keep in mind that CXF is a web services Swiss army knife, so it is good to learn more about the features it provides.