A WSDL is a service contract between the web services provider (server) and service requestor (client), and is primarily used for SOAP services. It is similar to the contract created by an interface for a Java class.


Spring Web Services provides support for exposing a WSDL using an instance of org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition


DefaultWsdl11Definition, which autogenerates the WSDL based an instance of
org.springframework.xml.xsd.SimpleXsdSchema.


SimpleXsdSchema is used to expose Ticket.xsd as source schema for WSDL generation,

Generating a WSDL File Using an XML Schema


package com.apress.prospringintegration.webservice.web;
import com.apress.prospringintegration.webservice.domain.TicketRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.castor.CastorMarshaller;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;

import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor;
import org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@SuppressWarnings("unused")
@Configuration
public class TicketIssuerServiceConfiguration {
public static String NAMESPACE = "http://prospringintegration.com/tk/schemas";
// the ws:inbound-gateway is in fact a reference to this base Spring WS object
@Value("#{wsInboundGateway}")
private MessageEndpoint wsInboundGateway;
@Bean
public XsdSchema schema() {
SimpleXsdSchema xsdSchema = new SimpleXsdSchema();
xsdSchema.setXsd(new ClassPathResource("Ticket.xsd"));
return xsdSchema;
}
@Bean
public DefaultWsdl11Definition tickets() throws Throwable {
DefaultWsdl11Definition defaultWsdl11Definition =
new DefaultWsdl11Definition();
defaultWsdl11Definition.setSchema(schema());
defaultWsdl11Definition.setPortTypeName("TicketRequest");
defaultWsdl11Definition.setLocationUri("/tickets");
defaultWsdl11Definition.setTargetNamespace(NAMESPACE);
return defaultWsdl11Definition;
}
@Bean
public PayloadRootQNameEndpointMapping payloadRootQNameEndpointMapping() {
String fqn = String.format("{%s}%s", NAMESPACE, "TicketRequest");
Map<String, MessageEndpoint> endpoints = new HashMap<String, MessageEndpoint>();
endpoints.put(fqn, wsInboundGateway);
PayloadRootQNameEndpointMapping payloadRootQNameEndpointMapping =
new PayloadRootQNameEndpointMapping();
payloadRootQNameEndpointMapping.setEndpointMap(endpoints);
payloadRootQNameEndpointMapping.setInterceptors(
new EndpointInterceptor[]{new PayloadLoggingInterceptor()});
return payloadRootQNameEndpointMapping;
}

@Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
SimpleUrlHandlerMapping simpleHandlerMapping = new SimpleUrlHandlerMapping();
simpleHandlerMapping.setDefaultHandler(soapMessageDispatcher());
Properties urlMap = new Properties();
urlMap.setProperty("*.wsdl", "tickets");
simpleHandlerMapping.setMappings(urlMap);
return simpleHandlerMapping;
}
@Bean
public SoapMessageDispatcher soapMessageDispatcher() {
return new SoapMessageDispatcher();
}
}


org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping is
used to map the incoming request to the service endpoints. In addition,
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping is used to specifically expose the WSDL file through the URI /tickets.wsdl.


To test the inbound web services gateway example using Castor marshalling, the ticket-servicemarshaller project must be built and deployed to a servlet container such as Tomcat or Jetty. To build the war, simply execute mvn install and copy the resulting war file within the target directory to the servlet container’s webapps directory.


Use a browser and go to the URL http://localhost:8080/ticketservice-marshalling-1.0/ticketservice/tickets.wsdl.

The WSDL shown will appear, describing the inbound gateway endpoint. You can also use this WSDL to create a client using one of the WSDL-to-Java tools available from projects such as Axis, CXF, or XFire.

Ouput of WSDL Generation tickets.wsdl


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:sch="http://prospringintegration.com/tk/schemas"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://prospringintegration.com/tk/schemas"
targetNamespace="http://prospringintegration.com/tk/schemas">
<wsdl:types>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
attributeFormDefault="unqualified"
elementFormDefault="qualified"
targetNamespace="http://prospringintegration.com/tk/schemas"
version="1.0">
<xs:element name="TicketRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="priority" type="priorityType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="TicketResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="ticket" type="ticketType"/>
</xs:sequence>

</xs:complexType>
</xs:element>
<xs:complexType name="ticketType">
<xs:sequence>
<xs:element minOccurs="0" name="description" type="xs:string"/>
<xs:element minOccurs="0" name="issueDateTime" type="xs:dateTime"/>
<xs:element minOccurs="0" name="priority" type="priorityType"/>
<xs:element name="ticketId" type="xs:long"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="priorityType">
<xs:restriction base="xs:string">
<xs:enumeration value="low"/>
<xs:enumeration value="medium"/>
<xs:enumeration value="high"/>
<xs:enumeration value="emergency"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
</wsdl:types>
<wsdl:message name="TicketRequest">
<wsdl:part element="tns:TicketRequest" name="TicketRequest">
</wsdl:part>
</wsdl:message>
<wsdl:message name="TicketResponse">
<wsdl:part element="tns:TicketResponse" name="TicketResponse">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="TicketRequest">
<wsdl:operation name="Ticket">
<wsdl:input message="tns:TicketRequest" name="TicketRequest">
</wsdl:input>
<wsdl:output message="tns:TicketResponse" name="TicketResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TicketRequestSoap11" type="tns:TicketRequest">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="Ticket">
<soap:operation soapAction=""/>
<wsdl:input name="TicketRequest">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="TicketResponse">

<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TicketRequestService">
<wsdl:port binding="tns:TicketRequestSoap11" name="TicketRequestSoap11">
<soap:address
location="http://localhost:8080/ticket-service-marshalling-1.0/tickets"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

Outbound Web Services Gateway with XML Marshalling


The Castor marshaller can also be used with the outbound web services gateway. This example will use the same domain and descriptor mapping classes from the inbound gateway example. Similar to the inbound-gateway configuration, the Castor marshaller is set through the marshaller and unmarshaller attributes of the outbound-gateway element

Spring Configuration for Gateway Client Using the Castor Marshaller client.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ws="http://www.springframework.org/schema/integration/ws"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
http://www.springframework.org/schema/integration/ws
http://www.springframework.org/schema/integration/ws/spring-integration-ws-2.0.xsd">
<context:component-scan base-package="com.apress.prospringintegration.webservice.client"/>
<context:property-placeholder location="client.properties"/>
<int:channel id="ticketRequests"/>
<ws:outbound-gateway id="ticketIssueGateway"
request-channel="ticketRequests"
uri="http://${ws.host}:${ws.port}/${ws.context}/ticketservice/tickets"
marshaller="castorMarshaller" unmarshaller="castorMarshaller"/>
</beans>

The Java configuration for the Castor marshaller Since the TicketRequest
instance is sent first to the marshaller, Castor is able to get the reference to this instance and the related domain and descriptor mapping classes.

Java Configuration for the Outbound Gateway Client Using the Castor Marshaller


package com.apress.prospringintegration.webservice.client;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.oxm.castor.CastorMarshaller;
@Configuration
public class TicketWebServiceMarshallingConfiguration {
@Bean
public CastorMarshaller castorMarshaller() {
CastorMarshaller castorMarshaller = new CastorMarshaller();
return castorMarshaller;
}
}

The client code is similar to the first outbound gateway example, However, in this case XML document isn’t created by hand; instead, all the interaction with the gateway
occurs through the domain objects

Outbound Gateway Using the Castor Marshaller Client Class


package com.apress.prospringintegration.webservice.client;
import com.apress.prospringintegration.webservice.domain.Ticket;
import com.apress.prospringintegration.webservice.domain.TicketRequest;
import com.apress.prospringintegration.webservice.domain.TicketResponse;
import com.apress.prospringintegration.webservice.domain.types.PriorityType;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.stereotype.Component;
@Component
public class TicketWebServiceMarshallingClient {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("client.xml");
MessageChannel channel =
context.getBean("ticketRequests", MessageChannel.class);
MessagingTemplate messagingTemplate = new MessagingTemplate();
TicketRequest tr = new TicketRequest();
tr.setDescription("Message Broker Down");
tr.setPriority(PriorityType.EMERGENCY);
System.out.printf("Ticket Request: %s [priority: %s] %n", tr.getDescription(),
tr.getPriority());

Message<TicketRequest> ticketRequestMessage =
MessageBuilder.withPayload(tr).build();
@SuppressWarnings("unchecked")
Message<TicketResponse> message =
(Message<TicketResponse>) messagingTemplate.sendAndReceive(
channel, ticketRequestMessage);
Ticket ticket = message.getPayload().getTicket();
System.out.printf("Ticket Response: %s [id: %d] [priority: %s] [date: %s]%n",
ticket.getDescription(), ticket.getTicketId(),
ticket.getPriority(), ticket.getIssueDateTime());
}
}

The results of running the outbound gateway client code, TicketRequest object is created and sent to the outbound gateway. Castor marshalling handles parsing
the XML. The gateway invokes the web service endpoint and returns the TicketResponse object with the new ticket issued.

Web Services Gateway Example Results Using the Castor Marshaller


Ticket Request: Message Broker Down [priority: emergency]
Ticket Response: Message Broker Down [id: 5433537107850368600] [priority: emergency] [date:Sun Feb 27 12:18:01 PST 2011]

Leave a Reply

Subscribe to Posts | Subscribe to Comments

About This Site

Howdy! My name is Suersh Rohan and I am the developer and maintainer of this blog. It mainly consists of my thoughts and opinions on the technologies I learn,use and develop with.

Blog Archive

Powered by Blogger.

- Copyright © My Code Snapshots -Metrominimalist- Powered by Blogger - Designed by Suresh Rohan -