Using SOAP Attachments
JAX-WS web services support the ability to include binary data in a scalable fashion in your SOAP requests.
Just as with legacy web services, to upload binary data (available on the input stream of your Info*Engine task), simply add a parameter to your task with a type of javax.activation.DataSource.
Unlike legacy Info*Engine web services, which used standard MIME SOAP attachments, JAX-WS web services use attachment references to make binary data appear as inline web service parameters. However, this approach no longer implicitly allows a SOAP client to include associated information like the filename or content type with the attachment using the Content-Disposition MIME header. As a result, Info*Engine web services now allow the filename to be specified as a separate parameter associated with the attachment. If an additional parameter is not used to specify an attachment filename, then the attachment has a default filename of “unknown.”
You can also explicitly specify the content type of the attachment. This, however, only alters the content type that is exposed to Info*Engine components for the incoming data. If not specified, then the default value for the attachment content type is application/octet-stream.
For example:
@param string fileName The filename
@param javax.activation.DataSource file The file to stage {fileName:fileName}
{contentType:image/jpeg}
In the previous example, your task receives a BLOB (attachment) and the filename of the attachment is specified by the accompanying fileName parameter value. The Content-Type of that attachment is exposed to the Info*Engine task as image/jpeg. It is important to note that this does nothing more than provide a value for the Content-Type of the incoming attachment. It does not force a web service client to comply with that Content-Type when supplying the data.
As with legacy web services, return an attachment from a task by simply specifying its return type as java.io.InputStream. In both the upload and download scenario, a Java web client is presented with a parameter or return value with a type of javax.activation.DataHandler.
In both the upload and download scenarios, an Info*Engine web service tunnels data between your task and the web service client to efficiently transfer it to and from Windchill. An efficient upload, however, is somewhat dependent upon how the client supplies the data. Small amounts of data can be internalized to memory, but clients should chunk the MIME data when sending large amounts. When using a Java-based client you must explicitly instruct the client to chunk data destined for the server or your client will likely die with an OutOfMemoryError. You should add the HTTP_CLIENT_STREAMING_CHUNK_SIZE property in your request context prior to uploading an attachment to Windchill. It is also very important to note that if you do not do this, it is likely that your application may put undue stress on the memory resources of the server on which your web service is running.
For example:
import java.io.File;
import javax.activation.FileDataSource;
import javax.activation.DataHandler;
import javax.xml.ws.BindingProvider;
import com.sun.xml.ws.developer.JAXWSProperties;
...
((BindingProvider)port).getRequestContext ().put ( JAXWSProperties.
HTTP_CLIENT_STREAMING_CHUNK_SIZE, 8192 );
File f = new File ( path );
DataHandler file = new DataHandler ( new FileDataSource ( f ) );
port.upload ( f.getName(), file );
In addition, when performing downloads it is important to test the resulting DataHandler to see if it is an instance of StreamingDataHandler. When downloading large amounts of data, the Sun classes may store that data in a temporary file. If you do not explicitly close an instance of StreamingDataHandler, then this temporary file remains on your client machine occupying disk space.
For example:
import javax.activation.DataHandler;
import com.sun.xml.ws.developer.StreamingDataHandler;
...
DataHandler file = null;
try
{
file = port.download ( ... );
..
// transfer the data to another stream/file, etc.
file.writeTo ( ... );
}
finally
{
if ( file instanceof StreamingDataHandler )
((StreamingDataHandler)file).close(); // remove any temporary file
}