Since we started discussing EPRs in the TAG, I've been struggling for lack of a completely filled-in example. I've now produced one, backed by running code (trivial, almost all auto-generated). I'm short on time, but I thought I'd at least get a preliminary version out there so people can see an end-to-end illustration.
I've been helped by a sample and tutorial that comes with the Apache WSRF toolkit, but my example is much simpler than the example they start with.
A version of our old friend the stockquote service, but treating the stock itself as an EndpointParameter. Only one operation at the moment, namely LastTradePrice, but others could easily be added.
Here's the WSDL, with some comments inline.
<?xml version='1.0'?> <definitions targetNamespace="http://example.com/stockquote" xmlns:ex="http://example.com/stockquote" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <schema targetNamespace="http://example.com/stockquote" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
The request element is empty, as the only relevant 'parameter' is stock symbol, which is part of the EPR:
<element name="TradePriceRequest"> <complexType/> </element>
The response is pretty trivial:
<element name="TradePrice"> <complexType> <sequence> <element name="price" type="float"/> </sequence> <attribute name="id" type="ID"/> </complexType> </element> </schema> </types>
The messages are trivially based on the elements/types above:
<message name="GetLastTradePriceInput"> <part name="body" element="ex:TradePriceRequest"/> </message> <message name="GetLastTradePriceOutput"> <part name="body" element="ex:TradePrice"/> </message>
The portType
is what's actually exposed as the name of the service:
<portType name="StockQuotePort"> <operation name="GetLastTradePrice">
The WSA/Soap binding story includes rules for construction Action names from the namespace, portType and operation names. I've actually explicitly assigned the same URI as those rules would have come up with:
<input message="ex:GetLastTradePriceInput" wsa:Action="http://example.com/stockquote/StockQuotePort/GetLastTradePriceRequest"/> <output message="ex:GetLastTradePriceOutput" wsa:Action="http://example.com/stockquote/StockQuotePort/GetLastTradePriceResponse"/> </operation> </portType>
The binding is completely predictable except for the
wsa:UsingAddressing
bit, which means messages are
required to use WS-Addressing-style SOAP headers.
<binding name="soapBinding" type="ex:StockQuotePort"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsa:UsingAddressing wsdl:required="true"/> <operation name="GetLastTradePrice"> <soap:operation style="document"/> <input> <soap:body use="literal"/> </input> <output> <soap:body use="literal"/> </output> </operation> </binding>
The service is again completely predictable:
<service name="StockQuote"> <port name="StockQuotePort" binding="ex:soapBinding"> <soap:address location="http://example.com/stockquote"/> </port> </service> </definitions>
Note that the one thing that's missing from the above is any indication that there's a Reference Parameters that's required for the service to work. This seems bizarre to me, but maybe I'm missing something. In particular, it appears that in WSDL 2.0 you may provide type information and other constraints which properties must satisfy if present, but not, as far as I can tell, that they are required.
Here's where we do find out about the reference parameter:
<?xml version='1.0'?> <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:sq="http://example.com/stockquote"> <wsa:Address>http://localhost:8080/wsrf/services/StockQuotePort</wsa:Address> <wsa:ReferenceParameters> <sq:ResourceIdentifier>IBM</sq:ResourceIdentifier> </wsa:ReferenceParameters> </wsa:EndpointReference>
Note, somewhat bizarrely, that the ResourceIdentifier element which
carries the crucial parameter, is in the example's stockquote
namespace. This despite the fact that the toolkit which builds the service
framework from the WSDL requires that it be called
ResourceIdentifier
. . .
Now we can put this all together. The EPR 'identifies' a service. But a
service may have multiple functionalities, i.e. operations, so to construct a
message for e.g. POSTing via HTTP, we need to combine the service identity from
the EPR with a wsa:Action
which identifies an operation:
<?xml version='1.0'?> <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sq="http://example.com/stockquote">
The SOAP header is where all the action is. We get the primary
destination indicator (wsa:To
), which is where we POST the whole
thing to, and the crucial Reference Parameter, from the EPR.
We get the operation designator (wsa:Action
), from the WSDL.
<Header xmlns:wsa="http://schemas.xmlsoap.org/ws/2005/08/addressing"> <wsa:To mustUnderstand="1">http://localhost:8080/wsrf/services/StockQuotePort</wsa:To> <wsa:Action mustUnderstand="1">http://example.com/stockquote/StockQuotePort/GetLastTradePriceRequest</wsa:Action> <sq:ResourceIdentifier wsa:IsReferenceParameter="true">IBM</sq:ResourceIdentifier> </Header>
In this example the body is completely redundant:
<Body> <sq:TradePriceRequest/> </Body> </Envelope>
Using the toolkit and its wizard, I built a service which actually
implements the above WSDL, and if you send it the above message, i.e. POST the
SOAP message above to
http://localhost:8080/wsrf/services/StockQuotePort
, the following
comes back:
<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Header> <wsa:Action soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" soapenv:mustUnderstand="0" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" >http://schemas.xmlsoap.org/ws/2004/03/addressing/anonymous</wsa:Action> <wsa:To soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" soapenv:mustUnderstand="0" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/03/addressing" >http://schemas.xmlsoap.org/ws/2004/03/addressing/anonymous</wsa:To> </soapenv:Header> <soapenv:Body> <stoc:TradePrice xmlns:stoc="http://example.com/stockquote"> <stoc:price>3.75</stoc:price> </stoc:TradePrice> </soapenv:Body> </soapenv:Envelope>