Wiki source code of Web Services-Sending Large Data
Version 3.1 by Pascal Robert on 2007/09/03 19:36
Show last authors
| author | version | line-number | content |
|---|---|---|---|
| 1 | === Kristoff Cossement === | ||
| 2 | |||
| 3 | Soap with mime attachments was indeed the way to go. | ||
| 4 | |||
| 5 | Remark: this only works with java 1.4.2//09 (I did not get it working with java 1.5.x)// | ||
| 6 | |||
| 7 | For those who are interested I included some sample code on how to exchange large binary data between a java client and and webobjects server without taking all data in memory. | ||
| 8 | You also need the java mail and java activation framework from sun. | ||
| 9 | |||
| 10 | ==== Client.java ==== | ||
| 11 | |||
| 12 | {{code}} | ||
| 13 | |||
| 14 | import javax.xml.soap.SOAPConnectionFactory; | ||
| 15 | import javax.xml.soap.*; | ||
| 16 | import javax.xml.transform.stream.*; | ||
| 17 | import javax.xml.transform.*; | ||
| 18 | import java.io.*; | ||
| 19 | import org.apache.axis.attachments.AttachmentPart; | ||
| 20 | import org.apache.axis.message.*; | ||
| 21 | import javax.activation.DataHandler; | ||
| 22 | import javax.activation.FileDataSource; | ||
| 23 | import javax.xml.soap.SOAPElement; | ||
| 24 | import java.util.*; | ||
| 25 | import javax.mail.*; | ||
| 26 | |||
| 27 | public class Client { | ||
| 28 | |||
| 29 | public static File resize(String sPath) | ||
| 30 | { | ||
| 31 | File file = new File(sPath); | ||
| 32 | |||
| 33 | |||
| 34 | String endPoint = "http://localhost:55555/cgi-bin/WebObjects/project.woa/ws/FileUpload"; | ||
| 35 | try{ | ||
| 36 | SOAPConnection connection = SOAPConnectionFactory.newInstance().createConnection(); | ||
| 37 | SOAPMessage message = (javax.xml.soap.SOAPMessage)MessageFactory.newInstance().createMessage(); | ||
| 38 | SOAPPart part = message.getSOAPPart(); | ||
| 39 | SOAPEnvelope envelope = (org.apache.axis.message.SOAPEnvelope)part.getEnvelope(); | ||
| 40 | SOAPBody body = (org.apache.axis.message.SOAPBody)envelope.getBody(); | ||
| 41 | SOAPBodyElement operation = (org.apache.axis.message.SOAPBodyElement)body.addBodyElement( | ||
| 42 | envelope.createName("upload", | ||
| 43 | "ns", | ||
| 44 | "http://localhost:55555/cgi-bin/WebObjects/project.woa/ws/FileUpload")); | ||
| 45 | operation.setEncodingStyle("http://schemas.xmlsoaporg/soap/encoding/"); | ||
| 46 | |||
| 47 | DataHandler dh = new DataHandler(new FileDataSource(file)); | ||
| 48 | AttachmentPart attachment = (org.apache.axis.attachments.AttachmentPart)message.createAttachmentPart(dh); | ||
| 49 | SOAPElement filename = operation.addChildElement("filename",""); | ||
| 50 | SOAPElement source = operation.addChildElement("source",""); | ||
| 51 | message.addAttachmentPart(attachment); | ||
| 52 | filename.addTextNode(file.getName()); | ||
| 53 | source.addTextNode(attachment.getContentId()); | ||
| 54 | |||
| 55 | SOAPMessage result = connection.call(message,endPoint); | ||
| 56 | System.out.println(result); | ||
| 57 | part = result.getSOAPPart(); | ||
| 58 | envelope = (org.apache.axis.message.SOAPEnvelope)part.getEnvelope(); | ||
| 59 | body = (org.apache.axis.message.SOAPBody)envelope.getBody(); | ||
| 60 | |||
| 61 | if(!body.hasFault()) | ||
| 62 | { | ||
| 63 | System.out.println("answer : "+body); | ||
| 64 | |||
| 65 | } | ||
| 66 | } | ||
| 67 | catch(Exception e) | ||
| 68 | { | ||
| 69 | e.printStackTrace(); | ||
| 70 | } | ||
| 71 | return null; | ||
| 72 | } | ||
| 73 | |||
| 74 | public static void main(String[] args) { | ||
| 75 | |||
| 76 | try { | ||
| 77 | |||
| 78 | resize(args[0]); | ||
| 79 | |||
| 80 | } | ||
| 81 | catch (Exception e) { | ||
| 82 | System.out.println(e.getMessage()); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | {{/code}} | ||
| 88 | |||
| 89 | ==== ==== | ||
| 90 | |||
| 91 | ===== Webobjects Application .java ===== | ||
| 92 | |||
| 93 | override dispatchRequest | ||
| 94 | |||
| 95 | {{code}} | ||
| 96 | |||
| 97 | Â public WOResponse dispatchRequest(WORequest request) | ||
| 98 | { | ||
| 99 | WOResponse result = null; | ||
| 100 | String sURI = request.uri(); | ||
| 101 | NSLog.debug.appendln("Accessing " + sURI); | ||
| 102 | |||
| 103 | Pattern p = Pattern.compile("/ws/FileUpload"); | ||
| 104 | Matcher m = p.matcher(sURI); | ||
| 105 | if(m.find()) | ||
| 106 | { | ||
| 107 | String sContType = request.headerForKey("content-type"); | ||
| 108 | p = Pattern.compile("multipart/related"); | ||
| 109 | m = p.matcher(sContType); | ||
| 110 | if(m.find()) | ||
| 111 | { | ||
| 112 | result = Dispatcher.handleFileUpload(request); | ||
| 113 | } | ||
| 114 | else | ||
| 115 | { | ||
| 116 | result = super.dispatchRequest(request); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | else | ||
| 120 | { | ||
| 121 | result = super.dispatchRequest(request); | ||
| 122 | } | ||
| 123 | |||
| 124 | return result; | ||
| 125 | |||
| 126 | } | ||
| 127 | |||
| 128 | {{/code}} | ||
| 129 | |||
| 130 | ===== Dispatcher.java ===== | ||
| 131 | |||
| 132 | {{code}} | ||
| 133 | |||
| 134 | Â // | ||
| 135 | // Dispatcher.java | ||
| 136 | // project | ||
| 137 | // | ||
| 138 | // Created by admin on 5/5/06. | ||
| 139 | // Copyright 2006 __MyCompanyName__. All rights reserved. | ||
| 140 | // | ||
| 141 | import com.webobjects.foundation.*; | ||
| 142 | import com.webobjects.appserver.*; | ||
| 143 | import com.webobjects.eocontrol.*; | ||
| 144 | |||
| 145 | import java.io.*; | ||
| 146 | import java.util.regex.*; | ||
| 147 | import org.w3c.dom.*; | ||
| 148 | import javax.xml.transform.*; | ||
| 149 | import javax.xml.transform.stream.*; | ||
| 150 | import javax.xml.transform.dom.*; | ||
| 151 | import javax.xml.parsers.*; | ||
| 152 | import org.apache.axis.attachments.*; | ||
| 153 | |||
| 154 | |||
| 155 | public class Dispatcher { | ||
| 156 | |||
| 157 | public static WOResponse handleFileUpload(WORequest request) | ||
| 158 | { | ||
| 159 | String sContType = request.headerForKey("content-type"); | ||
| 160 | String sSoapXml = ""; | ||
| 161 | InputStream requestStream = request.contentInputStream(); | ||
| 162 | |||
| 163 | String sTempDir = System.getProperty("java.io.tmpdir"); | ||
| 164 | String timestamp =(new Long(System.currentTimeMillis())).toString(); | ||
| 165 | File fTempFile = new File(sTempDir+"/"+timestamp); | ||
| 166 | File fSavedFile = new File(sTempDir+"/"+timestamp+".out"); | ||
| 167 | |||
| 168 | try | ||
| 169 | { | ||
| 170 | BufferedOutputStream fOut = new BufferedOutputStream(new FileOutputStream(fTempFile)); | ||
| 171 | byte[] buffer = new byte[32 * 1024]; | ||
| 172 | int bytesRead = 0; | ||
| 173 | while ((bytesRead = requestStream.read(buffer)) != -1) | ||
| 174 | { | ||
| 175 | fOut.write(buffer, 0, bytesRead); | ||
| 176 | } | ||
| 177 | fOut.close(); | ||
| 178 | } | ||
| 179 | catch (Exception e) | ||
| 180 | { | ||
| 181 | NSLog.debug.appendln(e.getMessage()); | ||
| 182 | } | ||
| 183 | |||
| 184 | try | ||
| 185 | { | ||
| 186 | InputStream iStream = new FileInputStream(fTempFile); | ||
| 187 | |||
| 188 | MultiPartRelatedInputStream mis = new MultiPartRelatedInputStream(sContType,iStream); | ||
| 189 | DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | ||
| 190 | Document doc = factory.newDocumentBuilder().parse(mis); | ||
| 191 | sSoapXml = toString(doc); | ||
| 192 | NSLog.debug.appendln("SOAP Envelope: " + sSoapXml); | ||
| 193 | mis.close(); | ||
| 194 | iStream.close(); | ||
| 195 | |||
| 196 | Node nEnvelope = getNamedChildNode(doc,"Envelope"); | ||
| 197 | if(null != nEnvelope) | ||
| 198 | { | ||
| 199 | Node nBody = getNamedChildNode(nEnvelope,"Body"); | ||
| 200 | if(null != nBody) | ||
| 201 | { | ||
| 202 | NSArray nSubNodes = getElementChildNodes(nBody); | ||
| 203 | if((null != nSubNodes) && (nSubNodes.count() > 0)) | ||
| 204 | { | ||
| 205 | Node nFileUpload = (Node)nSubNodes.get(0); | ||
| 206 | nSubNodes = getElementChildNodes(nFileUpload); | ||
| 207 | if((null != nSubNodes) && (nSubNodes.count() > 1)) | ||
| 208 | { | ||
| 209 | Node nFileName = (Node)nSubNodes.get(0); | ||
| 210 | Node nData = (Node)nSubNodes.get(1); | ||
| 211 | |||
| 212 | String sFileName = getTextFromNode(nFileName); | ||
| 213 | String sFileMimeID = getTextFromNode(nData); | ||
| 214 | |||
| 215 | fSavedFile = new File(sTempDir+"/"+sFileName); | ||
| 216 | |||
| 217 | Pattern pattern = Pattern.compile("(boundary=\".+?\")"); | ||
| 218 | Matcher match = pattern.matcher(sContType); | ||
| 219 | if(match.find()) | ||
| 220 | { | ||
| 221 | String boundary= match.group(1); | ||
| 222 | String sSubContentType = "multipart/related; type=\"text/xml\"; start=\"<"+sFileMimeID+">\"; "+boundary; | ||
| 223 | iStream = new FileInputStream(fTempFile); | ||
| 224 | mis = new MultiPartRelatedInputStream(sSubContentType,iStream); | ||
| 225 | try | ||
| 226 | { | ||
| 227 | BufferedOutputStream fOut = new BufferedOutputStream(new FileOutputStream(fSavedFile)); | ||
| 228 | byte[] buffer = new byte[32 * 1024]; | ||
| 229 | int bytesRead = 0; | ||
| 230 | while ((bytesRead = mis.read(buffer)) != -1) | ||
| 231 | { | ||
| 232 | fOut.write(buffer, 0, bytesRead); | ||
| 233 | } | ||
| 234 | mis.close(); | ||
| 235 | fOut.close(); | ||
| 236 | } | ||
| 237 | catch (Exception e) | ||
| 238 | { | ||
| 239 | System.out.println(e.getMessage()); | ||
| 240 | //throw new IOException(me + " failed, got: " + e.toString()); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | } | ||
| 244 | } | ||
| 245 | } | ||
| 246 | } | ||
| 247 | } | ||
| 248 | catch(Exception e) | ||
| 249 | { | ||
| 250 | e.printStackTrace(); | ||
| 251 | } | ||
| 252 | |||
| 253 | |||
| 254 | WOResponse result = new WOResponse(); | ||
| 255 | result.setContent( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+ | ||
| 256 | "<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"+ | ||
| 257 | "<soapenv:Body>\n"+ | ||
| 258 | "<ns:uploadResponse soapenv:encodingStyle=\"http://schemas.xmlsoaporg/soap/encoding/\" xmlns:ns=\"http://localhost:55555/cgi-bin/WebObjects/project.woa/ws/FileUpload\">\n"+ | ||
| 259 | "<ns:uploadReturn xsi:type=\"xsd:boolean\">true</ns:uploadReturn>\n"+ | ||
| 260 | "</ns:uploadResponse>\n"+ | ||
| 261 | "</soapenv:Body>\n"+ | ||
| 262 | "</soapenv:Envelope>"); | ||
| 263 | |||
| 264 | |||
| 265 | result.setHeader("text/xml; charset=utf-8","content-type"); | ||
| 266 | |||
| 267 | |||
| 268 | return result; | ||
| 269 | |||
| 270 | } | ||
| 271 | |||
| 272 | |||
| 273 | static public String toString(Document document) { | ||
| 274 | String result = null; | ||
| 275 | |||
| 276 | if (document != null) { | ||
| 277 | StringWriter strWtr = new StringWriter(); | ||
| 278 | StreamResult strResult = new StreamResult(strWtr); | ||
| 279 | TransformerFactory tfac = TransformerFactory.newInstance(); | ||
| 280 | try { | ||
| 281 | Transformer t = tfac.newTransformer(); | ||
| 282 | t.setOutputProperty(OutputKeys.ENCODING, "utf-8"); | ||
| 283 | t.setOutputProperty(OutputKeys.INDENT, "yes"); | ||
| 284 | t.setOutputProperty(OutputKeys.METHOD, "xml"); //xml, html, text | ||
| 285 | t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); | ||
| 286 | t.transform(new DOMSource(document.getDocumentElement()), strResult); | ||
| 287 | } catch (Exception e) { | ||
| 288 | System.err.println("XML.toString(Document): " + e); | ||
| 289 | } | ||
| 290 | result = strResult.getWriter().toString(); | ||
| 291 | } | ||
| 292 | |||
| 293 | return result; | ||
| 294 | } | ||
| 295 | |||
| 296 | static public Node getNamedChildNode(Node n, String sChildNodeName) | ||
| 297 | { | ||
| 298 | |||
| 299 | NodeList nl = n.getChildNodes(); | ||
| 300 | |||
| 301 | for(int i=0;i<nl.getLength();i++) | ||
| 302 | { | ||
| 303 | Node s = nl.item(i); | ||
| 304 | String sChild = s.getNodeName(); | ||
| 305 | if(sChildNodeName.equalsIgnoreCase(sChild) || sChild.endsWith(":"+sChildNodeName)) | ||
| 306 | { | ||
| 307 | NSLog.debug.appendln("childnode = " + s.getNodeName()); | ||
| 308 | return s; | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | return null; | ||
| 313 | |||
| 314 | } | ||
| 315 | static public NSArray getElementChildNodes(Node n) | ||
| 316 | { | ||
| 317 | NSMutableArray elements = new NSMutableArray(); | ||
| 318 | NodeList nl = n.getChildNodes(); | ||
| 319 | |||
| 320 | for(int i=0;i<nl.getLength();i++) | ||
| 321 | { | ||
| 322 | Node s = nl.item(i); | ||
| 323 | if(s.getNodeType() == Node.ELEMENT_NODE) | ||
| 324 | { | ||
| 325 | NSLog.debug.appendln("childnode = " + s.getNodeName()); | ||
| 326 | elements.addObject(s); | ||
| 327 | } | ||
| 328 | } | ||
| 329 | |||
| 330 | return elements; | ||
| 331 | } | ||
| 332 | static public String getTextFromNode(Node n) | ||
| 333 | { | ||
| 334 | String text = ""; | ||
| 335 | |||
| 336 | NodeList nl = n.getChildNodes(); | ||
| 337 | |||
| 338 | for(int i=0;i<nl.getLength();i++) | ||
| 339 | { | ||
| 340 | Node s = nl.item(i); | ||
| 341 | if(s.getNodeType() == Node.TEXT_NODE) | ||
| 342 | { | ||
| 343 | return s.getNodeValue(); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | return text; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | {{/code}} |