Titel-Logo
Projektstudien
TraceLogger
Basics of Cryptography
Custom JBossAS Login
SOAP Webservice
The Idea
Technologies
Project Structure
Service Definition
WSDL
XML Schema
Implementation
Descriptor
XML Signature
Installation and Test
Downloads
Role Based Access Control
Service definition - WSDL

Our service defines exactly one operation, namely the findPrice operation. This is an operation which expects some WKNs or ISINs as input and responds with the appropriate market prices or with a fault message if an error occurres. The operation follows therefore the request/response pattern. Interface definitions are denoted with the wsdl:portType tag in WSDL 1.1:

25 ...
26 <wsdl:portType name="SecurityPriceServicePortType">
27 <wsdl:operation name="findPrice">
28 <wsdl:input name="SecurityPriceServiceRequest" message="tns:SecurityPriceServiceRequest"/>
29 <wsdl:output name="SecurityPriceServiceResponse" message="tns:SecurityPriceServiceResponse"/>
30 <wsdl:fault name="SecurityPriceServiceException" message="tns:SecurityPriceServiceException"/>
31 </wsdl:operation>
32 </wsdl:portType>
33 ...

The wsdl:input, wsdl:output and wsdl:fault elements from line 28, 29 and 30 are in turn referencing the relevant messages which are describing the data being exchanged between the Web service and its clients during such a operation. For now we are following the input message:

13 ...
14 <wsdl:message name="SecurityPriceServiceRequest">
15 <wsdl:part name="SecurityPriceServiceRequest" element="tns:SecurityPriceServiceRequest"/>
16 </wsdl:message>
17 ...

For every expected input parameter the wsdl:message tag contains a wsdl:part element. In this case we are expecting only one parameter and this is the request itself, mainly consisting of a list of IDs identifying the securities. The element attribut refers already to an xml element with the (qualified) name tns:SecurityPriceServiceRequest. How this element actually looks like is defined within the (external) XML schema:

7 ...
8 <wsdl:types>
9 <xsd:schema targetNamespace="http://de.christofreichardt/SecurityPriceService">
10 <xsd:include schemaLocation="SecurityPriceServiceSchema.xsd"/>
11 </xsd:schema>
12 </wsdl:types>
13 ...

The wsdl:output and wsdl:fault elements are connected in the exact same manner with elements whose types are defined within the external schema. Before I discuss the types within the schema another important section of the WSDL document remains to be shown, namely the binding:

33 ...
34 <wsdl:binding name="SecurityPriceServiceBinding" type="tns:SecurityPriceServicePortType">
35 <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
36 <wsdl:operation name="findPrice">
37 <soap:operation soapAction="http://de.christofreichardt/SecurityPriceService/findPrice"/>
38 <wsdl:input name="SecurityPriceServiceRequest">
39 <soap:body use="literal"/>
40 </wsdl:input>
41 ...
47 </wsdl:operation>
48 </wsdl:binding>
49 ...

The binding refers to the above presented interface definition, that is the wsdl:portType and describes how the findPrice operation will be actually transmitted over the wire. Of course we are using SOAP messages on top of the HTTP protocol here. Furthermore we are specifying the document/literal style which means that the payload contains only the actual data to be passed to the service. Today the document/literal style is the recommended practise because the data going over the wire can be validated against the employed XML schema without much ado. This is convenient when the client and the service are managed by different platforms, e.g. by Java and .NET.

You may review the complete SecurityPriceService.wsdl.

[Top]

Service definition - XML Schema

The namespace of all XML elements and attributs in connection with the SecurityPriceService has been specified with http://de.christofreichardt/SecurityPriceService. Our schema document targets this namespace in line 4. Additionally, we declare a prefix for this namespace in line 5 to distinguish our to be defined elements from other elements (e.g. elements out of the XML schema namespace). Now we can continue with our exploration of the message connected with the wsdl:input of the findPrice operation:

3 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
4 targetNamespace="http://de.christofreichardt/SecurityPriceService"
5 xmlns:tns="http://de.christofreichardt/SecurityPriceService"
6 elementFormDefault="qualified">
7
8 <xsd:element name="SecurityPriceServiceRequest" type="tns:SecurityPriceServiceRequest"/>
9 <xsd:element name="SecurityPriceServiceResponse" type="tns:SecurityPriceServiceResponse"/>
10 <xsd:element name="SecurityPriceServiceFault" type="tns:SecurityPriceServiceFault"/>
11
12 <xsd:complexType name="SecurityPriceServiceRequest">
13 <xsd:sequence>
14 <xsd:element name="UserId" type="xsd:string" />
15 <xsd:element name="TransactionId" type="xsd:unsignedInt" />
16 <xsd:choice maxOccurs="25">
17 <xsd:element name="WKN" type="xsd:string"/>
18 <xsd:element name="ISIN" type="xsd:string"/>
19 </xsd:choice>
20 </xsd:sequence>
21 <xsd:attribute name="provider" type="xsd:string" use="optional" default="OnVista"/>
22 </xsd:complexType>
23 ...
96 </xsd:schema>

We see the declaration of a root element named SecurityPriceServiceRequest of type tns:SecurityPriceServiceRequest in line 8. Sometimes (complex) types are denoted with the postfix 'Type' (that would be SecurityPriceServiceRequestType) to differentiate between types and elements, but in our case this would lead to Java classes with the same postfix and this would be rather unusual. Our SecurityPriceServiceRequest element consists of an UserId element, a TransactionId element, a sequence of maximal 25 WKN or ISIN elements and an provider attribut with the default value OnVista. The decision to use an attribute to store the provider value results from the XML Schema specification concerning the occurence constraints, see 2.2.1 Occurrence Constraints within the XML schema recommendation of the W3C. It is specified that if an attribut (with a default value) that does not appear at all within an instance document the schema processor must provide the attribut together with its default value, whereas the handling of (missing) elements with default values is slightly different. We will look how wsconsume deals with this requirement later on.

How could such a SecurityPriceServiceRequest actually look like? See the subsequent example:

1 <SecurityPriceServiceRequest xmlns="http://de.christofreichardt/SecurityPriceService" provider="Test">
2 <UserId>tester</UserId>
3 <TransactionId>35</TransactionId>
4 <WKN>623100</WKN>
5 <WKN>716460</WKN>
6 <WKN>514000</WKN>
7 </SecurityPriceServiceRequest>

The above XML fragment will be embedded within a SOAP envelope (and body) at runtime. Next we look at how the SecurityPriceServiceResponse is defined. This will be a bit more complicated, since there is more than one type of security to consider. This demo takes shares, index certificates and options into account. Therefore we define a AbstractSecurityPrice type as starting point. This type consists of the actual security, that is its name, WKN and ISIN as well as its current rate (bid and ask). The OptionPrice type for example extends this AbstractSecurityPrice by adding the strike price, an expiration date and the way of the exercise (american or european).

3 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
4 targetNamespace="http://de.christofreichardt/SecurityPriceService"
5 xmlns:tns="http://de.christofreichardt/SecurityPriceService"
6 elementFormDefault="qualified">
7
8 <xsd:element name="SecurityPriceServiceRequest" type="tns:SecurityPriceServiceRequest"/>
9 <xsd:element name="SecurityPriceServiceResponse" type="tns:SecurityPriceServiceResponse"/>
10 <xsd:element name="SecurityPriceServiceFault" type="tns:SecurityPriceServiceFault"/>
23 ...
24 <xsd:complexType name="SecurityPriceServiceResponse">
25 <xsd:sequence>
26 <xsd:element name="Timestamp" type="xsd:dateTime"/>
27 <xsd:choice maxOccurs="25">
28 <xsd:element name="SharePrice" type="tns:SharePrice"/>
29 <xsd:element name="IndexPrice" type="tns:IndexPrice"/>
30 <xsd:element name="OptionPrice" type="tns:OptionPrice"/>
31 </xsd:choice>
32 </xsd:sequence>
33 </xsd:complexType>
40 ...
41 <xsd:complexType name="Security">
42 <xsd:sequence>
43 <xsd:element name="Name" type="xsd:string"/>
44 <xsd:element name="WKN" type="xsd:string"/>
45 <xsd:element name="ISIN" type="xsd:string"/>
46 </xsd:sequence>
47 </xsd:complexType>
48
49 <xsd:complexType name="AbstractSecurityPrice">
50 <xsd:sequence>
51 <xsd:element name="Security" type="tns:Security"/>
52 <xsd:element name="Bid" type="xsd:decimal"/>
53 <xsd:element name="Ask" type="xsd:decimal"/>
54 </xsd:sequence>
55 </xsd:complexType>
76 ...
77 <xsd:simpleType name="Exercise">
78 <xsd:restriction base="xsd:string">
79 <xsd:enumeration value="european"/>
80 <xsd:enumeration value="american"/>
81 </xsd:restriction>
82 </xsd:simpleType>
83
84 <xsd:complexType name="OptionPrice">
85 <xsd:complexContent>
86 <xsd:extension base="tns:AbstractSecurityPrice">
87 <xsd:sequence>
88 <xsd:element name="StrikePrice" type="xsd:decimal"/>
89 <xsd:element name="ExpirationDate" type="xsd:dateTime"/>
90 <xsd:element name="Exercise" type="tns:Exercise"/>
91 </xsd:sequence>
92 </xsd:extension>
93 </xsd:complexContent>
94 </xsd:complexType>
95
96 </xsd:schema>

The definition of the SecurityPriceServiceResponse type starts at line 24. Such a response consists of a timestamp and the list of the requested market prices. Then comes the definition of the Security type. This is simply a sequence of the security's name, its WKN and ISIN. Any security price consists of the Security itself and its market rate (bid and ask). We take the OptionPrice as an example for a specialised security price. Such an OptionPrice simply adds the strike price, an expiration date and the way of the exercise of the option.

See below how an actual SecurityPriceServiceResponse might look like:

1 <SecurityPriceServiceResponse xmlns="http://de.christofreichardt/SecurityPriceService">
2 <Timestamp>2014-10-13T19:09:20.734+02:00</Timestamp>
3 <OptionPrice>
4 <Security>
5 <Name>CALL auf DAX Performance-Index</Name>
6 <WKN>DE7LES</WKN>
7 <ISIN>DE000DE7LES6</ISIN>
8 </Security>
9 <Bid>10.810</Bid>
10 <Ask>10.820</Ask>
11 <StrikePrice>7.600</StrikePrice>
12 <ExpirationDate>2014-12-17T00:00:00.000+02:00</ExpirationDate>
12 <Exercise>american</Exercise>
13 </OptionPrice>
14 </SecurityPriceServiceResponse>

You may review the complete SecurityPriceServiceSchema.xsd.

[Top]

Service definition - Implementation

The wsdl:portType definition translates directly into a Java (endpoint) interface. Apache CXF does that for us during the generate-sources phase of the build lifecycle:

1 /**
2 * This class was generated by Apache CXF 2.7.10
3 * 2014-10-17T16:51:02.879+02:00
4 * Generated source version: 2.7.10
5 *
6 */
7 @WebService(targetNamespace = "http://de.christofreichardt/SecurityPriceService", name = "SecurityPriceServicePortType")
8 @XmlSeeAlso({ObjectFactory.class})
9 @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
10 public interface SecurityPriceServicePortType {
11 @WebMethod(action = "http://de.christofreichardt/SecurityPriceService/findPrice")
12 @WebResult(name = "SecurityPriceServiceResponse", targetNamespace = "http://de.christofreichardt/SecurityPriceService", partName = "SecurityPriceServiceResponse")
13 public SecurityPriceServiceResponse findPrice(
14 @WebParam(partName = "SecurityPriceServiceRequest", name = "SecurityPriceServiceRequest", targetNamespace = "http://de.christofreichardt/SecurityPriceService")
15 SecurityPriceServiceRequest securityPriceServiceRequest
16 ) throws SecurityPriceServiceException;
17 }

This boils down to the interface signature as shown below:

20 public interface SecurityPriceServicePortType {
21 public SecurityPriceServiceResponse findPrice(SecurityPriceServiceRequest securityPriceServiceRequest) throws SecurityPriceServiceException;
22 }

Both SecurityPriceServiceRequest and SecurityPriceServiceResponse are JAXB value classes which have been generated for us too. To get an idea I present the SecurityPriceServiceRequest value class below:

1 @XmlAccessorType(XmlAccessType.FIELD)
2 @XmlType(name = "SecurityPriceServiceRequest", propOrder = {
3 "userId",
4 "transactionId",
5 "wknOrISIN"
6 })
7 public class SecurityPriceServiceRequest {
8
9 @XmlElement(name = "UserId", required = true)
10 protected String userId;
11 @XmlElement(name = "TransactionId")
12 @XmlSchemaType(name = "unsignedInt")
13 protected long transactionId;
14 @XmlElementRefs({
15 @XmlElementRef(name = "ISIN", namespace = "http://de.christofreichardt/SecurityPriceService", type = JAXBElement.class, required = false),
16 @XmlElementRef(name = "WKN", namespace = "http://de.christofreichardt/SecurityPriceService", type = JAXBElement.class, required = false)
17 })
18 protected List<JAXBElement<String>> wknOrISIN;
19 @XmlAttribute(name = "provider")
20 protected String provider;
21
22 public String getUserId() {
23 return userId;
24 }
25
26 public void setUserId(String value) {
27 this.userId = value;
28 }
29
30 public long getTransactionId() {
31 return transactionId;
32 }
33
34 public void setTransactionId(long value) {
35 this.transactionId = value;
36 }
37
38 public List<JAXBElement<String>> getWKNOrISIN() {
39 if (wknOrISIN == null) {
40 wknOrISIN = new ArrayList<JAXBElement<String>>();
41 }
42 return this.wknOrISIN;
43 }
44
45 public String getProvider() {
46 if (provider == null) {
47 return "OnVista";
48 } else {
49 return provider;
50 }
51 }
52
53 public void setProvider(String value) {
54 this.provider = value;
55 }
56 }

The JAX-WS runtime uses these value classes to generate the appropriate XML at execution time. See e.g. the definition of the provider property in the lines 19,20 and 45-50. Thus the code generation has taken the default value for the provider into account.

Of course the web service must provide an implementation of the SecurityPriceServicePortType (endpoint) interface:

1 @WebService(
2 endpointInterface = "de.christofreichardt.jaxws.securitypriceservice.SecurityPriceServicePortType",
3 serviceName = "SecurityPriceService")
4 @HandlerChain(file = "SecurityPriceService_handler.xml")
5 public class SecurityPriceServicePortTypeImpl implements SecurityPriceServicePortType, Traceable {
6 @Override
7 public SecurityPriceServiceResponse findPrice(SecurityPriceServiceRequest securityPriceServiceRequest) throws SecurityPriceServiceException {
8 ...
9 }
10 }

Since I didn't have a direct connection to the stock exchange, I'm checking the relevant online resources (like OnVista) to get the market rates. When evaluating these resources I'm using the Jsoup html parser to retrieve the desired pieces of information. This presupposes a particular and well known page layout. If OnVista changes this layout the price extraction must be reworked. The implementation should not be tight to a particular provider or to any certain price determination. Thus the Strategy pattern is applied to abstract from the actual price extraction. An offline provider for testing purposes has been made available too.

[Top]

Web descriptor (web.xml)

It has to be mentioned that the provided service uses a web descriptor. The descriptor mainly maps endpoint implementations on url patterns. The application server then turns it into an address at which the endpoint can be accessed. That is this overrides the wsdl:port section of the WSDL file (the server would do this anyway).

1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
3 <servlet>
4 <servlet-name>WSServlet</servlet-name>
5 <servlet-class>de.christofreichardt.jaxws.securitypriceservice.SecurityPriceServicePortTypeImpl</servlet-class>
6 </servlet>
7 <servlet-mapping>
8 <servlet-name>WSServlet</servlet-name>
9 <url-pattern>/securitypriceservice</url-pattern>
10 </servlet-mapping>
11 <session-config>
12 <session-timeout>
13 30
14 </session-timeout>
15 </session-config>
16 </web-app>

[Top]

Valid XHTML 1.0 Strict