Raible's Wiki
Raible Designs AppFuseHomepage- Korean - Chinese - Italian - Japanese QuickStart Guide User Guide Tutorials Other ApplicationsStruts ResumeSecurity Example Struts Menu
Set your name in
UserPreferences
Referenced by
JSPWiki v2.2.33
Hide Menu |
This is version 3.
It is not the current version, and thus it cannot be edited. Part I: Integrating XFire Webservices into AppFuse - A HowTo for providing Webservices from within AppFuse. About this TutorialThis tutorial will show you how to create a Webservice Endpoint and what you can do to automate the creation of artifacts necessary to provide Webservices to others.Table of Contents
Preface [#0]You may wonder, why I bother to write a howto for XFire, given that there is already one for Axis, the far more widely used Webservice framework. But you may wonder as well, why the codehaus people bother writing XFire at all, years after Axis was published in the first place. The reason for the latter, in my personal opinion, is that Axis 1 has some shortfalls. Namely dealing with Collections and it is not so easy to plug in another XML binding framework. Why should you not be comfortable with the built in XML binding? Because it is not as powerful as for example XmlBeans. You have to limit your application to a subset of what's possible with webservices. Another, in some cases important benefit is performance (in terms of speed), that is because the next generation webservice frameworks (like Axis 2 and XFire) are based an StAX, the Streaming Api for Xml. Apache is aware of this limitations of Axis 1 and has taken Axis 2 on board as a replacement build from scratch for Axis 1. Axis 2 is (as well as XFire) in pre 1.0 state, XFire is, however, just a few days away from it's 1.0 as of Feb 2006. My motivation to use XFire instead of Axis 2 is, that I started using it, was successful in short time, and just stuck with it, becoming a committer of the project.There's work in progress to automate the process of plugging in XFire into AppFuse (via an extras package), you'll find the first shot version attached to this page as zip. All that's described on this page is performed by an ant-task in this package. Expand it in the extras folder of your project, go into the folder xfire-webservice with a shell and do an ant installthere. It will install the necessary files and do the changes described below. Download the prerequistie packages [#1]Currently I recommend the nightly snapshot of XFire. This may change with the release of 1.0, but the latest milestone 1.0M6a has got some problems that have been fixed in CVS. It is available from the Codehaus XFire site. You'll find source and binary distribution in one file here xfire-all-1.0-SNAPSHOT.zip. When you open the zip, you'll find a lot of xfire-xxx.jars. This is because XFire has various options for XML binding, configuration and container-integration. In this howto we'll focus on Aegis for binding and Spring integration, so all you need of the xfire-jars are:
plus some of the third-party libs you'll find in the libs/runtime dir of the zip. Later, we'll use some of the libs from libs/test as well, because I'll show you how you can setup testcases in the webservice field really easy. Add the packages to AppFuse's lib structure [#2]
lib/ xfire-1.0-SNAPSHOT/ lib/runtime lib/test Copy the following files into the xfire-1.0-SNAPSHOT/lib/runtime folder: from the root of the zip
from the lib/runtime folder
additionally, you need wsdl4j-1.5.2.jar which is available here
some other required libs under libs/runtime you already have in other lib directories of appfuse. Currently, there are no version conflicts with the 1.8 version of appfuse. If there are some with the new 1.9 version, I'll see to sort them out and amend this howto. Copy the following files from the libs/test dir to xfire-1.0-SNAPSHOT/lib/test
Now add the following to lib.properties # # XFire - http://xfire.codehaus.org # xfire.version=1.0-SNAPHOST xfire.dir=${lib.dir}/xfire-${xfire.version}/lib/runtime xfire.test.dir=${lib.dir}/xfire-${xfire.version}/lib/test Modify the build script to include these packages [#3]Now that AppFuse is aware of the new libraries, we need to include them in the build process.We must modify the package-web target, to add the following to the lib directives for the war task: ... <lib dir="${xfire.dir}" includes="*.jar"/> </war> Additinally we need to put the xfire libs into the compile-service classpath in properties.xml(just below <path id="service.compile.classpath">): <fileset dir="${xfire.dir}" includes="*.jar"/>and the corresponding test classpath <fileset dir="${xfire.test.dir}" includes="*.jar"/> Add the XFireServlet definition [#4]Actually there are two servlets, you could choose. One is the Spring integration of XFire servlet, the other the XFire integration of Spring servlet. You see, the both projects love each other :-) We'll go with the Spring way, known as XFireConfigurableServlet. One of the major differences is, that the XFire way creates the Spring appContext in the servlet, something that we don't need, as we already have a Spring enabled web application. If you want to create a webservice-only application, you can use the org.codehaus.xfire.transport.http.XFireConfigurableServlet instead, so that you don't need to use Springs startup-servlet or listener to load the appContext (if you don't know, what I'm talking about, you probably don't need it :-)Now it depends on the appfuse version you have. In versions below 1.9, the servlet-configuration is done under metadata/web in the servlets.xml and servlet-mapping.xml files. From 1.9 on, there is a web.xml file under web/WEB_INF. However, I assume, that you as a web developer know your web.xml. Open web/WEB-INF/web.xml and add the following: <!-- XFire servlet definition and mapping --> <servlet> <servlet-name>XFireServlet</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/servlet/XFireServlet/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>XFireServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> Additionally it makes sense to add mime-mappings in the web.xml file: <!-- currently the W3C havent settled on a media type for WSDL; http://www.w3.org/TR/2003/WD-wsdl12-20030303/#ietf-draft for now we go with the basic 'it's XML' response --> <mime-mapping> <extension>wsdl</extension> <mime-type>text/xml</mime-type> </mime-mapping> <mime-mapping> <extension>xsd</extension> <mime-type>text/xml</mime-type> </mime-mapping> The DispatcherServlet expects your Spring service definition in a file named XFire-servlet.xml under WEB-INF. The first definition (SimpleUrlHandlerMapping) tells the DispatcherServlet, that it should pass a request to "services/UserService" to the bean named "userWebservice". The second is the declaration of this web service. We delegate the requests directly to the bean "userManager" using the interface UserManager. userManager itself is declared in your applicationContext-service.xml. You see how smooth xfire integrates with Spring again. No boilerplate code between the servlet and the POJO Manager bean. Only a bit of xml wiring them together. You may have noticed the import. That file contains definitions for beans integrated with Spring from xfire. There you can find the spring bean declarations of "xfire", "xfire.serviceFactory" and some more. The doc on the xfire site gives the advice to put that in the global application-context declaration in your web.xml, but I thought it is more clear just to expose this to the context that deals with the xfire webservices rather than the root application context. Create a new file und web/WEB-INF named "XFire-servlet.xml" and paste the following into it: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"> <beans> <import resource="classpath:org/codehaus/xfire/spring/xfire.xml"/> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="urlMap"> <map> <entry key="/UserService"> <ref bean="userWebservice" /> </entry> </map> </property> </bean> <!-- Declare a parent bean with all properties common to both services --> <bean id="userWebservice" class="org.codehaus.xfire.spring.remoting.XFireExporter"> <property name="serviceFactory"> <ref bean="xfire.serviceFactory" /> </property> <property name="xfire"> <ref bean="xfire" /> </property> <property name="serviceBean"> <ref bean="userManager" /> </property> <property name="serviceInterface"> <value>org.appfuse.service.UserManager</value> </property> </bean> </beans> In principle you'd be done here. You could deploy the application and call the webservice. But because the UserManager has got a method "List getUsers()", we need to tell xfire, what components to expect to get back when calling this method. Create an xdoclet-task in build.xml to generate the aegis.xml mapping files [#5]XFire doesn't need a .wsdd file like axis, because all services are configured via Spring and optional additional files. In this howto, we use aegis-mapping, which works on xml descriptors to provide information XFire can't obtain through introspection from the class files. Another method is to annotate the classes with java 5 annotations (covered by xfire-java5) or with commons-annotations (xfire-annotations). It's beyond the scope of this howto to explain all possibilities, so we stick with aegis. Normally you'd create the xxx.aegis.xml mapping files by hand, but as we are used to xdoclet tags in AppFuse, I wrote a template doing that for us. The xxx.aegis.xml files go into the package structure like property files, so if you want to provide a mapping for org.appfuse.model.User, you just put it there under org.appfuse.model.User.aegis.xml. What you can do with the mappings is described here. There's a schema for the xml here. Create a file named aegis-mapping.xdt in metadata/templates: <?xml version="1.0" encoding="utf-8"?> <mappings<XDtClass:ifHasClassTag tagName="aegis.mapping" paramName="xmlns"> xmlns:<XDtClass:className/>="<XDtClass:classTagValue tagName="aegis.mapping" paramName="xmlns"/>"</XDtClass:ifHasClassTag>> <mapping<XDtClass:ifHasClassTag tagName="aegis.mapping" paramName="name"> name="<XDtClass:ifHasClassTag tagName="aegis.mapping" paramName="xmlns"><XDtClass:className/>:</XDtClass:ifHasClassTag><XDtClass:classTagValue tagName="aegis.mapping" paramName="name"/>"</XDtClass:ifHasClassTag><XDtClass:ifHasClassTag tagName="aegis.mapping" paramName="uri"> uri="<XDtClass:classTagValue tagName="aegis.mapping" paramName="uri"/>"</XDtClass:ifHasClassTag>> <XDtMethod:forAllMethods> <XDtMethod:ifHasMethodTag tagName="aegis.property"><property<XDtMethod:ifHasMethodTag tagName="aegis.property" paramName="name"> name="<XDtMethod:methodTagValue tagName="aegis.property" paramName="name"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifDoesntHaveMethodTag tagName="aegis.property" paramName="name"> name="<XDtMethod:propertyName/>"</XDtMethod:ifDoesntHaveMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.property" paramName="type"> type="<XDtMethod:methodTagValue tagName="aegis.property" paramName="type"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.property" paramName="mappedName"> mappedName="<XDtMethod:methodTagValue tagName="aegis.property" paramName="mappedName"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.property" paramName="nillable"> nillable="<XDtMethod:methodTagValue tagName="aegis.property" paramName="nillable"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.property" paramName="ignore"> ignore="<XDtMethod:methodTagValue tagName="aegis.property" paramName="ignore"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.property" paramName="componentType"> componentType="<XDtMethod:methodTagValue tagName="aegis.property" paramName="componentType"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.property" paramName="style"> style="<XDtMethod:methodTagValue tagName="aegis.property" paramName="style"/>"</XDtMethod:ifHasMethodTag>/></XDtMethod:ifHasMethodTag> <XDtMethod:ifHasMethodTag tagName="aegis.method"><method<XDtMethod:ifHasMethodTag tagName="aegis.method" paramName="name"> name="<XDtMethod:methodTagValue tagName="aegis.method" paramName="name"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifDoesntHaveMethodTag tagName="aegis.method" paramName="name"> name="<XDtMethod:methodName/>"</XDtMethod:ifDoesntHaveMethodTag>> <XDtMethod:ifHasMethodTag tagName="aegis.method-return-type"> <return-type<XDtMethod:ifHasMethodTag tagName="aegis.method-return-type" paramName="keyType"> keyType="<XDtMethod:methodTagValue tagName="aegis.method-return-type" paramName="keyType"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.method-return-type" paramName="componentType"> componentType="<XDtMethod:methodTagValue tagName="aegis.method-return-type" paramName="componentType"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.method-return-type" paramName="mappedName"> mappedName="<XDtMethod:methodTagValue tagName="aegis.method-return-type" paramName="mappedName"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.method-return-type" paramName="typeName"> typeName="<XDtMethod:methodTagValue tagName="aegis.method-return-type" paramName="typeName"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.method-return-type" paramName="type"> typeName="<XDtMethod:methodTagValue tagName="aegis.method-return-type" paramName="type"/>"</XDtMethod:ifHasMethodTag>/> </XDtMethod:ifHasMethodTag> <XDtMethod:ifHasMethodTag tagName="aegis.method-parameter"> <XDtMethod:forAllMethodTags tagName="aegis.method-parameter"> <parameter<XDtMethod:ifHasMethodTag tagName="aegis.method-parameter" paramName="index"> index="<XDtMethod:methodTagValue tagName="aegis.method-parameter" paramName="index"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.method-parameter" paramName="keyType"> keyType="<XDtMethod:methodTagValue tagName="aegis.method-parameter" paramName="keyType"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.method-parameter" paramName="componentType"> componentType="<XDtMethod:methodTagValue tagName="aegis.method-parameter" paramName="componentType"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.method-parameter" paramName="mappedName"> mappedName="<XDtMethod:methodTagValue tagName="aegis.method-parameter" paramName="mappedName"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.method-parameter" paramName="typeName"> typeName="<XDtMethod:methodTagValue tagName="aegis.method-parameter" paramName="typeName"/>"</XDtMethod:ifHasMethodTag><XDtMethod:ifHasMethodTag tagName="aegis.method-parameter" paramName="type"> typeName="<XDtMethod:methodTagValue tagName="aegis.method-parameter" paramName="type"/>"</XDtMethod:ifHasMethodTag>/> </XDtMethod:forAllMethodTags> </XDtMethod:ifHasMethodTag> </method> </XDtMethod:ifHasMethodTag> </XDtMethod:forAllMethods> </mapping> </mappings> Tags recognized are: Class-Level: @aegis.mapping xmlns="" name="" uri="" Method-Level: @aegis.property name="" type="" mappedName="" nillable="" ignore="" componentType="" style="" @aegis.method name="" @aegis.method-return-type keyType="" componentType="" mappedName="" typeName="" type="" @aegis.method-parameter index="" keyType="" componentType="" mappedName="" typeName="" type="" First create the bit that resolves the getUsers() List component type: [...} * @aegis.mapping */ public interface UserManager { [...] * @aegis.method-return-type componentType="org.appfuse.model.User" */ public List getUsers(User user); [...] The same issue comes up in the User type itself and in the Role type. For User.java this looks like [...] * * @struts.form include-all="true" extends="BaseForm" * @hibernate.class table="app_user" * @aegis.mapping */ public class User extends BaseObject implements Serializable, UserDetails { private static final long serialVersionUID = 3832626162173359411L; [...] /** * @struts.validator type="required" * @hibernate.id length="20" generator-class="assigned" unsaved-value="version" * @aegis.property name="Username" */ public String getUsername() { return username; } [...] /** * Returns the full name. * @aegis.property ignore="true" */ public String getFullName() { return firstName + ' ' + lastName; } [...] * @aegis.property componentType="org.appfuse.model.Role" */ public Set getRoles() { return roles; } and for Role we have the same Collection resolving plus we need to get rid of the circular reference to User. This is because xfire is about document/literal style webservices. What that is compared to jax-rpc is best explained here. document/literal doesn't have references in the xml that it understands. So if we would keep that circular reference, we would get a StackOverflowException. [...] * @hibernate.class table="role" * @aegis.mapping */ public class Role extends BaseObject implements Serializable, GrantedAuthority { [...] * @aegis.property ignore="true" */ public Set getUsers() { return users; } [...] Depending on your specific usage of the webservice you design, you can ignore further properties, but I leave that to you in this example. Open build.xml and add the following target definition (I personally put it directly before the compile-web target): <target name="gen-aegis-mapping" depends="prepare" description="Generates Aegis Mapping XML descriptors from POJOs"> <taskdef name="xdoclet" classname="xdoclet.DocletTask" classpathref="xdoclet.classpath"/> <xdoclet excludedtags="@version,@author" addedtags="@xdoclet-generated at ${TODAY}" force="${xdoclet.force}" destdir="${build.dir}/service/classes" mergedir="metadata/webservice"> <fileset dir="src/service" includes="**/*.java"/> <template templateFile="metadata/templates/aegis-mapping.xdt" acceptAbstractClasses="false" prefixWithPackageStructure="true" destinationFile="{0}.aegis.xml" havingClassTag="aegis.mapping"/> </xdoclet> <xdoclet excludedtags="@version,@author" addedtags="@xdoclet-generated at ${TODAY}" force="${xdoclet.force}" destdir="${build.dir}/dao/classes" mergedir="metadata/webservice"> <fileset dir="src/dao" includes="**/*.java"/> <template templateFile="metadata/templates/aegis-mapping.xdt" acceptAbstractClasses="false" prefixWithPackageStructure="true" destinationFile="{0}.aegis.xml" havingClassTag="aegis.mapping"/> </xdoclet> </target> Expose a Manager as a webservice [#6]Now you've got everything together that's necessary to see it running. Do an ant gen-aegis-mapping deploy and open the url "services/UserService?wsdl" of your application in your browser. You should see a xfire generated wsdl webservice definition: <?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:ns1="http://model.appfuse.org" xmlns:ns3="http://dao.appfuse.org" xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" xmlns:soapenc11="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenc12="http://www.w3.org/2003/05/soap-encoding" xmlns:tns="http://service.appfuse.org" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://service.appfuse.org"> <wsdl:types xmlns:ns2="http://acegisecurity.org"> <xsd:schema targetNamespace="http://model.appfuse.org" elementFormDefault="qualified" attributeFormDefault="qualified"> <xsd:complexType name="User"> <xsd:sequence> <xsd:element name="accountExpired" type="xsd:boolean" minOccurs="0" /> <xsd:element name="accountLocked" type="xsd:boolean" minOccurs="0" /> <xsd:element name="accountNonExpired" type="xsd:boolean" minOccurs="0" /> <xsd:element name="accountNonLocked" type="xsd:boolean" minOccurs="0" /> <xsd:element name="address" type="ns1:Address" minOccurs="0" nillable="true" /> <xsd:element name="authorities" type="ns2:ArrayOfGrantedAuthority" minOccurs="0" nillable="true" /> <xsd:element name="confirmPassword" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="credentialsExpired" type="xsd:boolean" minOccurs="0" /> <xsd:element name="credentialsNonExpired" type="xsd:boolean" minOccurs="0" /> <xsd:element name="email" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="enabled" type="xsd:boolean" minOccurs="0" /> <xsd:element name="firstName" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="lastName" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="password" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="passwordHint" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="phoneNumber" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="roles" type="ns1:ArrayOfRole" minOccurs="0" nillable="true" /> <xsd:element name="username" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="version" type="xsd:int" minOccurs="0" nillable="true" /> <xsd:element name="website" type="xsd:string" minOccurs="0" nillable="true" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="ArrayOfRole"> <xsd:sequence> <xsd:element name="Role" type="ns1:Role" nillable="true" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="Role"> <xsd:sequence> <xsd:element name="authority" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="description" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="name" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="version" type="xsd:int" minOccurs="0" nillable="true" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="Address"> <xsd:sequence> <xsd:element name="address" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="city" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="country" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="postalCode" type="xsd:string" minOccurs="0" nillable="true" /> <xsd:element name="province" type="xsd:string" minOccurs="0" nillable="true" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="ArrayOfUser"> <xsd:sequence> <xsd:element name="User" type="ns1:User" nillable="true" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> </xsd:complexType> </xsd:schema> <xsd:schema targetNamespace="http://acegisecurity.org" elementFormDefault="qualified" attributeFormDefault="qualified"> <xsd:complexType name="ArrayOfGrantedAuthority"> <xsd:sequence> <xsd:element name="GrantedAuthority" type="ns2:GrantedAuthority" nillable="true" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> </xsd:complexType> <xsd:complexType name="GrantedAuthority"> <xsd:sequence> <xsd:element name="authority" type="xsd:string" minOccurs="0" nillable="true" /> </xsd:sequence> </xsd:complexType> </xsd:schema> <xsd:schema targetNamespace="http://service.appfuse.org" elementFormDefault="qualified" attributeFormDefault="qualified"> <xsd:element name="getUsers"> <xsd:complexType> <xsd:sequence> <xsd:element name="in0" type="ns1:User" nillable="true" minOccurs="1" maxOccurs="1" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="getUsersResponse"> <xsd:complexType> <xsd:sequence> <xsd:element name="out" type="ns1:ArrayOfUser" nillable="true" minOccurs="1" maxOccurs="1" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="setUserDAO"> <xsd:complexType> <xsd:sequence> <xsd:element name="in0" type="ns3:UserDAO" nillable="true" minOccurs="1" maxOccurs="1" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="setUserDAOResponse"> <xsd:complexType /> </xsd:element> <xsd:element name="getUser"> <xsd:complexType> <xsd:sequence> <xsd:element name="in0" type="xsd:string" nillable="true" minOccurs="1" maxOccurs="1" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="getUserResponse"> <xsd:complexType> <xsd:sequence> <xsd:element name="out" type="ns1:User" nillable="true" minOccurs="1" maxOccurs="1" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="saveUser"> <xsd:complexType> <xsd:sequence> <xsd:element name="in0" type="ns1:User" nillable="true" minOccurs="1" maxOccurs="1" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="saveUserResponse"> <xsd:complexType /> </xsd:element> <xsd:complexType name="UserExistsException" /> <xsd:element name="UserExistsException" type="tns:UserExistsException" /> <xsd:element name="removeUser"> <xsd:complexType> <xsd:sequence> <xsd:element name="in0" type="xsd:string" nillable="true" minOccurs="1" maxOccurs="1" /> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="removeUserResponse"> <xsd:complexType /> </xsd:element> </xsd:schema> <xsd:schema targetNamespace="http://dao.appfuse.org" elementFormDefault="qualified" attributeFormDefault="qualified"> <xsd:complexType name="UserDAO" /> </xsd:schema> </wsdl:types> <wsdl:message name="getUserResponse"> <wsdl:part element="tns:getUserResponse" name="parameters" /> </wsdl:message> <wsdl:message name="getUsersRequest"> <wsdl:part element="tns:getUsers" name="parameters" /> </wsdl:message> <wsdl:message name="removeUserResponse"> <wsdl:part element="tns:removeUserResponse" name="parameters" /> </wsdl:message> <wsdl:message name="setUserDAOResponse"> <wsdl:part element="tns:setUserDAOResponse" name="parameters" /> </wsdl:message> <wsdl:message name="removeUserRequest"> <wsdl:part element="tns:removeUser" name="parameters" /> </wsdl:message> <wsdl:message name="saveUserRequest"> <wsdl:part element="tns:saveUser" name="parameters" /> </wsdl:message> <wsdl:message name="setUserDAORequest"> <wsdl:part element="tns:setUserDAO" name="parameters" /> </wsdl:message> <wsdl:message name="UserExistsException"> <wsdl:part element="tns:UserExistsException" name="UserExistsException" /> </wsdl:message> <wsdl:message name="getUsersResponse"> <wsdl:part element="tns:getUsersResponse" name="parameters" /> </wsdl:message> <wsdl:message name="saveUserResponse"> <wsdl:part element="tns:saveUserResponse" name="parameters" /> </wsdl:message> <wsdl:message name="getUserRequest"> <wsdl:part element="tns:getUser" name="parameters" /> </wsdl:message> <wsdl:portType name="UserManagerPortType"> <wsdl:operation name="getUsers"> <wsdl:input message="tns:getUsersRequest" name="getUsersRequest" /> <wsdl:output message="tns:getUsersResponse" name="getUsersResponse" /> </wsdl:operation> <wsdl:operation name="setUserDAO"> <wsdl:input message="tns:setUserDAORequest" name="setUserDAORequest" /> <wsdl:output message="tns:setUserDAOResponse" name="setUserDAOResponse" /> </wsdl:operation> <wsdl:operation name="getUser"> <wsdl:input message="tns:getUserRequest" name="getUserRequest" /> <wsdl:output message="tns:getUserResponse" name="getUserResponse" /> </wsdl:operation> <wsdl:operation name="saveUser"> <wsdl:input message="tns:saveUserRequest" name="saveUserRequest" /> <wsdl:output message="tns:saveUserResponse" name="saveUserResponse" /> <wsdl:fault message="tns:UserExistsException" name="UserExistsException" /> </wsdl:operation> <wsdl:operation name="removeUser"> <wsdl:input message="tns:removeUserRequest" name="removeUserRequest" /> <wsdl:output message="tns:removeUserResponse" name="removeUserResponse" /> </wsdl:operation> </wsdl:portType> <wsdl:binding name="UserManagerHttpBinding" type="tns:UserManagerPortType"> <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="getUsers"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="getUsersRequest"> <wsdlsoap:body use="literal" /> </wsdl:input> <wsdl:output name="getUsersResponse"> <wsdlsoap:body use="literal" /> </wsdl:output> </wsdl:operation> <wsdl:operation name="setUserDAO"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="setUserDAORequest"> <wsdlsoap:body use="literal" /> </wsdl:input> <wsdl:output name="setUserDAOResponse"> <wsdlsoap:body use="literal" /> </wsdl:output> </wsdl:operation> <wsdl:operation name="getUser"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="getUserRequest"> <wsdlsoap:body use="literal" /> </wsdl:input> <wsdl:output name="getUserResponse"> <wsdlsoap:body use="literal" /> </wsdl:output> </wsdl:operation> <wsdl:operation name="saveUser"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="saveUserRequest"> <wsdlsoap:body use="literal" /> </wsdl:input> <wsdl:output name="saveUserResponse"> <wsdlsoap:body use="literal" /> </wsdl:output> <wsdl:fault name="UserExistsException"> <wsdlsoap:fault name="UserExistsException" use="literal" /> </wsdl:fault> </wsdl:operation> <wsdl:operation name="removeUser"> <wsdlsoap:operation soapAction="" /> <wsdl:input name="removeUserRequest"> <wsdlsoap:body use="literal" /> </wsdl:input> <wsdl:output name="removeUserResponse"> <wsdlsoap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="UserManager"> <wsdl:port binding="tns:UserManagerHttpBinding" name="UserManagerHttpPort"> <wsdlsoap:address location="http://localhost:8080/appfuse-xfire/services/UserService" /> </wsdl:port> </wsdl:service> </wsdl:definitions> The next part of this howto deals with unit-testing of your webservices. You can do that on various levels of the xfire-stack. The third part is about client-generation and will follow (hopefully) soon. So stay tuned!
|