Listing 1.
public List buildComponents(String wsdlURI)
{
// The list of components that will be returned
List serviceList = Collections.synchronizedList(new ArrayList());
// Create the WSDL Reader object
WSDLReader reader = wsdlFactory.newWSDLReader();
try
{
// Read the WSDL and get the top-level Definition object
Definition def = reader.readWSDL(null, wsdlURI);
// Create a castor schema from the types element defined in WSDL
// This method will return null if there are types defined in the WSDL
wsdlTypes = createSchemaFromTypes(def);
// Get the services defined in the document
Map services = def.getServices();
if(services != null)
{
// Create a component for each service defined
Iterator svcIter = services.values().iterator();
for(int i = 0; svcIter.hasNext(); i++)
{
// Create a new ServiceInfo component for each service found
ServiceInfo serviceInfo = new ServiceInfo();
// Populate the new component from the WSDL Definition read
populateComponent(serviceInfo, (Service)svcIter.next());
// Add the new component to the List to be returned
serviceList.add(serviceInfo);
}
}
}
catch(Throwable t)
{
// Process the error/exception
System.err.println(t.getMessage());
}
// return the List of services we created
return serviceList;
}
/**
* Populates a ServiceInfo instance from the specified Service definiition
*
* @param component The component to populate
* @param service The Service to populate from
*
* @return The populated component is returned representing the Service parameter
*/
private ServiceInfo populateComponent(ServiceInfo component, Service service)
{
// Get the qualified service name information
QName qName = service.getQName();
// Get the service's namespace URI
String namespace = qName.getNamespaceURI();
// Use the local part of the qualified name for the component's name
String name = qName.getLocalPart();
// Set the name
component.setName(name);
// Get the defined ports for this service
Map ports = service.getPorts();
// Use the Ports to create methods for all request/response messages defined
Iterator portIter = ports.values().iterator();
while(portIter.hasNext())
{
// Get the next defined port
Port port = (Port)portIter.next();
// Get the Port's Binding
Binding binding = port.getBinding();
// Now we will create operations from the Binding information
List operations = buildOperations(binding);
// Process methods built from the binding information
Iterator operIter = operations.iterator();
while(operIter.hasNext())
{
OperationInfo operation = (OperationInfo)operIter.next();
// Set the namespace URI for the method using the service's namespace.
operation.setNamespaceURI(namespace);
// Find the SOAP target URL
ExtensibilityElement addrElem =
findExtensibilityElement(port.getExtensibilityElements(), "address");
if(addrElem != null && addrElem instanceof SOAPAddress)
{
// Set the SOAP target URL
SOAPAddress soapAddr = (SOAPAddress)addrElem;
operation.setTargetURL(soapAddr.getLocationURI());
}
// Add the method to the component
component.addOperation(operation);
}
}
return component;
}
Listing 2.
// Get the operation bound to the binding operation
Operation operation = bindingOperation.getOperation();
// From the operation we can get the Input definition
Input inDef = operation.getInput();
// Get the message defintion for the Input
Message inMessage = inDef.getMessage();
// Get the parts defined for this message
Map parts = inMessage.getParts();
Listing 3.
<types xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:s0="http://www.xignite.com/services/">
<s:schema elementFormDefault="qualified"
targetNamespace="http://www.xignite.com/services/">
<s:element name="GetQuotesHistorical">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Symbol" type="s:string" />
<s:element minOccurs="1" maxOccurs="1" name="Month" type="s:int" />
<s:element minOccurs="1" maxOccurs="1" name="Year" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetQuotesHistoricalResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetQuotesHistoricalResult"
type="s0:ArrayOfQuote" />
</s:sequence>
</s:complexType>
</s:element>
<s:complexType name="ArrayOfQuote">
<s:sequence>
<s:element minOccurs="0" maxOccurs="unbounded" name="Quote" nillable="true"
type="s0:Quote" />
</s:sequence>
</s:complexType>
<s:complexType name="Quote">
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="Error" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="Symbol" type="s:string" />
<s:element minOccurs="0" maxOccurs="1" name="Date" type="s:string" />
<s:element minOccurs="1" maxOccurs="1" name="Open" type="s:double" />
<s:element minOccurs="1" maxOccurs="1" name="High" type="s:double" />
<s:element minOccurs="1" maxOccurs="1" name="Low" type="s:double" />
<s:element minOccurs="1" maxOccurs="1" name="Last" type="s:double" />
<s:element minOccurs="1" maxOccurs="1" name="LastAdjusted" type="s:double" />
<s:element minOccurs="1" maxOccurs="1" name="PercentChange" type="s:double" />
<s:element minOccurs="1" maxOccurs="1" name="Volume" type="s:double" />
<s:element minOccurs="1" maxOccurs="1" name="Change" type="s:double" />
</s:sequence>
</s:complexType>
</s:schema>
</types>
Listing 4
/**
* Builds and adds parameters to the supplied method given a SOAP Message definition
(from WSDL)
*
* @param method The method that the parameters built will be added to
* @param msg The SOAP Message definition that has parts to defined
parameters for
*/
private String buildMessageText(OperationInfo operationInfo, Message msg)
{
// Build a JDOM representation of the message
//Element rootElem = new Element(operationInfo.getTargetMethodName(),
operationInfo.getTargetObjectURI());
StringBuffer sb = new StringBuffer();
// Get the message parts
List msgParts = msg.getOrderedParts(null);
// Process each part
Iterator iter = msgParts.iterator();
while(iter.hasNext())
{
// Get each part
Part part = (Part)iter.next();
// Add content for each message part
Element partElem = new Element(part.getElementName().getLocalPart());
// Determine if this message part's type is complex
XMLType xmlType = getXMLType(part);
if(xmlType != null && xmlType.isComplexType())
{
// Build the message structure
buildComplexPart((ComplexType)xmlType, partElem);
}
else
{
partElem.addContent("0");
}
sb.append(XMLSupport.outputString(partElem));
}
return sb.toString();
}
Listing 5.
// All SAAJ connections are created by using a connection factory
SOAPConnectionFactory conFactory = SOAPConnectionFactory.newInstance();
SOAPConnection connection = conFactory.createConnection();
// All SAAJ SOAP messages are created by using a message factory
MessageFactory msgFactory = MessageFactory.newInstance();
SOAPMessage msg = msgFactory.createMessage();
Listing 6.
// Get the SOAP part from the SOAP message object
SOAPPart soapPart = msg.getSOAPPart();
// The SOAP part object will automatically contain the SOAP envelope
SOAPEnvelope envelope = soapPart.getEnvelope();
if(operation.getStyle().equalsIgnoreCase("rpc"))
{
// Add namespace declarations to the envelope
// usually only required for RPC/encoded
envelope.addNamespaceDeclaration(XSI_NAMESPACE_PREFIX, XSI_NAMESPACE_URI);
envelope.addNamespaceDeclaration(XSD_NAMESPACE_PREFIX, XSD_NAMESPACE_URI);
}
// The client does not yet support SOAP headers
SOAPHeader header = envelope.getHeader();
header.detachNode();
// Get the SOAP body from the envelope and populate it
SOAPBody body = envelope.getBody();
// Create the default namespace for the SOAP body
body.addNamespaceDeclaration("", operation.getNamespaceURI());
// Add the service information
String targetObjectURI = operation.getTargetObjectURI();
if(targetObjectURI == null)
{
// The target object URI should not be null
targetObjectURI = "";
}
// Add the service information
Name svcInfo = envelope.createName(operation.getTargetMethodName(), "",
targetObjectURI);
// Add the service information
SOAPElement svcElem = body.addChildElement(svcInfo);
if(operation.getStyle().equalsIgnoreCase("rpc"))
{
// Set the encoding style of the service element
svcElem.setEncodingStyle(operation.getEncodingStyle());
}
// Add the message to the SOAP body
svcElem.addTextNode(operation.getInputMessageText());
// Check for a SOAPAction
String soapActionURI = operation.getSoapActionURI();
// Add the SOAPAction value as a MIME header
MimeHeaders mimeHeaders = msg.getMimeHeaders();
mimeHeaders.setHeader("SOAPAction", "\"" +
operation.getSoapActionURI() + "\"");
// Save changes to the message we just populated
msg.saveChanges();
Listing 7
// Get ready for the invocation
URLEndpoint endpoint = new URLEndpoint(operation.getTargetURL());
// Make the call
SOAPMessage response = connection.call(msg, endpoint);
// Close the connection, we are done with it
connection.close();
// Get the content of the SOAP response
Source responseContent = response.getSOAPPart().getContent();
// Convert the SOAP response into a JDOM
TransformerFactory tFact = TransformerFactory.newInstance();
Transformer transformer = tFact.newTransformer();
JDOMResult jdomResult = new JDOMResult();
transformer.transform(responseContent, jdomResult);
// Get the document created by the transform operation
Document responseDoc = jdomResult.getDocument();
// Send the response to the console
String strResponse = XMLSupport.outputString(responseDoc);
System.out.println("SOAP Response from: " + operation.getTargetMethodName() +
": " + strResponse);
// Set the response as the output message
operation.setOutputMessageText(strResponse);
Listing 8.
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetQuotesHistoricalResponse xmlns="http://www.xignite.com/services/">
<GetQuotesHistoricalResult>
<Quote>
<Date>12/31/2002</Date>
<Open>3.07</Open>
<High>3.15</High>
<Low>3.04</Low>
<Last>3.11</Last>
<LastAdjusted>3.11</LastAdjusted>
<PercentChange>0.974</PercentChange>
<Volume>39579300</Volume>
<Change>0.03</Change>
</Quote>
<Quote>
<Date>12/30/2002</Date>
<Open>3.28</Open>
<High>3.31</High>
<Low>3.05</Low>
<Last>3.08</Last>
<LastAdjusted>3.08</LastAdjusted>
<PercentChange>-5.231</PercentChange>
<Volume>39969900</Volume>
<Change>-0.17</Change>
</Quote>
…
</GetQuotesHistoricalResult>
</GetQuotesHistoricalResponse>
</soap:Body>
</soap:Envelope
With the help of an automatically generated XSLT script, we can transform the XML response
into an HTML report.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "html"/>
…………
<xsl:template match = "GetQuotesHistoricalResult">
<html>
<head>
</head>
<body>
<table width="550" border="2" align="center">
<tr valign="bottom">
<td width="150" align="center">Date</td>
<td width="150" align="center">Open</td>
<td width="150" align="center">High</td>
<td width="150" align="center">Low</td>
<td width="150" align="center">Last</td>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Quote">
<tr>
<td align="left" width="150"><xsl:value-of select="Date"/></td>
<td align="left" width="150"><xsl:value-of select="Open"/></td>
<td align="left" width="150"><xsl:value-of select="High"/></td>
<td align="left" width="150"><xsl:value-of select="Low"/></td>
<td align="left" width="150"><xsl:value-of select="Last"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>