Re: Webobjects WebServices - howto stream large Binary Objects

Kristof Cossement <[email protected]>
Newsgroups gmane.comp.web.webobjects.devel
Message-ID <[email protected]>
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 and webobjects  
server without taking all data in memory.
You also need the java mail and java activation framework from sun.



Client.java
=========


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.xmlsoap.org/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
======================

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
//  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.xmlsoap.org/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.xmlsoap.org/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;
	}
}



On Mar 29, 2006, at 5:09 AM, Marc Respass wrote:

> WebObjects uses Apache Axis for WebServices. It looks like SOAP  
> with attachments is the way to g . Here's an article that may help  
> (http://www.devx.com/ibm/Article/20254). It looks like some work  
> will need to be done on the client side to retrieve the attachment.  
> From the article "Note that Listing 3 makes it clear that the  
> attachment is outside of the XML message! This is necessary for  
> efficiency." This looks interesting. Good luck. If you get it  
> working and you want to, post some sample code back :)
>
> Marc
>
> On Mar 28, 2006, at 9:10 AM, Kristof Cossement wrote:
>
>> I want to use webobjects for creating webservices to send large  
>> binary files (eg a zipfile of 200Mb)
>>
>> This works for small data objects (like a jpg of 50kB)
>> The problem is the data is not getting streamed, but the entire  
>> file is being read in memory, which causes stack overflows.
>>
>> Could someone give me a hint on how I can communicate through  
>> webservices with large binary data objects?
>>
>> This is an extract of the code I use:
>>
>> WebService Consumer (Project 1)
>> ============================
>>
>> 	FileInputStream is = new FileInputStream("/path/to/file");
>>
>> 	NSData d = new NSData(is,1024);	 // CRASHES HERE !!!
>> 		
>> 	Object [] params = new Object[1];
>> 	params[0] = d;
>> 	
>> 	WOWebServiceClient client = new WOWebServiceClient();
>> 	// extra initialisation here
>> 	
>> 	Object result = client.invoke("FileUpload", "upload", params);
>>
>>
>>
>>
>> This is the WebService (Project 2)
>> ================================
>> // I create a routine with an "NSData" parameter and register it  
>> as a webservice
>>
>> WOWebServiceRegistrar.registerWebService(FileUpload.class, true);
>>
>>
>> import java.io.*;
>> import com.webobjects.foundation.*;
>>
>> public class FileUpload {
>> public static boolean upload(NSData d) {
>> 			
>> 		//OutputStream stream
>> 		try {
>> 			FileOutputStream fileOutputStream = new FileOutputStream("/tmp/ 
>> file");
>> 			d.writeToStream(fileOutputStream);
>> 			fileOutputStream.close();
>> 		}
>> 		catch (IOException exception) {
>> 			// Do something with the exception
>> 		}
>>
>> 	 return true;
>> 	}
>> }
>>
>>
>>
>>
>>
>>
>>
>> This e-mail, and any attachments thereto, is intended only for use  
>> by the addressee(s) named herein and may contain legally  
>> privileged and/or confidential information and/or information  
>> protected by intellectual property rights.
>> If you are not the intended recipient, please note that any  
>> review, dissemination, disclosure, alteration, printing, copying  
>> or transmission of this e-mail and/or any file transmitted with  
>> it, is strictly prohibited and may be unlawful.
>> If you have received this e-mail by mistake, please immediately  
>> notify the sender and permanently delete the original as well as  
>> any copy of any e-mail and any printout thereof.
>> We may monitor e-mail to and from our network.
>>
>> NSS nv Tieltstraat 167 8740 Pittem Belgium
>>
>>
>> _______________________________________________
>> WebObjects-dev mailing list
>> [email protected]
>> http://www.omnigroup.com/mailman/listinfo/webobjects-dev
>

_______________________________________________
WebObjects-dev mailing list
[email protected]
http://www.omnigroup.com/mailman/listinfo/webobjects-dev
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.