Re: Streaming attachment uploads
I did the HTTP PUT logic in two parts.
With 8.0.0 you can put an attachment on any mail / calendar item
(with the caveat that you can only put personal attachments on
sent and received items). I expose most of the elements from the
AttachmentItemInfo element:
<xs:complexType name="AttachmentItemInfo">
<xs:sequence>
<xs:element name="id" type="tns:AttachmentID" minOccurs="0"/>
<xs:element ref="tns:name" minOccurs="0"/>
<xs:element name="contentId" type="xs:string" minOccurs="0"/>
<xs:element name="contentType" type="xs:string" minOccurs="0"/>
<xs:element name="size" type="xs:unsignedInt" minOccurs="0"/>
<xs:element name="date" type="xs:dateTime" minOccurs="0"/>
<xs:element name="data" type="xs:base64Binary" minOccurs="0"/>
<xs:element name="hidden" type="xs:boolean" minOccurs="0"/>
<xs:element name="isPersonal" type="xs:boolean" minOccurs="0"/>
<xs:element name="hash" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
On the HTTP PUT, you specify the id of the item you want to add
the attachment. You need to specify the name. You can specify
contentId, contentType, date and isPersonal. As with all parameters
in a URL, you separate the parameters with '&' and do param'='value.
For example "...&name=test.txt..." You can only stream one attachment
at a time.
To stream attachments to an item that you want to send, it is a
multiple step process. You create a draft item. You stream the
attachment to the draft item. Then you send the draft item.
I had to put in a hook on the send to reference the original draft item
on the send. I added a new "draft" value to the LinkType element.
<xs:complexType name="LinkInfo">
<xs:sequence>
<xs:element name="id" type="xs:string"/>
<xs:element name="type" type="tns:LinkType"/>
<xs:element name="thread" type="xs:string" minOccurs="0"/>
<xs:element name="copyAttachments" type="xs:boolean" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="LinkType">
<xs:restriction base="xs:string">
<xs:enumeration value="forward"/>
<xs:enumeration value="reply"/>
<xs:enumeration value="draft"/>
</xs:restriction>
</xs:simpleType>
When you send the email, you put the id of the draft item (that
has the attachment and <type>draft</type> in the <link> element
of the item to send. After the send is complete, the draft item is
purged. As a side note, I didn't see a significant improvement in
streaming attachments into items, but it was still faster to stream
large appointments. It is also significantly more efficient to stream
in the attachments. It optimally uses memory allocations.
Here is some test code showing how this is done:
public void testStreamAttachment() {
byte[] bytes;
byte[] b = new byte[ 16384 ];
Calendar end;
Calendar start;
Distribution dist = new Distribution();
File file;
FileInputStream in;
HttpURLConnection huc;
int code;
int len;
LinkInfo link = new LinkInfo();
Mail mail = new Mail();
MessageBody mb = new MessageBody();
MessagePart[] mp = new MessagePart[1];
OutputStream os;
Recipient[] recip = new Recipient[1];
RecipientList list = new RecipientList();
SendItemResponse resp = null;
String id;
String str;
URL url;
try {
// get the start time
start = Calendar.getInstance();
// set up the draft appointment
mail.setSubject( "Test of HTTP PUT" );
mail.setSource( ItemSource.draft );
bytes = "Message Body!".getBytes( "UTF-8" );
mp[0] = new MessagePart();
mp[0].set_value( bytes );
mb.setPart( mp );
mail.setMessage( mb );
recip[ 0 ] = new Recipient();
recip[ 0 ].setDisplayName( "Preston Stephenson" );
recip[ 0 ].setEmail( "pstephenson@prestons.provo.novell.com" );
recip[ 0 ].setDistType( DistributionType.TO );
list.setRecipient( recip );
dist.setRecipients( list );
mail.setDistribution( dist );
// create the draft appointment
resp = m_main.getService().sendItemRequest( mail, m_main.getSessionId(),
m_main.getTrace() );
if ( 0 != resp.getStatus().getCode() ) {
m_main.displayError( resp.getStatus(), "testStreamAttachment" );
}
// get the id of the draft appointment
// encode it for the HTTP PUT
id = URLEncoder.encode(resp.getId()[0], "UTF-8");
// set up the url
str = "http://" + m_main.getLogin().getServer() + ":" +
m_main.getLogin().getPort() + "/attachment?session="
+ m_main.getSessionId() + "&id=" + id + "&name=testgw.txt";
url = new URL( str );
// set up the file stream
file = new File( "c:\\temp", "testgw.txt" );
str = String.valueOf( file.length() );
// set up the HTTP PUT
huc = (HttpURLConnection)url.openConnection();
huc.setDoOutput( true );
huc.setRequestMethod( "PUT" );
huc.setFixedLengthStreamingMode( (int)file.length() );
// stream the data
os = huc.getOutputStream();
in = new FileInputStream( file );
for ( ;; ) {
len = in.read(b);
if ( -1 == len ) {
break;
}
os.write( b, 0, len );
}
os.close();
// wait for the PUT to finish
code = huc.getResponseCode();
if ( code < 200 || code > 299 ) {
m_main.displayError( resp.getStatus(), "testStreamAttachment" );
}
// set up the mail item to send
mail = new Mail();
recip[ 0 ] = new Recipient();
recip[ 0 ].setDisplayName( "Preston Stephenson" );
recip[ 0 ].setEmail( "pstephenson@prestons.provo.novell.com" );
recip[ 0 ].setDistType( DistributionType.TO );
list.setRecipient( recip );
dist.setRecipients( list );
mail.setDistribution( dist );
// set the link type to get the information from the draft message
link.setType( LinkType.draft );
link.setId( resp.getId()[0] );
mail.setLink( link );
// send the item
resp = m_main.getService().sendItemRequest( mail, m_main.getSessionId(),
m_main.getTrace() );
// output the time it took to build and send the email
end = Calendar.getInstance();
str = "Streaming: " + String.valueOf( end.getTimeInMillis() -
start.getTimeInMillis() );
m_main.displayError( resp.getStatus(), str );
} catch ( Exception e ) {
e.printStackTrace();
}
}
The logic will be in 8.0.1 HP1 and later builds.
Let me know if you have questions or problems.
You can reply privately and I can send you a link
to a development 8.0.1 HP1 build.
Preston
>>> On Thursday, September 17, 2009 at 4:50 AM, Ray<ray@nospam.de> wrote:
> Hey Preston,
>
> I second that idea !
>
> I suggest the HTTP PUT option.
> Its much easier to parse than a POST.
> ( Just get the bytes after the double return chars, length is in
> Content‑Length header )
>
> And you can still give options on the query part of the URL.
>
> Example:
>
> PUT /attachment?session=kewdxkedsa&id=DraftMsgID&name=e xample.doc
>
> where id points to a draft message ID.
>
> After the call the attachment is uploaded and attached to the specified
> draft msg.
>
> Regards,
> Ray.
>
> "Preston Stephenson" <PStephenson@gw.novell.com> schrieb im Newsbeitrag
> news:4AADE249.07F1.0037.1@gw.novell.com...
>>I haven't figured out a way to stream in attachments
>> for a send.
>>
>>
>>>>> On Friday, September 11, 2009 at 6:13 PM, Sean
>> Kirkby<skirkby@armordatasystems.com> wrote:
>>> Hi,
>>>
>>> As I understand it, the streaming attachments feature was added to
>>> provide
>> a
>>> faster option for downloading large attachments.
>>>
>>> Is performance also a problem when sending new mail with large
>> attachments?
>>> If so, is there a more efficient/faster way to stream attachments UP to
>> the
>>> POA?
>>>
>>> Or do we still just need to base64‑encode the attachment and put it
in
>> an
>>> attachmentItemInfo object in the message, and send/create via
>> sendItemRequest
>>> and/or createItemRequest?
>>>
>>> Thanks.
>>>
>>> ‑‑sk.
|