Providing an RPC style service endpoint
You have two choices. Either you expose the web service as a java service endpoint (JSE) or as an EJB service
endpoint using a stateless session bean. For this tutorial we'll start off providing a JSE. I use code from the
web service samples that you can find as part of the main testsuite.
The service endpoint interface
Typically you start off with a service endpoint interface (SEI) like this
public interface Organization extends Remote { String getContactInfo(String organization) throws RemoteException; Person jobRequest(Person target) throws RemoteException; }
There are certain rules you have to follow for a valid SEI. For example
The SEI must extend Remote
All methods must include RemoteException in their throws clause
Method parameter types are limited to the ones specified by the JAX-RPC specification
The endpoint implementation bean
The SEI defines the java contract of the web service. You will also need to provide an implementation bean.
Here it is
public class OrganizationJSEEndpoint implements Organization { public String getContactInfo(String organization) { log.info("getContactInfo: " + organization); return "The '" + organization + "' boss is currently out of office, please call again."; } public Person jobRequest(Person target) { log.info("jobRequest: " + target); return target; } }
Generating required deployment artifacts
First thing on the bumpy road to a valid WS4EE deployment is to generate the required server side deployment
artifacts. JBossWS does not have its own toolset yet. We recommend you use wscompile from the
Java Web Service Development Pack.
To describe the web service, you need a document in the web service description language (WSDL). The WSDL is
programming language independent. Therefore we need another document that describes the mapping details between
Java and XML, this is called jaxrpc-mapping.xml. Both can be generated with wscompile.
wscompile -cp output/classes -gen:server -f:rpcliteral -mapping jaxrpc-mapping.xml config.xml
wscompile needs a configuration file for its operation, we use
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config"> <service name="OrganizationService" targetNamespace="http://org.jboss.test.webservice/samples" typeNamespace="http://org.jboss.test.webservice/samples/types" packageName="org.jboss.test.webservice.samples"> <interface name="org.jboss.test.webservice.samples.Organization"></interface> </service> </configuration>
The Web Service Description
The WSDL for our SEI is shown next
<definitions name="OrganizationService" targetNamespace="http://org.jboss.test.webservice/samples" xmlns:tns="http://org.jboss.test.webservice/samples" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://org.jboss.test.webservice/samples/types" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> <!-- Complex type definitions --> <types> <schema targetNamespace="http://org.jboss.test.webservice/samples/types" xmlns:tns="http://org.jboss.test.webservice/samples/types" xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> <complexType name="Person"> <sequence> <element name="age" type="int"></element> <element name="name" type="string" nillable="true"></element> </sequence> </complexType> </schema> </types> <!-- The structure of the individual messages --> <message name="Organization_getContactInfo"> <part name="String_1" type="xsd:string"></part> </message> <message name="Organization_getContactInfoResponse"> <part name="result" type="xsd:string"></part> </message> <message name="Organization_jobRequest"> <part name="Person_1" type="ns2:Person"></part> </message> <message name="Organization_jobRequestResponse"> <part name="result" type="ns2:Person"></part> </message> <!-- What operation the service provides and what messages it exchanges --> <portType name="Organization"> <operation name="getContactInfo" parameterOrder="String_1"> <input message="tns:Organization_getContactInfo"/> <output message="tns:Organization_getContactInfoResponse"></output> </operation> <operation name="jobRequest" parameterOrder="Person_1"> <input message="tns:Organization_jobRequest"/> <output message="tns:Organization_jobRequestResponse"></output> </operation> </portType> <!-- How the service is bound --> <binding name="OrganizationBinding" type="tns:Organization"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"></soap:binding> <operation name="getContactInfo"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal" namespace="http://org.jboss.test.webservice/samples"></soap:body> </input> <output> <soap:body use="literal" namespace="http://org.jboss.test.webservice/samples"></soap:body> </output> </operation> <operation name="jobRequest"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal" namespace="http://org.jboss.test.webservice/samples"></soap:body> </input> <output> <soap:body use="literal" namespace="http://org.jboss.test.webservice/samples"></soap:body> </output> </operation> </binding> <!-- Where the service is located --> <service name="OrganizationService"> <port name="OrganizationPort" binding="tns:OrganizationBinding"> <soap:address location="REPLACE_WITH_ACTUAL_URL"></soap:address> </port> </service> </definitions>
Note, the exact location of the service can be left unspecified as this entry will be replaced by JBossWS
during deploytime.
Java to XML mapping
As already mentioned, there is nothing Java specific in the WSDL. How XML namespaces map to
Java packages and other mapping concerns are described in jaxrpc-mapping.xml, which is shown next
<java-wsdl-mapping version="1.1" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://www.ibm.com/webservices/xsd/j2ee_jaxrpc_mapping_1_1.xsd"> <package-mapping> <package-type>org.jboss.test.webservice.samples</package-type> <namespaceURI>http://org.jboss.test.webservice/samples/types</namespaceURI> </package-mapping> <package-mapping> <package-type>org.jboss.test.webservice.samples</package-type> <namespaceURI>http://org.jboss.test.webservice/samples</namespaceURI> </package-mapping> <java-xml-type-mapping> <java-type>org.jboss.test.webservice.samples.Person</java-type> <root-type-qname xmlns:typeNS="http://org.jboss.test.webservice/samples/types">typeNS:Person</root-type-qname> <qname-scope>complexType</qname-scope> <variable-mapping> <java-variable-name>age</java-variable-name> <xml-element-name>age</xml-element-name> </variable-mapping> <variable-mapping> <java-variable-name>name</java-variable-name> <xml-element-name>name</xml-element-name> </variable-mapping> </java-xml-type-mapping> <service-interface-mapping> <service-interface>org.jboss.test.webservice.samples.OrganizationService</service-interface> <wsdl-service-name xmlns:serviceNS="http://org.jboss.test.webservice/samples">serviceNS:OrganizationService</wsdl-service-name> <port-mapping> <port-name>OrganizationPort</port-name> <java-port-name>OrganizationPort</java-port-name> </port-mapping> </service-interface-mapping> <service-endpoint-interface-mapping> <service-endpoint-interface>org.jboss.test.webservice.samples.Organization</service-endpoint-interface> <wsdl-port-type xmlns:portTypeNS="http://org.jboss.test.webservice/samples">portTypeNS:Organization</wsdl-port-type> <wsdl-binding xmlns:bindingNS="http://org.jboss.test.webservice/samples">bindingNS:OrganizationBinding</wsdl-binding> <service-endpoint-method-mapping> <java-method-name>getContactInfo</java-method-name> <wsdl-operation>getContactInfo</wsdl-operation> <method-param-parts-mapping> <param-position>0</param-position> <param-type>java.lang.String</param-type> <wsdl-message-mapping> <wsdl-message xmlns:wsdlMsgNS="http://org.jboss.test.webservice/samples">wsdlMsgNS:Organization_getContactInfo</wsdl-message> <wsdl-message-part-name>String_1</wsdl-message-part-name> <parameter-mode>IN</parameter-mode> </wsdl-message-mapping> </method-param-parts-mapping> <wsdl-return-value-mapping> <method-return-value>java.lang.String</method-return-value> <wsdl-message xmlns:wsdlMsgNS="http://org.jboss.test.webservice/samples">wsdlMsgNS:Organization_getContactInfoResponse</wsdl-message> <wsdl-message-part-name>result</wsdl-message-part-name> </wsdl-return-value-mapping> </service-endpoint-method-mapping> <service-endpoint-method-mapping> <java-method-name>jobRequest</java-method-name> <wsdl-operation>jobRequest</wsdl-operation> <method-param-parts-mapping> <param-position>0</param-position> <param-type>org.jboss.test.webservice.samples.Person</param-type> <wsdl-message-mapping> <wsdl-message xmlns:wsdlMsgNS="http://org.jboss.test.webservice/samples">wsdlMsgNS:Organization_jobRequest</wsdl-message> <wsdl-message-part-name>Person_1</wsdl-message-part-name> <parameter-mode>IN</parameter-mode> </wsdl-message-mapping> </method-param-parts-mapping> <wsdl-return-value-mapping> <method-return-value>org.jboss.test.webservice.samples.Person</method-return-value> <wsdl-message xmlns:wsdlMsgNS="http://org.jboss.test.webservice/samples">wsdlMsgNS:Organization_jobRequestResponse</wsdl-message> <wsdl-message-part-name>result</wsdl-message-part-name> </wsdl-return-value-mapping> </service-endpoint-method-mapping> </service-endpoint-interface-mapping> </java-wsdl-mapping>
The endpoint as a web application
A java service endpoint is deployed as a web application. Therefore we need a web.xml deployment descriptor, which
we will have to code by hand.
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <servlet> <servlet-name>Organization</servlet-name> <servlet-class>org.jboss.test.webservice.samples.OrganizationJSEEndpoint</servlet-class> </servlet> <servlet-mapping> <servlet-name>Organization</servlet-name> <url-pattern>/Organization</url-pattern> </servlet-mapping> </web-app>
Note, that we declare the endpoint implemenation bean in the <servlet-class> element, but it is actually not
a servlet at all.
The webservices deployment descriptor
One more descriptor is needed that glues everything together. It is called webservices.xml, is placed in WEB-INF, and must also be coded
by hand. Here it is
<webservices xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd" version="1.1"> <webservice-description> <webservice-description-name>OrganizationServiceJSE</webservice-description-name> <wsdl-file>WEB-INF/wsdl/OrganizationService.wsdl</wsdl-file> <jaxrpc-mapping-file>WEB-INF/jaxrpc-mapping.xml</jaxrpc-mapping-file> <port-component> <port-component-name>PortComponent</port-component-name> <wsdl-port>OrganizationPort</wsdl-port> <service-endpoint-interface>org.jboss.test.webservice.samples.Organization</service-endpoint-interface> <service-impl-bean> <servlet-link>Organization</servlet-link> </service-impl-bean> </port-component> </webservice-description> </webservices>
Deployment to JBoss
Then we package everything together and deploy to JBoss. On the server we should see messages like this
23:12:56,515 INFO [TomcatDeployer] deploy, ctxPath=/ws4ee-samples-server-jse, warUrl=file:/.../ws4ee-samples-server-jse-exp.war/ 23:12:57,125 INFO [WSDLFilePublisher] WSDL published to: file:/.../data/wsdl/ws4ee-samples-server-jse.war/OrganizationService.wsdl 23:12:57,546 INFO [AxisService] WSDD published to: ...\data\wsdl\ws4ee-samples-server-jse.war\PortComponent.wsdd 23:12:58,328 INFO [AxisService] Web Service deployed: http://TDDELL:8080/ws4ee-samples-server-jse/Organization
A potential client can access the WSDL from this address
http://TDDELL:8080/ws4ee-samples-server-jse/Organization?wsdl
How to connect to this endpoint from a Java client will be shown in the next tutorial.
Comments