WebObjects/Web Services/Sending Large Data

Kristoff Cossement edit

Soap with mime attachments was indeed the way to go.

Remark: this only works with java 1.4.2_09 (I did not get it working with java 1.5.x)

For those who are interested I included some sample code on how to exchange large binary data between a java client and a webobjects server without taking all data in memory. You also need the java mail and java activation framework from sun.

Client.java edit
 import javax.xml.soap.SOAPConnectionFactory;
 import javax.xml.soap.*;
 import javax.xml.transform.stream.*;
 import javax.xml.transform.*;
 import java.io.*;
 import org.apache.axis.attachments.AttachmentPart;
 import org.apache.axis.message.*;
 import javax.activation.DataHandler;
 import javax.activation.FileDataSource;
 import javax.xml.soap.SOAPElement;
 import java.util.*;
 import javax.mail.*;
 
 public class Client {
 
   public static File resize(String sPath)
   {
     File file = new File(sPath);
 
 
     String endPoint = "http://localhost:55555/cgi-bin/WebObjects/project.woa/ws/FileUpload";
     try{
       SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection();
       SOAPMessage message = (javax.xml.soap.SOAPMessage)MessageFactory.newInstance().createMessage();
       SOAPPart part = message.getSOAPPart();
       SOAPEnvelope envelope = (org.apache.axis.message.SOAPEnvelope)part.getEnvelope();
       SOAPBody body = (org.apache.axis.message.SOAPBody)envelope.getBody();
       SOAPBodyElement operation = (org.apache.axis.message.SOAPBodyElement)body.addBodyElement(
           envelope.createName("upload",
             "ns",
             "http://localhost:55555/cgi-bin/WebObjects/project.woa/ws/FileUpload"));
       operation.setEncodingStyle("http://schemas.xmlsoaporg/soap/encoding/");
 
       DataHandler dh = new DataHandler(new FileDataSource(file));
       AttachmentPart attachment = (org.apache.axis.attachments.AttachmentPart)message.createAttachmentPart(dh);
       SOAPElement filename = operation.addChildElement("filename","");
       SOAPElement source = operation.addChildElement("source","");
       message.addAttachmentPart(attachment);
       filename.addTextNode(file.getName());
       source.addTextNode(attachment.getContentId());
 
       SOAPMessage result = connection.call(message,endPoint);
       System.out.println(result);
       part = result.getSOAPPart();
       envelope = (org.apache.axis.message.SOAPEnvelope)part.getEnvelope();
       body = (org.apache.axis.message.SOAPBody)envelope.getBody();
 
       if(!body.hasFault())
       {
         System.out.println("answer : "+body);
 
       }
     }
     catch(Exception e)
     {
       e.printStackTrace();
     }
     return null;
   }
 
   public static void main(String[] args) {
 
     try {
 
       resize(args[0]);
 
     }
     catch (Exception e) {
       System.out.println(e.getMessage());
     }
   }
 }
Webobjects Application .java edit

override dispatchRequest

 public WOResponse dispatchRequest(WORequest request)
 {
   WOResponse result = null;
   String sURI = request.uri();
   NSLog.debug.appendln("Accessing " + sURI);
 
   Pattern p = Pattern.compile("/ws/FileUpload");
   Matcher m = p.matcher(sURI);
   if(m.find())
   {
     String sContType = request.headerForKey("content-type");
     p = Pattern.compile("multipart/related");
     m = p.matcher(sContType);
     if(m.find())
     {
       result = Dispatcher.handleFileUpload(request);
     }
     else
     {
       result = super.dispatchRequest(request);
     }
   }
   else
   {
     result = super.dispatchRequest(request);
   }
 
   return result;
 
 }
Dispatcher.java edit
 //
 // Dispatcher.java
 // project
 //
 // Created by admin on 5/5/06.
 // Copyright 2006 __MyCompanyName__. All rights reserved.
 //
 import com.webobjects.foundation.*;
 import com.webobjects.appserver.*;
 import com.webobjects.eocontrol.*;
 
 import java.io.*;
 import java.util.regex.*;
 import org.w3c.dom.*;
 import javax.xml.transform.*;
 import javax.xml.transform.stream.*;
 import javax.xml.transform.dom.*;
 import javax.xml.parsers.*;
 import org.apache.axis.attachments.*;
 
 
 public class Dispatcher {
 
   public static WOResponse handleFileUpload(WORequest request)
   {
     String sContType = request.headerForKey("content-type");
     String sSoapXml = "";
     InputStream requestStream = request.contentInputStream();
 
     String sTempDir = System.getProperty("java.io.tmpdir");
     String timestamp =(new Long(System.currentTimeMillis())).toString();
     File fTempFile = new File(sTempDir+"/"+timestamp);
     File fSavedFile = new File(sTempDir+"/"+timestamp+".out");
 
     try
     {
       BufferedOutputStream fOut = new BufferedOutputStream(new FileOutputStream(fTempFile));
       byte[] buffer = new byte[32 * 1024];
       int bytesRead = 0;
       while ((bytesRead = requestStream.read(buffer)) != -1)
       {
         fOut.write(buffer, 0, bytesRead);
       }
       fOut.close();
     }
     catch (Exception e)
     {
       NSLog.debug.appendln(e.getMessage());
     }
 
     try
     {
       InputStream iStream = new FileInputStream(fTempFile);
 
       MultiPartRelatedInputStream mis = new MultiPartRelatedInputStream(sContType,iStream);
       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
       Document doc = factory.newDocumentBuilder().parse(mis);
       sSoapXml = toString(doc);
       NSLog.debug.appendln("SOAP Envelope: " + sSoapXml);
       mis.close();
       iStream.close();
 
       Node nEnvelope = getNamedChildNode(doc,"Envelope");
       if(null != nEnvelope)
       {
         Node nBody = getNamedChildNode(nEnvelope,"Body");
         if(null != nBody)
         {
           NSArray nSubNodes = getElementChildNodes(nBody);
           if((null != nSubNodes) && (nSubNodes.count() > 0))
           {
             Node nFileUpload = (Node)nSubNodes.get(0);
             nSubNodes = getElementChildNodes(nFileUpload);
             if((null != nSubNodes) && (nSubNodes.count() > 1))
             {
               Node nFileName = (Node)nSubNodes.get(0);
               Node nData = (Node)nSubNodes.get(1);
 
               String sFileName = getTextFromNode(nFileName);
               String sFileMimeID = getTextFromNode(nData);
 
               fSavedFile = new File(sTempDir+"/"+sFileName);
 
               Pattern pattern = Pattern.compile("(boundary=\".+?\")");
               Matcher match = pattern.matcher(sContType);
               if(match.find())
               {
                 String boundary= match.group(1);
                 String sSubContentType = "multipart/related; type=\"text/xml\"; start=\"<"+sFileMimeID+">\";   "+boundary;   
                 iStream = new FileInputStream(fTempFile);
                 mis = new MultiPartRelatedInputStream(sSubContentType,iStream);
                 try
                 {
                   BufferedOutputStream fOut = new BufferedOutputStream(new FileOutputStream(fSavedFile));
                   byte[] buffer = new byte[32 * 1024];
                   int bytesRead = 0;
                   while ((bytesRead = mis.read(buffer)) != -1)
                   {
                     fOut.write(buffer, 0, bytesRead);
                   }
                   mis.close();
                   fOut.close();
                 }
                 catch (Exception e)
                 {
                   System.out.println(e.getMessage());
                   //throw new IOException(me + " failed, got: " + e.toString());
                 }
               }
             }
           }  
         }
       }
     }
     catch(Exception e)
     {
       e.printStackTrace();
     }
 
 
     WOResponse result = new WOResponse();
     result.setContent( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
         "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoaporg/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"+
         "<soapenv:Body>\n"+
         "<ns:uploadResponse soapenv:encodingStyle=\"http://schemas.xmlsoaporg/soap/encoding/\" xmlns:ns=\"http://localhost:55555/cgi-bin/WebObjects/project.woa/ws/FileUpload\">\n"+
         "<ns:uploadReturn xsi:type=\"xsd:boolean\">true</ns:uploadReturn>\n"+
         "</ns:uploadResponse>\n"+
         "</soapenv:Body>\n"+
         "</soapenv:Envelope>");
 
 
     result.setHeader("text/xml; charset=utf-8","content-type");
 
 
     return result;
 
   }
 
 
   static public String toString(Document document) {
     String result = null;
 
     if (document != null) {
       StringWriter strWtr = new StringWriter();
       StreamResult strResult = new StreamResult(strWtr);
       TransformerFactory tfac = TransformerFactory.newInstance();
       try {
         Transformer t = tfac.newTransformer();
         t.setOutputProperty(OutputKeys.ENCODING, "utf-8");
         t.setOutputProperty(OutputKeys.INDENT, "yes");
         t.setOutputProperty(OutputKeys.METHOD, "xml"); //xml, html, text
         t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
         t.transform(new DOMSource(document.getDocumentElement()), strResult);
       } catch (Exception e) {
         System.err.println("XML.toString(Document): " + e);
       }
       result = strResult.getWriter().toString();
     }
 
     return result;
   }
 
   static public Node getNamedChildNode(Node n, String sChildNodeName)
   {
 
     NodeList nl = n.getChildNodes();
 
     for(int i=0;i<nl.getLength();i++)
     {
       Node s = nl.item(i);
       String sChild = s.getNodeName();
       if(sChildNodeName.equalsIgnoreCase(sChild) || sChild.endsWith(":"+sChildNodeName))
       {
         NSLog.debug.appendln("childnode = " + s.getNodeName());
         return s;
       }
     }
 
     return null;
 
   }
   static public NSArray getElementChildNodes(Node n)
   {
     NSMutableArray elements = new NSMutableArray();
     NodeList nl = n.getChildNodes();
 
     for(int i=0;i<nl.getLength();i++)
     {
       Node s = nl.item(i);
       if(s.getNodeType() == Node.ELEMENT_NODE)
       {
         NSLog.debug.appendln("childnode = " + s.getNodeName());
         elements.addObject(s);
       }
     }
 
     return elements;
   }
   static public String getTextFromNode(Node n)
   {
     String text = "";
 
     NodeList nl = n.getChildNodes();
 
     for(int i=0;i<nl.getLength();i++)
     {
       Node s = nl.item(i);
       if(s.getNodeType() == Node.TEXT_NODE)
       {
         return s.getNodeValue();
       }
     }
     return text;
   }
 }