/*******************************************************************************
* Copyright (c) 2007, 2010 The Planets Project Partners.
*
* All rights reserved. This program and the accompanying
* materials are made available under the terms of the
* Apache License, Version 2.0 which accompanies
* this distribution, and is available at
* http://www.apache.org/licenses/LICENSE-2.0
*
*******************************************************************************/
package eu.planets_project.tb.gui.backing.admin.wsclient.util;
import java.io.ByteArrayOutputStream;
import java.util.Iterator;
import java.util.List;
import javax.xml.messaging.URLEndpoint;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.transform.JDOMResult;
/**
* A generic SOAP Web Services client. Uses the SAAJ library to talk to WebService endpoints.
*
* @author Markus Reis, ARC
*/
public class WSClient
{
private static Log log = LogFactory.getLog(WSClient.class);
/** The prefix to use for XML Schema instance namespace */
public static final String XSI_NAMESPACE_PREFIX = "xsi";
/** The URI for XML Schema instance namespace */
public static final String XSI_NAMESPACE_URI = "http://www.w3.org/2001/XMLSchema-instance";
/** The prefix to use for XML Schema namespace */
public static final String XSD_NAMESPACE_PREFIX = "xsd";
/** The URI for XML Schema namespace */
public static final String XSD_NAMESPACE_URI = "http://www.w3.org/2001/XMLSchema";
/**
* Constructor
*/
public WSClient()
{
}
/**
* Invokes an operation using SAAJ
*
* @param operation The operation to invoke
*/
public static String invokeOperation(OperationInfo operation) throws Exception
{
try
{
// Determine if the operation style is RPC
boolean isRPC = false;
if (operation.getStyle() != null)
isRPC = operation.getStyle().equalsIgnoreCase("rpc");
else ;
// All connections are created by using a connection factory
SOAPConnectionFactory conFactory = SOAPConnectionFactory.newInstance();
// Now we can create a SOAPConnection object using the connection factory
SOAPConnection connection = conFactory.createConnection();
// All SOAP messages are created by using a message factory
MessageFactory msgFactory = MessageFactory.newInstance();
// Now we can create the SOAP message object
SOAPMessage msg = msgFactory.createMessage();
// 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();
//my extension - START
//envelope.addNamespaceDeclaration("_ns1", operation.getNamespaceURI());
//my extension - END
if(isRPC)
{
// 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);
}
// Get the SOAP header from the envelope
SOAPHeader header = envelope.getHeader();
// The client does not yet support SOAP headers
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);
Name svcInfo = envelope.createName(operation.getTargetMethodName(), "ns1", operation.getNamespaceURI());
SOAPElement svcElem = body.addChildElement(svcInfo);
if(isRPC)
{
// Set the encoding style of the service element
svcElem.setEncodingStyle(operation.getEncodingStyle());
}
// Add the message contents to the SOAP body
Document doc = XMLSupport.readXML(operation.getInputMessageText());
if(doc.hasRootElement())
{
// Begin building content
buildSoapElement(envelope, svcElem, doc.getRootElement(), isRPC);
}
//svcElem.addTextNode(operation.getInputMessageText());
//svcElem.
// Check for a SOAPAction
String soapActionURI = operation.getSoapActionURI();
if(soapActionURI != null && soapActionURI.length() > 0)
{
// 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();
// Get ready for the invocation
URLEndpoint endpoint = new URLEndpoint(operation.getTargetURL());
// Show the URL endpoint message in the log
ByteArrayOutputStream msgStream = new ByteArrayOutputStream();
msg.writeTo(msgStream);
log.debug("SOAP Message MeasurementTarget URL: " + endpoint.getURL());
log.debug("SOAP Request: " + msgStream.toString());
// 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 Log
String strResponse = XMLSupport.outputString(responseDoc);
log.debug("SOAP Response from: " + operation.getTargetMethodName() + ": " + strResponse);
// Set the response as the output message
operation.setOutputMessageText(strResponse);
// Return the response generated
return strResponse;
}
catch(Throwable ex)
{
throw new Exception("Error invoking operation", ex);
}
}
/**
* Builds a hierarchy of SOAPElements given a complex value JDOM Element
*
* @param envelope The SOAP Envelope
* @param rootElem The root SOAP Element to build content for
* @param jdomElem A JDOM Element that represents a complex value
* @param isRPC Pass true when building for RPC encoded messages
*
* @throws SOAPException
*/
protected static void buildSoapElement(SOAPEnvelope envelope, SOAPElement soapElem, Element jdomElem, boolean isRPC) throws SOAPException
{
// If the source node has text use its value
String elemText = jdomElem.getText();
if(elemText != null)
{
if(isRPC == true)
{
// Set the type attribute for this element
String type = jdomElem.getAttributeValue("type");
if(type != null)
{
soapElem.addAttribute(envelope.createName(XSI_NAMESPACE_PREFIX + ":type"), XSD_NAMESPACE_PREFIX + ":" + type);
}
}
// Add the element text value
soapElem.addTextNode(elemText);
}
// If the source node has attributes add the attribute values
List attrs = jdomElem.getAttributes();
if(attrs != null)
{
Iterator attrIter = attrs.iterator();
while(attrIter.hasNext())
{
// Get the attribute to add
Attribute attr = (Attribute)attrIter.next();
// Create a name for the attribute
Name attrName = envelope.createName(attr.getName(), attr.getNamespacePrefix(), attr.getNamespaceURI());
// Add the attribute and its value to the element
soapElem.addAttribute(attrName, attr.getValue());
}
}
// Build children
List children = jdomElem.getChildren();
if(children != null)
{
Iterator childIter = children.iterator();
while(childIter.hasNext())
{
Element jdomChildElem = (Element)childIter.next();
// Create a new SOAPElement as a child of the current one
//SOAPElement soapChildElem = soapElem.addChildElement(jdomChildElem.getName());
SOAPElement soapChildElem = soapElem.addChildElement(jdomChildElem.getName(), jdomChildElem.getNamespacePrefix(), jdomChildElem.getNamespaceURI());
// Build it
buildSoapElement(envelope, soapChildElem, jdomChildElem, isRPC);
}
}
}
/**
* Test!!
*
* @param wsdl The WSDL to load and run!
*/
public static void test(String wsdl)
{
try
{
ComponentBuilder builder = new ComponentBuilder();
List components = builder.buildComponents(wsdl);
Iterator iter = components.iterator();
while(iter.hasNext())
{
ServiceInfo info = (ServiceInfo)iter.next();
Iterator iter2 = info.getOperations();
while(iter2.hasNext())
{
OperationInfo oper = (OperationInfo)iter2.next();
invokeOperation(oper);
}
}
}
catch(Exception e)
{
log.error(e.getMessage());
e.printStackTrace();
}
}
/**
* Invokes an operation using SAAJ
*
* @param operation The operation to invoke
*/
public static void main(String[] args)
{
try
{
/*OperationInfo operation = new OperationInfo();
operation.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
operation.setInputMessageName("HelloWorld_sayHello");
operation.setInputMessageText("<urn:sayHello xmlns:urn='urn:jbosstest'><arg0>Markus</arg0></urn:sayHello>");
operation.setNamespaceURI("urn:jbosstest");
operation.setOutputMessageName("HelloWorld_sayHelloResponse");
operation.setOutputMessageText("<sayHello><return>0</return></sayHello>");
operation.setSoapActionURI("");
operation.setStyle("document");
operation.setTargetMethodName("sayHello");
operation.setTargetObjectURI(null);
operation.setTargetURL("http://localhost:8080/HelloWorld/HelloWorld");*/
OperationInfo operation = new OperationInfo();
operation.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
operation.setInputMessageName("ConversionRateSoapIn");
operation.setInputMessageText("<ns5:ConversionRate xmlns:ns5='http://www.webserviceX.NET/'><ns5:FromCurrency>EUR</ns5:FromCurrency><ns5:ToCurrency>SKK</ns5:ToCurrency></ns5:ConversionRate>");
operation.setNamespaceURI("http://www.webserviceX.NET/");
operation.setOutputMessageName("ConversionRateSoapOut");
operation.setOutputMessageText("<ConversionRate><ConversionRateResult>0</ConversionRateResult></ConversionRate>");
operation.setSoapActionURI("http://www.webserviceX.NET/ConversionRate");
operation.setStyle("document");
operation.setTargetMethodName("ConversionRate");
operation.setTargetObjectURI(null);
operation.setTargetURL("http://www.webservicex.net/CurrencyConvertor.asmx");
// Determine if the operation style is RPC
boolean isRPC = operation.getStyle().equalsIgnoreCase("rpc");
// All connections are created by using a connection factory
SOAPConnectionFactory conFactory = SOAPConnectionFactory.newInstance();
// Now we can create a SOAPConnection object using the connection factory
SOAPConnection connection = conFactory.createConnection();
// All SOAP messages are created by using a message factory
MessageFactory msgFactory = MessageFactory.newInstance();
// Now we can create the SOAP message object
SOAPMessage msg = msgFactory.createMessage();
// 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();
//envelope.addNamespaceDeclaration("", operation.getNamespaceURI());
if(isRPC)
{
// 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);
}
// Get the SOAP header from the envelope
SOAPHeader header = envelope.getHeader();
// The client does not yet support SOAP headers
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);
Name svcInfo = envelope.createName(operation.getTargetMethodName(), "ns2", operation.getNamespaceURI());
SOAPElement svcElem = body.addChildElement(svcInfo);
if(isRPC)
{
// Set the encoding style of the service element
svcElem.setEncodingStyle(operation.getEncodingStyle());
}
// Add the message contents to the SOAP body
Document doc = XMLSupport.readXML(operation.getInputMessageText());
if(doc.hasRootElement())
{
// Begin building content
buildSoapElement(envelope, svcElem, doc.getRootElement(), isRPC);
}
//svcElem.addTextNode(operation.getInputMessageText());
//svcElem.
// Check for a SOAPAction
String soapActionURI = operation.getSoapActionURI();
if(soapActionURI != null && soapActionURI.length() > 0)
{
// 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();
// Get ready for the invocation
URLEndpoint endpoint = new URLEndpoint(operation.getTargetURL());
// Show the URL endpoint message in the log
ByteArrayOutputStream msgStream = new ByteArrayOutputStream();
msg.writeTo(msgStream);
log.debug("SOAP Message MeasurementTarget URL: " + endpoint.getURL());
log.debug("SOAP Request: " + msgStream.toString());
// 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 Log
String strResponse = XMLSupport.outputString(responseDoc);
log.debug("SOAP Response from: " + operation.getTargetMethodName() + ": " + strResponse);
// Set the response as the output message
operation.setOutputMessageText(strResponse);
// Return the response generated
//return strResponse;
}
catch(Throwable ex)
{
log.error("Error invoking operation:");
log.error(ex.getMessage());
}
//return "";
}
}