WebObjects/Web Services/Sending Large Data
Kristoff Cossement
editSoap 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
editimport 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
editoverride 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; } }