[MOBY-guts] biomoby commit

Paul Gordon gordonp at pub.open-bio.org
Wed Jul 7 16:02:48 UTC 2004


gordonp
Wed Jul  7 12:02:47 EDT 2004
Update of /home/repository/moby/moby-live/Java/src/main/org/biomoby/client
In directory pub.open-bio.org:/tmp/cvs-serv32166/client

Modified Files:
	MobyRequest.java 
Log Message:
Fixed issues with SOAP payload parsing related to namespaces and encoding schemes, works with Axis 1.1beta without warnings too

moby-live/Java/src/main/org/biomoby/client MobyRequest.java,1.3,1.4
===================================================================
RCS file: /home/repository/moby/moby-live/Java/src/main/org/biomoby/client/MobyRequest.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- /home/repository/moby/moby-live/Java/src/main/org/biomoby/client/MobyRequest.java	2004/05/20 16:08:05	1.3
+++ /home/repository/moby/moby-live/Java/src/main/org/biomoby/client/MobyRequest.java	2004/07/07 16:02:47	1.4
@@ -16,9 +16,7 @@
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.transform.TransformerException;
 import javax.xml.namespace.QName;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-import org.w3c.dom.Element;
+import org.w3c.dom.*;
 
 // Utilities
 import java.util.Hashtable;
@@ -34,6 +32,7 @@
 import org.w3c.dom.NodeList;
 import org.apache.axis.message.MessageElement;
 import java.io.PrintStream;
+import java.io.StringBufferInputStream;
 
 /**
  * This class handles the WSDL transaction to request a response
@@ -56,6 +55,7 @@
     protected MobyDataSecondaryInstance[] secondaryData = null;
     protected Vector outputData = null;
     protected Central mobyCentral = null;
+    protected PrefixResolver mobyPrefixResolver = null;
     
     protected Hashtable wsdlCache = null;
     protected String lastWsdlCacheKey = null;
@@ -69,6 +69,7 @@
     protected XPathContext xpath_context;
     protected String responseString = null;
 
+    private XPath stringEncodedXPath;
     private XPath base64EncodedXPath;
     private XPath queryResponseXPath;
     private XPath simpleChildXPath;
@@ -97,11 +98,20 @@
 	}
 
 	xpath_context = new XPathContext();
-	PrefixResolver mobyPrefixResolver = new MobyPrefixResolver();
+	mobyPrefixResolver = new MobyPrefixResolver();
 
 	// Now compile the XPath statements that will be used fetch data from the server response
 	try{
-	    base64EncodedXPath = new XPath("//*[@xsi:type=\"SOAP-ENC:base64\"]", null, mobyPrefixResolver, XPath.SELECT);
+	    base64EncodedXPath = new XPath("//*[starts-with(substring-after(@"+
+                                           MobyPrefixResolver.XSI1999_PREFIX+
+                                           ":type, ':'), \"base64\") or starts-with(substring-after(@"+
+                                           MobyPrefixResolver.XSI2001_PREFIX+
+                                           ":type, ':'), \"base64\")]", null, mobyPrefixResolver, XPath.SELECT);
+	    stringEncodedXPath = new XPath("//*[substring-after(@"+
+                                           MobyPrefixResolver.XSI1999_PREFIX+
+                                           ":type, ':')=\"string\" or substring-after(@"+
+                                           MobyPrefixResolver.XSI2001_PREFIX+
+                                           ":type, ':')=\"string\"]", null, mobyPrefixResolver, XPath.SELECT);
 	    queryResponseXPath = new XPath("//moby:mobyData | //mobyData", null, mobyPrefixResolver, XPath.SELECT);
 	    simpleChildXPath = new XPath("moby:Simple | Simple", null, mobyPrefixResolver, XPath.SELECT);
 	    collectionChildXPath = new XPath("moby:Collection | Collection", null, mobyPrefixResolver, XPath.SELECT);
@@ -306,23 +316,25 @@
 	// Should initialize endpoint, etc. This call is AXIS SPECIFIC, otherwise you'll 
 	// have to do the call's info setting manually.
 	//((org.apache.axis.client.Call) soapCall).setSOAPService(soapService); 
-	soapCall.setPortTypeName(new QName("http://biomoby.org/", 
-					   mobyService.getName() + "PortType"));
-	soapCall.setOperationName(new QName("http://biomoby.org/", 
-					    mobyService.getName()));
+	soapCall.removeAllParameters();
 	soapCall.setTargetEndpointAddress(mobyService.getURL());
+	soapCall.setPortName(new QName("http://biomoby.org/", 
+					   mobyService.getName() + "PortType"));
+	//soapCall.setOperationName(new QName("http://biomoby.org/", 
+	//				    mobyService.getName()));
 	soapCall.setSOAPActionURI("http://biomoby.org/#" + mobyService.getName());
-	soapCall.setReturnType(XMLType.SOAP_STRING);	
-	soapCall.removeAllParameters();
 	MobyData[] requiredInputData = mobyService.getPrimaryInputs();
 	if(requiredInputData == null)
 	    return; // A method requiring no input?
 	else{
 	    // There is one argument, the MOBY request object string
-		    soapCall.addParameter("MOBYRequest",
-					  XMLType.SOAP_STRING,
-					  stringType,
-					  ParameterMode.IN);
+	    /*soapCall.setReturnType(new QName("http://biomoby.org/", mobyService.getName()));	
+	    soapCall.addParameter("MOBYRequest",
+				  XMLType.SOAP_STRING,
+				  stringType,
+				  ParameterMode.IN);*/
+	    if(debug)
+		debugPS.println("Set returnType after addParameter was " + soapCall.getReturnType());
 	}
 	return;
     }
@@ -337,9 +349,12 @@
 	//Setup
         mobyXMLInputData[0] = mobyInputXML;
 
+	if(debug)
+	    debugPS.println("returnType just before invoke call is " + soapCall.getReturnType());
 	Object returnedObject = null;
 	try{
-	    returnedObject = soapCall.invoke(mobyXMLInputData);
+	    returnedObject = soapCall.invoke(new QName("http://biomoby.org/", 
+					    mobyService.getName()), mobyXMLInputData);
 	}
 	catch(Exception e){
 	    throw new SOAPException("While invoking SOAP Call: " + e);
@@ -354,6 +369,7 @@
 	    return decodeSOAPMessage(resultDom);
 	    //return resultDom;
 	} catch(Exception e){
+	    e.printStackTrace();
 	    throw new SOAPException("Could not get SOAP response as DOM Element: "+ e);
 	}
 
@@ -368,53 +384,143 @@
      * @return The root element of the MOBY response DOM
      */
     protected Element decodeSOAPMessage(Element n) throws SOAPException, MobyException{
-
 	if(n == null){
 	    throw new SOAPException("SOAP Message given to decode is null");
 	}
 
-	// Find base64 encoded elements in the SOAP message using XPath
 	NodeList node_list = null;
+	Node responseNode = null;
+	XPath responseElementXPath = null;
 	try{
-	    node_list = runXPath(base64EncodedXPath, n);
+	    responseElementXPath = new XPath("//"+ MobyPrefixResolver.MOBY_TRANSPORT_PREFIX+
+						   ":"+mobyService.getName()+"Response", 
+						   null, mobyPrefixResolver, XPath.SELECT);
      	}catch(TransformerException te){
             throw new SOAPException("Cannot select SOAP nodes due to exception "+
+				    "while compiling XPath statement (code bug?):" +te);
+	}
+	try{
+	    node_list = runXPath(responseElementXPath, n);
+	}
+	catch(TransformerException te){	  
+            throw new SOAPException("Cannot select SOAP nodes due to exception "+
 				    "while executing XPath statement:" +te);
 	}
 
 	if(node_list == null || node_list.getLength() == 0){
-	    // Note: before giving up we should really have a plain string check as per the MOBY API 0.6
-	    throw new SOAPException("Could not find a Base64 encoded SOAP payload");
+	    throw new SOAPException("Could not find a response element in SOAP payload");
 	}
-	// Do decoding for each part found
-	for(int i = 0; i < node_list.getLength(); i++){
-	    
+
+	if(node_list.getLength() > 1){
+	    throw new SOAPException("Found more than one response element in SOAP payload, " +
+				    "unable to resolve ambiguity of the payload (service provider error?)");
+	}
+	responseNode = node_list.item(0);
+
+	// Find base64 encoded elements in the SOAP message using XPath and 
+	// replace them with the real decoded contents
+	node_list = null;
+	try{
+            node_list = runXPath(base64EncodedXPath, responseNode);
+        }
+	catch(TransformerException te){
+            throw new SOAPException("Cannot select base64 encoded SOAP nodes due to exception "+
+        			    "while executing XPath statement:" +te);
+	}
+	if(debug && node_list != null){
+	    debugPS.println("There were " + node_list.getLength() + 
+				" base64 encoded elements in the data");
+	}
+
+	// Do decoding for each base64 part found
+	for(int i = 0; node_list != null && i < node_list.getLength(); i++){
 	    org.w3c.dom.Node change = node_list.item(i);
-	    change.normalize();
+	    /* Make sure the text data is all put into one contiguous piece for decoding*/
+	    change.normalize(); 
+	    
 	    byte[] decodedBytes = org.apache.axis.encoding.Base64.decode(change.getFirstChild().getNodeValue());
 	    String newText = new String(decodedBytes);
 	    if(debug){
 		debugPS.println("New decoded text is" + newText);
 	    }
 	    
-	    // release resources related to the Xpath execution, since we won't be using this doc anymore
-	    releaseXPath(n);
-	    
-	    responseString = new String(decodedBytes);
-	    // Parse the MOBY XML document payload
-	    Document domDoc = null;
-	    try{
-		domDoc = docBuilder.parse(new ByteArrayInputStream(decodedBytes));
-	    } catch(org.xml.sax.SAXException saxe){
-		throw new MobyException("The SOAP payload defining the MOBY Result " +
-					"could not be parsed: " + saxe);
-	    } catch(java.io.IOException ioe){
-		throw new MobyException("The SOAP payload defining the MOBY Result " +
-					" could not be read (from a String!)" + ioe);
+	    // Swap out this node for the decoded data
+	    change.getParentNode().replaceChild(n.getOwnerDocument().createTextNode(new String(decodedBytes)), 
+						change);
+	}
+
+	// Now see if there are any strings that need decoding
+	node_list = null;
+	try{
+            node_list = runXPath(stringEncodedXPath, responseNode);
+        }
+	catch(TransformerException te){
+            throw new SOAPException("Cannot select base64 encoded SOAP nodes due to exception "+
+        			    "while executing XPath statement:" +te);
+	}
+
+	// Do decoding for each base64 part found
+	for(int i = 0; node_list != null && i < node_list.getLength(); i++){
+	    org.w3c.dom.Node change = node_list.item(i);
+	    /* Make sure the text data is all put into one contiguous piece for decoding*/
+	    change.normalize();
+	    String plainString = "";
+	    int j = 0;
+	    for(NodeList children = change.getChildNodes(); 
+		children != null && j < children.getLength();
+		j++){
+		Node child = children.item(j);
+		if(child instanceof CDATASection || child instanceof Text){
+		    plainString += child.getNodeValue();
+		}
+	    }
+
+	    // Swap out this node for the decoded data
+	    change.getParentNode().replaceChild(n.getOwnerDocument().createTextNode(plainString), change);
+	}
+	if(debug && node_list != null){
+	    debugPS.println("There were " + node_list.getLength() + 
+				" XML Schema string encoded elements in the data");
+	}
+
+	// Parse the MOBY XML document payload
+	responseNode.normalize();
+	NodeList children = responseNode.getChildNodes();
+	if(children == null){
+	    throw new MobyException("The MOBY payload has no contents at all"); 
+	}
+	if(children.getLength() != 1){
+	    debugPS.println("Warning: MOBY Payload appears to have more than " +
+			       "just text in it, skipping the non-text sections");
+	}
+
+	responseString = "";
+	for(int j = 0; j < children.getLength(); j++){
+	    Node child = children.item(j);
+	    if(child instanceof CDATASection || child instanceof Text){
+		responseString += child.getNodeValue();
 	    }
-	    return domDoc.getDocumentElement();
 	}
-	return null; //Shouldn't get here
+
+	if(responseString.length() == 0){
+	    throw new MobyException("The MOBY payload has no text contents at all"); 
+	}
+
+	Document domDoc = null;
+	try{
+	    domDoc = docBuilder.parse(new StringBufferInputStream(responseString));
+	} catch(org.xml.sax.SAXException saxe){
+	    throw new MobyException("The SOAP payload defining the MOBY Result " +
+				    "could not be parsed: " + saxe);
+	} catch(java.io.IOException ioe){
+	    throw new MobyException("The SOAP payload defining the MOBY Result " +
+				    " could not be read (from a String!)" + ioe);
+	}
+
+	// release resources related to the Xpath execution, since we won't be using this doc anymore
+	releaseXPath(n);
+	    
+	return domDoc.getDocumentElement();
     }
 
 
@@ -492,7 +598,7 @@
 	if(debug){
 	    debugPS.println("Aha! Got " + response_list.getLength() + " mobyContent response elements");
 	}
-	// Do data deserialization for each response's mobyData
+	// Do data decoding for each response's mobyData
 	for(int i = 0; i < response_list.getLength(); i++){
 	    Node response = response_list.item(i);
 	    




More information about the MOBY-guts mailing list