JSE Server Side Programming Model
The JSE server side programming model is about exposing plain java service endpoints.
The JSE is deployed as a standard war archive plus an additional webservices.xml deployment descriptor.
Service Endpoint Interface
The SEI declares the endpoint implementation methods that are to be exposed as web service operations.
For the JSE we use the same service endpoint interface as for the EJB service endpoint.
Web Service Description Language
To describe the functionality of a service endpoint, we use an interoperable document format, the WSDL.
The Java Web Service Development Pack comes
with the tools needed to generate the WSDL from the service endpoint interface.
To generate a WSDL that uses document/literal, you would use something similar to:
wscompile -cp ../../output/classes -gen:server -f:documentliteral -d WEB-INF/wsdl -mapping WEB-INF/OrganizationServiceJSE_Mapping.xml config.xml <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config"> <service name="OrganizationServiceJSE" targetNamespace="http://com.underworld.crimeportal" typeNamespace="http://com.underworld.crimeportal/types" packageName="com.underworld.crimeportal"> <interface name="com.underworld.crimeportal.OrganizationEndpoint"></interface> </service> </configuration>
The options to wscompile are described as part
of the jaxrpc documentation that comes with the JWSDP.
The webservice tutorial is also a good starting point.
Here is a WSDL, that corresponds to the service endpoint interface from above.
<definitions name="OrganizationServiceJSE" targetNamespace="http://com.underworld.crimeportal" xmlns:tns="http://com.underworld.crimeportal" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:ns2="http://com.underworld.crimeportal/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> <types> <schema targetNamespace="http://com.underworld.crimeportal/types" ...> <complexType name="getContactInfo"> <sequence> <element name="String_1" type="string" nillable="true"></element> </sequence> </complexType> <complexType name="getContactInfoResponse"> <sequence> <element name="result" type="string" nillable="true"></element> </sequence> </complexType> <element name="getContactInfo" type="tns:getContactInfo"></element> <element name="getContactInfoResponse" type="tns:getContactInfoResponse"></element> </schema> </types> <message name="OrganizationEndpoint_getContactInfo"> <part name="parameters" element="ns2:getContactInfo"></part> </message> <message name="OrganizationEndpoint_getContactInfoResponse"> <part name="result" element="ns2:getContactInfoResponse"></part> </message> <portType name="OrganizationEndpoint"> <operation name="getContactInfo"> <input message="tns:OrganizationEndpoint_getContactInfo"/> <output message="tns:OrganizationEndpoint_getContactInfoResponse"></output> </operation> </portType> <binding name="OrganizationEndpointBinding" type="tns:OrganizationEndpoint"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap:binding> <operation name="getContactInfo"> <soap:operation soapAction=""></soap:operation> <input> <soap:body use="literal"></soap:body> </input> <output> <soap:body use="literal"></soap:body> </output> </operation> </binding> <service name="OrganizationServiceJSE"> <port name="OrganizationEndpointPort" binding="tns:OrganizationEndpointBinding"> <soap:address location="REPLACE_WITH_ACTUAL_URL"></soap:address> </port> </service> </definitions>
In this example we use the 'document' style wich results in two XML schema type definitions in the wsdl.
There is a lot to say about the different encoding styles.
Here is a selection of good articles
Also note, that Axis defaults to rpc/encoded, which strictly speaking is not J2EE compliant because the basic
profile does not allow it.
JAX-RPC Mapping Files
In addition to a service endpoint interface and a WSDL file, the Web Service must include a JAX-RPC mapping file.
The example below shows the complete jaxrpc mapping as generated by wscompile.
<java-wsdl-mapping ...> <package-mapping> <package-type>com.underworld.crimeportal</package-type> <namespaceURI>http://com.underworld.crimeportal/types</namespaceURI> </package-mapping> <package-mapping> <package-type>com.underworld.crimeportal</package-type> <namespaceURI>http://com.underworld.crimeportal</namespaceURI> </package-mapping> <java-xml-type-mapping> <java-type>com.underworld.crimeportal.OrganizationEndpoint_getContactInfo_ResponseStruct</java-type> <root-type-qname xmlns:typeNS="http://com.underworld.crimeportal/types">typeNS:getContactInfoResponse</root-type-qname> <qname-scope>complexType</qname-scope> <variable-mapping> <java-variable-name>result</java-variable-name> <xml-element-name>result</xml-element-name> </variable-mapping> </java-xml-type-mapping> <java-xml-type-mapping> <java-type>com.underworld.crimeportal.OrganizationEndpoint_getContactInfo_RequestStruct</java-type> <root-type-qname xmlns:typeNS="http://com.underworld.crimeportal/types">typeNS:getContactInfo</root-type-qname> <qname-scope>complexType</qname-scope> <variable-mapping> <java-variable-name>String_1</java-variable-name> <xml-element-name>String_1</xml-element-name> </variable-mapping> </java-xml-type-mapping> <service-interface-mapping> <service-interface>com.underworld.crimeportal.OrganizationServiceJSE</service-interface> <wsdl-service-name xmlns:serviceNS="http://com.underworld.crimeportal">serviceNS:OrganizationServiceJSE</wsdl-service-name> <port-mapping> <port-name>OrganizationEndpointPort</port-name> <java-port-name>OrganizationEndpointPort</java-port-name> </port-mapping> </service-interface-mapping> <service-endpoint-interface-mapping> <service-endpoint-interface>com.underworld.crimeportal.OrganizationEndpoint</service-endpoint-interface> <wsdl-port-type xmlns:portTypeNS="http://com.underworld.crimeportal">portTypeNS:OrganizationEndpoint</wsdl-port-type> <wsdl-binding xmlns:bindingNS="http://com.underworld.crimeportal">bindingNS:OrganizationEndpointBinding</wsdl-binding> <service-endpoint-method-mapping> <java-method-name>getContactInfo</java-method-name> <wsdl-operation>getContactInfo</wsdl-operation> <wrapped-element></wrapped-element> <method-param-parts-mapping> <param-position>0</param-position> <param-type>java.lang.String</param-type> <wsdl-message-mapping> <wsdl-message xmlns:wsdlMsgNS="http://com.underworld.crimeportal">wsdlMsgNS:OrganizationEndpoint_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://com.underworld.crimeportal">wsdlMsgNS:OrganizationEndpoint_getContactInfoResponse</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>
Packaging the service endpoint
The standard deployment descriptor for web components web.xml, declares the service endpoint implementation.
<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>OrganizationEndpoint</servlet-name> <servlet-class>com.underworld.crimeportal.web.OrganizationEndpointImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>OrganizationEndpoint</servlet-name> <url-pattern>/exactpath/jse</url-pattern> </servlet-mapping> </web-app>
Note, the service endpoint implementation is defined in the <servlet-class> element. This is highly confusing
because it is not a servlet at all, but a simple plain java object.
Additionally, we need the J2EE Web Service deployment descriptor, webservices.xml
<webservices xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:impl="http://com.underworld.crimeportal/ws4ee" 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/server-web.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>OrganizationEndpointPort</wsdl-port> <service-endpoint-interface>com.underworld.crimeportal.OrganizationEndpoint</service-endpoint-interface> <service-impl-bean> <servlet-link>OrganizationEndpoint</servlet-link> </service-impl-bean> </port-component> </webservice-description> </webservices>
Deploy the Web Service to JBoss
When you deploy the war that contains all the artifacts we just taked about, you should see something like this in the
JBoss console
13:24:49,453 INFO [TomcatDeployer] deploy, ctxPath=/samples-server-web, ... 13:24:49,625 INFO [WSDLFilePublisher] WSDL published to: file:/.../server/default/data/wsdl/samples-server-web.war/server-web.wsdl 13:24:49,718 INFO [AxisService] WSDD published to: ...\server\default\data\wsdl\samples-server-web.war\OrganizationServiceJSE.wsdd 13:24:49,718 INFO [AxisService] Web Service deployed: http://localhost:8080/samples-server-web/exactpath/jse
To see the WSDL that describes this service, point your browser to
http://localhost:8080/samples-server-web/exactpath/jse?wsdl
you will see the WSDl from above, with a corrected location.
Accessing the Service from Java
This service can now be accessed from any webservice client. Here is a simple test case, that shows how a java client
would first obtain the WSDL from the remote location, and then invoke getContactInfo on the service endpoint
interface. Please note that in the case of document style web services, the client should be given a pointer to
the jaxrpc-mapping.xml file, which the standard JAXRPC javax.xml.rpc.ServiceFactory does not support.
public void testWebServiceAccess() throws Exception { URL wsdlURL = new URL("http://localhost:8080/samples-server-jse/exactpath/jse?wsdl"); URL mappingURL = new File(resourcePath + "/resources/WEB-INF/OrganizationServiceJSE_Mapping.xml").toURL(); QName serviceName = new QName("http://com.underworld.crimeportal", "OrganizationServiceJSE"); ServiceFactoryImpl factory = (ServiceFactoryImpl)ServiceFactory.newInstance(); Service service = factory.createService(wsdlURL, mappingURL, null, serviceName, null); OrganizationEndpoint endpoint = (OrganizationEndpoint)service.getPort(OrganizationEndpoint.class); String info = endpoint.getContactInfo("mafia"); assertEquals("The 'mafia' boss is currently out of office, please call again.", info); }
Comments