// The MIT License
//
// Copyright (c) 2004 Evren Sirin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
package org.mindswap.wsdl;
import java.util.Iterator;
import java.util.Vector;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import org.apache.axis.client.Call;
import org.apache.axis.constants.Style;
import org.apache.axis.message.SOAPBodyElement;
import org.apache.axis.message.SOAPEnvelope;
import org.mindswap.utils.URIUtils;
import org.mindswap.utils.Utils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class WSDLOperation {
public static boolean DEBUG = false;
private WSDLService service = null;
private Call call = null;
private Vector inputs = new Vector();
private Vector outputs = new Vector();
private String operationName;
private String inputMessageName;
private String outputMessageName;
private String portName;
private String documentation;
public WSDLOperation(Call c) {
this.call = c;
}
public WSDLParameter getInput(int i) {
return (WSDLParameter) getInputs().elementAt(i);
}
public WSDLParameter getInput(String name) {
for(int i = 0; i < inputs.size(); i++) {
WSDLParameter in = (WSDLParameter) inputs.get(i);
String paramName = in.getName();
if(paramName.equals(name) || URIUtils.getLocalName(paramName).equals(name))
return in;
}
return null;
}
public WSDLParameter getOutput(int i) {
return (WSDLParameter) getOutputs().elementAt(i);
}
public WSDLParameter getOutput(String name) {
for(int i = 0; i < outputs.size(); i++) {
WSDLParameter out = (WSDLParameter) outputs.get(i);
String paramName = out.getName();
if( URIUtils.relaxedMatch(paramName, name) )
return out;
}
return null;
}
public Vector getInputs() { return inputs; }
public Vector getOutputs() { return outputs; }
void addInput(String name, QName type) { inputs.add(new WSDLParameter(name, type)); }
void addOutput(String name, QName type) { outputs.add(new WSDLParameter(name, type)); }
public String getName() { return call.getOperationName().getLocalPart(); }
public String getOperationName() { return operationName; }
public void setOperationName(String s) { operationName = s; }
public String getPortName() { return portName; }
public void setPortName(String s) { portName = s; }
public String getInputMessageName() { return inputMessageName; }
public void setInputMessageName(String s) { inputMessageName = s; }
public String getOutputMessageName() { return outputMessageName; }
public void setOutputMessageName(String s) { outputMessageName = s; }
public WSDLService getService() { return service; }
public void setService(WSDLService s) { service = s; }
public String getDocumentation() { return documentation; }
public void setDocumentation(String s) { documentation = s; }
public String toString() {
return getName();
}
public String getDescription() {
String s = getName() + "(";
for(Iterator i = inputs./*values().*/iterator(); i.hasNext(); ) {
WSDLParameter param = (WSDLParameter) i.next();
s += param.getName() + ":" + param.getType().getLocalPart();
if(i.hasNext()) s += ", ";
}
s += ") -> (";
for(Iterator i = outputs./*values().*/iterator(); i.hasNext(); ) {
WSDLParameter param = (WSDLParameter) i.next();
s += param.getName() + ":" + param.getType().getLocalPart();
if(i.hasNext()) s += ", ";
}
s += ")";
return s;
}
public void invoke() throws Exception {
SOAPEnvelope request = createRequest();
if(DEBUG) {
System.out.println("Invoke operation " + getDescription());
System.out.println(request);
}
SOAPEnvelope reply = call.invoke(request);
if(DEBUG)
System.out.println(Utils.formatXML(reply));
// TODO Handle SOAPFault message
processResult(reply);
}
private void processResult(SOAPEnvelope reply) throws SOAPException {
SOAPElement soapBody = reply.getBody();
SOAPElement response = (SOAPElement) soapBody.getChildElements().next();
Iterator messageParts = response.getChildElements();
for(int i = 0; i < outputs.size(); i++) {
WSDLParameter output = (WSDLParameter) outputs.elementAt(i);
SOAPElement e = (SOAPElement) messageParts.next();
output.setTextValue(e.toString());
if(DEBUG) {
System.out.println("processResult " + e);
System.out.println("getValue " + e.getValue());
System.out.println("getType " + (e.getNodeType() == Node.ELEMENT_NODE));
System.out.println("getValue is null? " + (e.getValue() == null));
System.out.println("result has children? " + e.getChildElements().hasNext());
if(e.getChildElements().hasNext()) {
Node child = (Node) e.getChildElements().next();
System.out.println("result first child " + child);
}
}
Iterator children = e.getChildElements();
if( children.hasNext() ) {
Node child = (Node) e.getChildElements().next();
if( child.getNodeType() == Node.TEXT_NODE )
output.setValue( child.toString() );
else
output.setValue( e.toString() );
}
else
output.setValue( e.toString() );
}
}
private SOAPEnvelope createRequest() throws SOAPException {
String targetNamespace = call.getOperationName().getNamespaceURI();
String opName = call.getOperationName().getLocalPart();
SOAPEnvelope envelope = new SOAPEnvelope();
if(DEBUG) {
System.out.println("SOAP Action = " +call.getSOAPActionURI());
System.out.println("SOAP Action used = " + call.useSOAPAction());
}
envelope.addNamespaceDeclaration("xsi", WSDLConsts.xsiURI);
envelope.addNamespaceDeclaration("xsd",WSDLConsts. xsdURI);
//envelope.addNamespaceDeclaration("ns0", targetNamespace);
String inputEncodingStyle = "http://schemas.xmlsoap.org/soap/encoding/";
if(inputEncodingStyle != null) {
envelope.setEncodingStyle(inputEncodingStyle);
envelope.addAttribute(WSDLConsts.soapURI, "encodingStyle", inputEncodingStyle);
}
// FIXME test this feature
String nsOp = call.getOperationStyle().equals(Style.RPC) ? "u" : "";
SOAPBodyElement soapBody = new SOAPBodyElement(
envelope.createName(opName, nsOp, targetNamespace));
envelope.addBodyElement(soapBody);
for(Iterator i = inputs.iterator(); i.hasNext(); ) {
WSDLParameter param = (WSDLParameter) i.next();
Object paramValue = param.getValue();
if(paramValue == null) continue;
SOAPElement soapElement = soapBody.addChildElement(URIUtils.getLocalName(param.getName()), "");
// TODO treat string, int, float differently
if(paramValue instanceof Node) {
if(DEBUG)
System.out.println("Case 1");
createSOAPElement(soapElement, (Node) paramValue);
if(soapElement.getAttributeValue(WSDLConsts.xsiType) == null) {
if(DEBUG) System.out.println("Case 1a");
soapElement.addAttribute(WSDLConsts.xsiType,
"u:" + param.getType().getLocalPart());
}
}
else {
if(DEBUG)
System.out.println("Case 2 " + param.getType());
soapElement.addAttribute(WSDLConsts.xsiType, "xsd:" + param.getType().getLocalPart());
soapElement.addTextNode(paramValue.toString());
}
}
return envelope;
}
public void createSOAPElement(SOAPElement parent, Node node) throws SOAPException {
int type = node.getNodeType();
if(type == Node.TEXT_NODE) {
if(DEBUG)
System.out.println("Case 3");
parent.addAttribute(WSDLConsts.xsiType, "xsd:string");
parent.addTextNode(node.getNodeValue());
}
else if(type == Node.ELEMENT_NODE) {
SOAPElement soapElement;
if(!(node.getParentNode() instanceof org.w3c.dom.Document)) {
if(DEBUG)
System.out.println("Case 4");
soapElement = parent.addChildElement(node.getNodeName());
}
else {
if(DEBUG)
System.out.println("Case 5");
soapElement = parent;
}
//NamedNodeMap attrs = node.getAttributes();
NodeList children = node.getChildNodes();
if (children != null) {
int len = children.getLength();
for (int i = 0; i < len; i++) {
createSOAPElement(soapElement, children.item(i));
}
}
}
}
}