Codehaus XFire
Documentation
Quicklinks
Developers
|
This tutorial offers a 7-step approach to creating XFire web services that utilize JSR 181 annotations and Apache XMLBeans.
Step 1: Dependencies
Sample IVY Config File
One of the first steps in getting XFire working is simply setting up the initial JAR dependencies. For those of you already familiar with maven or ivy, this dependency list below should look familiar. While there may be a few extra JAR files listed below that are not required to use XFire, the overall list and JAR revisions should help you get started.
Check the XFire dependency guide for more information.
 | Be Careful
Note the use of the nightly XFire build below (xfire-all-1.0-SNAPSHOT.jar). You may wish to use a specific release for your project. I pull the nightly XFire snapshot down for my development environment only. |
<dependencies>
<dependency org="log4j" name="log4j" rev="1.2.9" conf="bundle,runtime->default" />
<dependency org="springframework" name="springframework" rev="1.2.6" conf="bundle,runtime->default">
<artifact name="spring" type="jar"/>
</dependency>
<dependency org="commons-codec" name="commons-codec" rev="1.3" conf="client,bundle,runtime->default" />
<dependency org="commons-beanutils" name="commons-beanutils" rev="1.7.0" conf="bundle,runtime->default" />
<dependency org="commons-collections" name="commons-collections" rev="2.1" conf="bundle,runtime->default" />
<dependency org="commons-digester" name="commons-digester" rev="1.5" conf="bundle,runtime->default" />
<dependency org="commons-discovery" name="commons-discovery" rev="0.2" conf="bundle,runtime->default" />
<dependency org="commons-httpclient" name="commons-httpclient" rev="3.0" conf="client,bundle,runtime->default" />
<dependency org="commons-el" name="commons-el" rev="1.0" conf="bundle,runtime->default" />
<dependency org="commons-fileupload" name="commons-fileupload" rev="1.0" conf="bundle,runtime->default" />
<dependency org="commons-logging" name="commons-logging" rev="1.0.4" conf="client,bundle,runtime->default" />
<dependency org="commons-validator" name="commons-validator" rev="1.1.4" conf="bundle,runtime->default" />
<dependency org="oro" name="oro" rev="2.0.8" conf="bundle,runtime->default" />
<dependency org="jstl" name="jstl" rev="1.1.2" conf="bundle,runtime->default" />
<dependency org="javamail" name="mailapi" rev="1.3.2" conf="client,bundle,runtime->default" />
<dependency org="xbean" name="xbean-spring" rev="2.0" conf="bundle,runtime->default" />
<dependency org="jaxen" name="jaxen" rev="1.1-beta-8" conf="bundle,runtime->default" />
<dependency org="jdom" name="jdom" rev="1.0" conf="client,bundle,runtime->default" />
<dependency org="wsdl4j" name="wsdl4j" rev="1.4" conf="client,bundle,runtime->default" />
<!--
Stax is the XML api that powers XFire and allows it to process XML efficiently.
There are many different Atax implementations out there - the reference
implementation (RI), Woodstox, FastInfoset, and there is one included in the JWSDP.
Regardless of which you one choose you must have the stax-api jar on your classpath.
In addition we highly recommend that you use Woodstox as your Stax implementation.
It is about 30-40% faster then the RI and works more reliably. To ensure you are
using Woodstox and not the RI make sure the stax-1.1.x-dev jar is off your
classpath and the wstx-2.0.3 jar is on it.
<dependency org="wstx" name="wstx" rev="2.0.3" conf="bundle,runtime->default" />
-->
<dependency org="woodstox" name="wstx-lgpl" rev="2.8" conf="client,bundle,runtime->default" />
<dependency org="stax" name="stax" rev="api-1.0" conf="client,bundle,runtime->default" />
<dependency org="xfire" name="xfire-all" rev="1.0-SNAPSHOT" conf="client,bundle,runtime->default" />
<dependency org="acegisecurity" name="acegisecurity" rev="0.9.0" conf="bundle,runtime->default">
<artifact name="acegi-security" type="jar" />
</dependency>
<dependency org="xfire" name="xfire-jsr181-api" rev="1.0-M1" conf="bundle,runtime->default" />
<dependency org="xfire" name="jaxb-api" rev="20051106" conf="bundle,runtime->default" />
<dependency org="xfire" name="jaxb-impl" rev="20051106" conf="bundle,runtime->default" />
<dependency org="xfire" name="jaxb-xjc" rev="20051106" conf="bundle,runtime->default" />
<dependency org="xfire" name="XmlSchema" rev="20051110" conf="bundle,runtime->default" />
<dependency org="activation" name="activation" rev="1.0.2" conf="client,bundle,runtime->default" />
<dependency org="xmlbeans" name="xmlpublic" rev="2.1.0" conf="client,bundle,runtime->default" />
<dependency org="xmlbeans" name="xbean" rev="2.1.0" conf="client,bundle,runtime->default" />
<dependency org="xmlbeans" name="xbean_xpath" rev="2.1.0" conf="bundle,runtime->default" />
</dependencies>
Step 2: Start with XSD
If you subscribe to XML-driven development or MDA or AMDD, then I recommend starting your application with (3) XSD files:
Common.xsd
- Common.xsd simply stores types used in both request and response
<complexType name="UserToken">
<sequence>
<element name="username" type="string" maxOccurs="1" minOccurs="1"/>
<element name="password" type="string" maxOccurs="1" minOccurs="1"/>
</sequence>
</complexType>
Request.xsd
Response.xsd
 | Handy Hint
Don't forget that Eclipse has a great XSD editor (which created the XSD visuals you see below). |
Below are some instructions outlining the intent behind creating these (3) separate XSD files, which are used to then generate XMLBeans in Step 3 of this process.
|
Request.xsd |
Response.xsd |
Description |
- 1 request element:
<element name="request" type="tns:Request">
</element>
- 1 Request complex type:
<complexType name="Request" abstract="true">
</complexType>
- All SOAP requests extend Request
<complexType name="GetContactTypes">
<complexContent>
<extension base="tns:Request">....</extension>
</complexContent>
</complexType>
|
- 1 response element:
<element name="response" type="tns:Response">
</element>
- 1 Response complex type:
<complexType name="Response" abstract="true">
...
</complexType>
- All SOAP responses extend Response
<complexType name="GetContactTypesResponse">
<complexContent>
<extension base="tns:Response">...</extension>
</complexContent>
</complexType>
|
Image |
|
|
Notes |
preview :: this will create the following XMLBean class structure
public abstract interface
request.RequestDocument implements XMLObject {
request.Request getRequest();
}
public class RequestDocumentImpl
implements request.RequestDocument
public abstract interface
request.GetContactTypes implements Request
|
|
 | Warning
Because I was unable to deploy the service as document/literal wrapped service, you should create a separate XSD element per exposed method on your webservice implementation class |
Step 3: Generate XMLBeans
If your XSDs are placed in META-INF/xfire/, then the following Ant task will generate XMLBeans from the XSD files:
|
Ant Task |
|
Task XML |
<target name=">step3.gen.xmlbeans.from.schema" description="Generate XMLBeans">
<taskdef name="xmlbean" classname="org.apache.xmlbeans.impl.tool.XMLBean"
classpathref="all.app.path" />
<echo message="About to generate XMLBeans from XSDs"/>
<xmlbean srcgendir="src" destfile="build\appXMLBeans-1.0.jar"
classpath="classes" debug="true" verbose="true">
<fileset *dir="/META-INF/xfire/"* includes="*.xsd"/>
</xmlbean> </target>
|
|
Step 4: Setup Eclipse to Support Annotations
- Install JDK 1.5 and Add in JDT-APT to your Eclipse install JDT-APT
Set JDK Compliance to 5.0 |
Allow Annotations |
 |
 |
 | Useful Information
JDT-APT currently runs on top of Eclipse 3.1.1. It is not currently part of Eclipse itself, but rather is a separate plugin along with a modified version of the JDT plugin. We are in the process of porting to Eclipse 3.2, which is currently in development. |
Step 5: Create your annotated service
Web Service Interface |
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.WebResult;
import org.codehaus.xfire.fault.XFireFault;
import org.company.service.request.RequestDocument;
import org.company.service.response.ResponseDocument;
@WebService(name="ServiceInterface", targetNamespace="http:)
public interface ServiceInterface {
@WebMethod(operationName = "GetXYZ")
@WebResult(name = "response", targetNamespace = "http:)
public ResponseDocument getXYZ(RequestDocument request) throws XFireFault;
}
|
Web Service Implementation |
package org.company.service.server;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.ParameterStyle;
import javax.jws.soap.SOAPBinding.Style;
import javax.jws.soap.SOAPBinding.Use;
import javax.xml.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.xfire.fault.XFireFault;
import org.company.service.request.GetXYZ;
import org.company.service.request.RequestDocument; import org.company.service.response.GetXYZResponse; import org.company.service.response.ResponseDocument; import org.company.service.service.XYZService;
@WebService(serviceName = "ServiceInterface",
targetNamespace = "http:,
endpointInterface = "org.company.service.server.ServiceInterface")
@SOAPBinding(style = Style.DOCUMENT, use = Use.LITERAL,
parameterStyle = ParameterStyle.BARE)
public class ServiceImpl implements ServiceInterface {
private XYZService xyzService; protected final Log log = LogFactory.getLog(getClass());
public ResponseDocument getProvidersUsingVendor(RequestDocument request)
throws XFireFault {
GetXYZ xyzRequest = (GetXYZ) request.getRequest();
GetXYZResponse xyzResponse = getXYZService().getXYZ(xyzRequest);
ResponseDocument responseDoc = ResponseDocument.Factory.newInstance();
responseDoc.setResponse(xyzResponse);
return responseDoc;
}
...
}
|
 | Handy Hint
Note how the use of XMLBeans and how the RequestDocument is cast to the GetXYZ type |
Step 6: Wire up Spring
If you notice in the ServiceImpl class above, I'm using Spring to do some dependency injection. If you want to do this (sharing your XFire application context with the Spring application context loaded by your web application's org.springframework.web.context.ContextLoaderListener for example, then strip out everything from META-INF/xfire/services.xml and put it in your own Spring config file loaded by the ContextLoaderListener declared in your web application.
In your WEB-INF/web.xml, load Spring like this (using the classpath: notation in order to load xfire.xml from your XFire JAR deployed in WEB-INF/lib)
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/MyService-acegi-base.xml
/WEB-INF/MyService-authentication.xml
/WEB-INF/MyService-authorization.xml
/WEB-INF/MyService-dao.xml
/WEB-INF/MyService-sqlmap.xml
/WEB-INF/MyService-datasource.xml
/WEB-INF/MyService-servlet.xml
/WEB-INF/MyService-xfire.xml
classpath:org/codehaus/xfire/spring/xfire.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Then declare your XFire spring beans in another Spring XML config file (such as the /WEB-INF/MyService-xfire.xml referenced above).
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="BookService" class="org.codehaus.xfire.spring.ServiceBean" >
<property name="serviceClass" value="org.codehaus.xfire.demo.BookService"/>
<property name="namespace" value="http://xfire.codehaus.org/BookService"/>
</bean>
<bean id="CustomerService" class="org.codehaus.xfire.spring.ServiceBean" >
<property name="serviceClass" value="org.codehaus.xfire.demo.CustomerService"/>
<property name="serviceFactory" value="jsr181"/>
</bean>
<bean id="webService" class="org.company.service.server.ServiceImpl">
<property name="xyzService" ref="xyzService"/>
</bean>
<bean name="xfire.jaxbServiceFactory" class="org.codehaus.xfire.jaxb2.JaxbServiceFactory">
<constructor-arg ref="xfire.transportManager"/>
</bean>
<bean id="xfire.xmlbeansServiceFactory"
class="org.codehaus.xfire.xmlbeans.XmlBeansServiceFactory"
singleton="true">
<constructor-arg index="0" ref="xfire.transportManager"/>
</bean>
<bean id="xfire.annotationServiceFactory"
class="org.codehaus.xfire.annotations.AnnotationServiceFactory">
<constructor-arg index="0" ref="webAnnotations"/>
<constructor-arg index="1" ref="xfire.transportManager"/>
<constructor-arg index="2" ref="xfire.aegisBindingProvider"/>
</bean>
<bean id="xfire.xmlBeansAnnotationServiceFactory"
class="org.codehaus.xfire.annotations.AnnotationServiceFactory">
<constructor-arg index="0" ref="webAnnotations"/>
<constructor-arg index="1" ref="xfire.transportManager"/>
<constructor-arg index="2" ref="xmlbeans.aegisBindingProvider"/>
</bean>
<bean id="xmlbeansTypeRegistry" class="org.codehaus.xfire.xmlbeans.XmlBeansTypeRegistry"/>
<bean id="xmlbeans.aegisBindingProvider" class="org.codehaus.xfire.aegis.AegisBindingProvider">
<constructor-arg index="0" ref="xmlbeansTypeRegistry"/>
</bean>
<bean id="webAnnotations" class="org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations"/>
<bean id="xfireServiceTemplate"
class="org.codehaus.xfire.spring.remoting.XFireExporter" abstract="true">
<property name="serviceFactory" ref="xfire.serviceFactory" />
<property name="xfire" ref="xfire" />
<property name="style" value="document" />
<property name="use" value="literal" />
</bean>
<bean id="xfireXMLBeansServiceTemplate"
class="org.codehaus.xfire.spring.remoting.XFireExporter" abstract="true">
<property name="serviceFactory" ref="xfire.xmlbeansServiceFactory" />
<property name="xfire" ref="xfire" />
<property name="style" value="document" />
<property name="use" value="literal" />
</bean>
<bean id="xfireXMLBeansAnnotationsServiceTemplate"
class="org.codehaus.xfire.spring.remoting.XFireExporter" abstract="true">
<property name="serviceFactory" ref="xfire.xmlBeansAnnotationServiceFactory" />
<property name="xfire" ref="xfire" />
<property name="style" value="document" />
<property name="use" value="literal" />
</bean>
<bean id="MyXFireService" parent="xfireXMLBeansAnnotationsServiceTemplate" >
<property name="serviceBean" ref="webService"/>
<!--
Interface specification is no longer required when using
xfire-jsr181-api-1.0-M1.jar instead of wsm-1.0-alpha.jar
<property name="serviceInterface" value="org.company.service.server.ServiceInterface"/>
-->
<property name="schemas">
<list>
<value>/META-INF/xfire/Common.xsd</value>
<value>/META-INF/xfire/Request.xsd</value>
<value>/META-INF/xfire/Response.xsd</value>
</list>
</property>
</bean>
Step 7: Deploy the Web Service & Generate the Client
Ant Task |
<target name="download.wsdl">
<get src="http://localhost:8080/services/ServiceInterface"
dest="dist/yourapp-1.0.wsdl"
verbose="true"
usetimestamp="true"/>
</target>
<target name=">step7.gen.client.from.wsdl" depends="download.wsdl">
<taskdef name="wsgen" classname="org.codehaus.xfire.gen.WsGenTask" classpathref="wsgen.path" />
<wsgen outputDirectory="src"
wsdl="dist/yourapp-1.0.wsdl"
package="org.company.service.wsclient"
binding="xmlbeans" />
</target>
|
The generated client code will look something like this:
package org.company.service.wsclient;
import java.net.MalformedURLException;
import javax.xml.namespace.QName;
import org.codehaus.xfire.XFireRuntimeException;
import org.codehaus.xfire.aegis.AegisBindingProvider;
import org.codehaus.xfire.annotations.AnnotationServiceFactory;
import org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Endpoint;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.soap.AbstractSoapBinding;
import org.codehaus.xfire.transport.TransportManager;
import org.codehaus.xfire.xmlbeans.XmlBeansTypeRegistry;
import org.company.service.server.ServiceInterface;
public class ServiceInterface {
private Service service;
private static XFireProxyFactory proxyFactory = new XFireProxyFactory();
public ServiceInterfaceClient() {
createService();
service.addEndpoint(new QName("http:,
"ServiceInterfaceLocalPort"),
new QName("http:, "ServiceInterfaceLocalBinding"),
"xfire.local:);
service.addEndpoint(new QName("http:,
"ServiceInterfaceHttpPort"),
new QName("http:,
"ServiceInterfaceHttpBinding"),
"http:);
}
private void createService() {
TransportManager tm = (org.codehaus.xfire.XFireFactory.newInstance().getXFire().getTransportManager());
AnnotationServiceFactory asf = new AnnotationServiceFactory(
new Jsr181WebAnnotations(), tm, new AegisBindingProvider(new XmlBeansTypeRegistry()));
asf.setBindingCreationEnabled(true);
service = asf.create((org.company.service.server.ServiceImpl.class));
{
AbstractSoapBinding soapBinding = asf.createSoap11Binding(service,
new QName("http:, "ServiceInterfaceHttpBinding"),
"http:);
}
{
AbstractSoapBinding soapBinding = asf.createSoap11Binding(service,
new QName("http:,
"ServiceInterfaceLocalBinding"),
"urn:xfire:transport:local");
}
}
public void addEndpoint(QName name, QName binding, String address) {
service.addEndpoint((name), (binding), (address));
}
public ServiceInterface getEndpoint(Endpoint endpoint) {
try {
return ((ServiceInterface ) proxyFactory.create((endpoint).getBinding(), (endpoint).getUrl()));
} catch (MalformedURLException e) {
throw new XFireRuntimeException("Invalid URL", e);
}
}
public ServiceInterface getEndpoint(QName name) {
Endpoint endpoint = service.getEndpoint((name));
if ((endpoint) == null) {
throw new IllegalStateException("No such endpoint!");
}
return getEndpoint((endpoint));
}
public ServiceInterface getEndpoint() {
if (service.getEndpoints().size() == 0) {
throw new IllegalStateException("No available endpoints!");
}
Endpoint endpoint = ((Endpoint) service.getEndpoints().iterator().next());
return (this).getEndpoint((endpoint));
}
public ServiceInterface getServiceInterfaceLocalPort() {
return (this).getEndpoint(
new QName("http:, "ServiceInterfaceLocalPort"));
}
public ServiceInterface getServiceInterfaceHttpPort() {
return (this).getEndpoint(
new QName("http:, "ServiceInterfaceHttpPort"));
}
}
 | Handy Hint
For those of you who are concerned about the apparent requirement here to package your Service implementation class with a Java client JAR that you might need to send to a business partner using your web service, Dan Diephouse offered the following suggestion:
You need to pass off the implementation class because according to JSR 181 the soap binding annotations need to be on the implementation class, and we need those to figure out how to send the messages. You can however make a copy of your service impl class and put "throws UnsupportedOperationException" in all the bodies though. |
|