DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Transferring Large Files Between .Net & Java: Web Services Interoperability

01.31.2012
| 6267 views |
  • submit to reddit
        It seems alot people have been experiencing problems uploading/downloading extremely large files via web services between a .Net web services client and a Java based web service. This note will hopefully put the matter to rest. The JAX-WS / Metro framework requires one to pass/return a Datahandler when accepting/returning streamed data. The problem is that when generating the stub code in Microsoft Visual Studio from the WSDL exported from the Java server, a byte[] array is returned in place of the Data Handler. The reason is that .NET does not know what a Java Datahandler is. When processing a very large file, say. 3 GB, your client will run out of memory. What we really want is for .Net to generate a Stream object in place of the byte array. To accomplish this, we need to employ some trickery. Say you have a class called ServerService and you want to upload a file, specifying the file name as the parameter. You would do this as follows:

  @MTOM(enabled = true, threshold = 512)    
  @StreamingAttachment(parseEagerly=true, memoryThreshold=4000000L)   
  @WebService   
  public class ServerService {   
   @WebMethod   
   public upload(@WebParam(name="fileStream")StreamBody stream) {   
     Datahandler dh = stream.getDataHandler();   
    // copy data from datahandler to file   
   }   
  }   

The constraint of the above is that the upload method using a stream may have only one parameter. One way around to specify the file name & other attributes in the Data itself. Simply write a FilterInputStream that reads and parses the first few lines. These lines are the attribute/name pairs that describe the data, i.e. filename, etc. When a linefeed is encountered the data itself begins. The below class is necessary to jinx .Net into creating a Stream object:

 @XmlAccessorType(XmlAccessType.FIELD)  
 @XmlType(name = "StreamBody", namespace = "http://schemas.microsoft.com/Message")  
 public class StreamBody {  
   /**  
    * The data stream.  
    */  
   @XmlValue  
   public DataHandler dataHandler;  
   public DataHandler getDataHandler() {  
     return dataHandler;  
   }  
   public void setDataHandler(DataHandler dataHandler) {  
     this.dataHandler = dataHandler;  
   }  
 }  

To enable mtom in your Java web services server, modify the sun-jaxws.xml with enable-mtom="true" as follows:

 <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">    
   <endpoint name="FileArchiva" implementation="com.stimulus.archiva.file.webservice.FileArchivaWS"  
     url-pattern="/FileArchivaWS"  
     wsdl-location="WEB-INF/wsdl/library.wsdl" enable-mtom="true"/>  
 </endpoints>  

To enable streaming and MTOM on the .Net client, modify a file called app.config and add the parameters messageEncoding="Mtom" and transferMode="Streamed".

 <system.serviceModel>  
   <bindings>  
    <basicHttpBinding>  
     <binding name="FileArchivaWSPortBinding" closeTimeout="00:01:00"  
      openTimeout="01:00:00" receiveTimeout="01:00:00" sendTimeout="01:00:00"  
      allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"  
      maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"  
      messageEncoding="Mtom" textEncoding="utf-8" transferMode="Streamed"  
      useDefaultWebProxy="true">  
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"  
       maxBytesPerRead="4096" maxNameTableCharCount="16384" />  
      <security mode="None">  
       <transport clientCredentialType="None" proxyCredentialType="None"  
        realm="" />  
       <message clientCredentialType="UserName" algorithmSuite="Default" />  
      </security>  
     </binding>  
    </basicHttpBinding>  
   </bindings>