KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > axis > attachments > DimeBodyPart


1 /*
2  * Copyright (C) The Apache Software Foundation. All rights reserved.
3  *
4  * This software is published under the terms of the Apache Software License
5  * version 1.1, a copy of which has been included with this distribution in
6  * the docs/licenses/apache-1.1.txt file.
7  */

8
9 package org.jboss.axis.attachments;
10
11
12 import org.jboss.axis.utils.Messages;
13 import org.jboss.logging.Logger;
14
15 import javax.activation.DataHandler JavaDoc;
16 import javax.activation.DataSource JavaDoc;
17 import java.io.IOException JavaDoc;
18 import java.util.StringTokenizer JavaDoc;
19
20 /**
21  * @author Rick Rineholt
22  */

23
24
25 /**
26  * This class is a single part for DIME mulitpart message.
27  <pre>
28  DIME 1.0 format
29  0 1 2 3
30  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
31  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32  | VERSION |B|E|C| TYPE_T| OPT_T | OPTIONS_LENGTH |
33  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34  | ID_LENGTH | TYPE_LENGTH |
35  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36  | DATA_LENGTH |
37  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38  | /
39  / OPTIONS + PADDING /
40  / |
41  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42  | /
43  / ID + PADDING /
44  / |
45  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46  | /
47  / TYPE + PADDING /
48  / |
49  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50  | /
51  / DATA + PADDING /
52  / |
53  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54  </pre>
55  */

56
57 /**
58  * Holds one attachment DIME part.
59  */

60 public class DimeBodyPart
61 {
62    private static Logger log = Logger.getLogger(DimeBodyPart.class.getName());
63
64    protected Object JavaDoc data = null;
65    protected DimeTypeNameFormat dtnf = null;
66    protected byte[] type = null;
67    protected byte[] id = null;
68    static final byte POSITION_FIRST = (byte)0x04;
69    static final byte POSITION_LAST = (byte)0x02;
70    private static final byte CHUNK = 0x01; //Means set the chunk bit
71
private static final byte CHUNK_NEXT = 0x2; //Means this was part of a CHUNK
72
private static int MAX_TYPE_LENGTH = (1 << 16) - 1;
73    private static int MAX_ID_LENGTH = (1 << 16) - 1;
74
75    static final long MAX_DWORD = 0xffffffffL;
76
77    protected DimeBodyPart()
78    {
79    } //do not use.
80

81    /**
82     * Create a DIME Attachment Part.
83     *
84     * @param data a byte array containing the data as the attachment.
85     * @param format the type format for the data.
86     * @param type the type of the data
87     * @param id the ID for the DIME part.
88     */

89    public DimeBodyPart(byte[] data, DimeTypeNameFormat format,
90                        String JavaDoc type, String JavaDoc id)
91    {
92       System.arraycopy(data, 0, this.data = new byte[data.length], 0, data.length);
93       this.dtnf = format;
94       this.type = type.getBytes();
95       if (this.type.length > MAX_TYPE_LENGTH)
96          throw new IllegalArgumentException JavaDoc(Messages.getMessage
97                  ("attach.dimetypeexceedsmax",
98                          "" + this.type.length, "" + MAX_TYPE_LENGTH));
99       this.id = id.getBytes();
100       if (this.id.length > MAX_ID_LENGTH)
101          throw new IllegalArgumentException JavaDoc(Messages.getMessage("attach.dimelengthexceedsmax", "" + this.id.length,
102                  "" + MAX_ID_LENGTH));
103    }
104
105    /**
106     * Create a DIME Attachment Part.
107     *
108     * @param dh the data for the attachment as a JAF datahadler.
109     * @param format the type format for the data.
110     * @param type the type of the data
111     * @param id the ID for the DIME part.
112     */

113    public DimeBodyPart(DataHandler JavaDoc dh,
114                        DimeTypeNameFormat format, String JavaDoc type, String JavaDoc id)
115    {
116       this.data = dh;
117       this.dtnf = format;
118       if (type == null || type.length() == 0)
119          type = "application/octet-stream";
120       this.type = type.getBytes();
121       if (this.type.length > MAX_TYPE_LENGTH)
122          throw new IllegalArgumentException JavaDoc(Messages.getMessage("attach.dimetypeexceedsmax",
123                  "" + this.type.length, "" + MAX_TYPE_LENGTH));
124       this.id = id.getBytes();
125       if (this.id.length > MAX_ID_LENGTH)
126          throw new IllegalArgumentException JavaDoc(Messages.getMessage("attach.dimelengthexceedsmax",
127                  "" + this.id.length, "" + MAX_ID_LENGTH));
128    }
129
130    /**
131     * Create a DIME Attachment Part.
132     *
133     * @param dh the data for the attachment as a JAF datahadler.
134     * The type and foramt is derived from the DataHandler.
135     * @param id the ID for the DIME part.
136     */

137    public DimeBodyPart(DataHandler JavaDoc dh, String JavaDoc id)
138    {
139       this(dh, DimeTypeNameFormat.MIME, dh.getContentType(), id);
140
141       String JavaDoc ct = dh.getContentType();
142
143       if (ct != null)
144       {
145          ct = ct.trim();
146          if (ct.toLowerCase().startsWith("application/uri"))
147          {
148             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(ct, " \t;");
149             String JavaDoc t = st.nextToken(" \t;");
150
151             if (t.equalsIgnoreCase("application/uri"))
152             {
153                for (; st.hasMoreTokens();)
154                {
155                   t = st.nextToken(" \t;");
156                   if (t.equalsIgnoreCase("uri"))
157                   {
158                      t = st.nextToken("=");
159                      if (t != null)
160                      {
161                         t = t.trim();
162                         if (t.startsWith("\""))
163                            t =
164                                    t.substring(1);
165
166                         if (t.endsWith("\""))
167                            t =
168                                    t.substring(0, t.length() - 1);
169                         this.type = t.getBytes();
170                         this.dtnf = DimeTypeNameFormat.URI;
171                      }
172                      return;
173                   }
174                   else if (t.equalsIgnoreCase("uri="))
175                   {
176                      t = st.nextToken(" \t;");
177                      if (null != t && t.length() != 0)
178                      {
179                         t = t.trim();
180                         if (t.startsWith("\""))
181                            t =
182                                    t.substring(1);
183                         if (t.endsWith("\""))
184                            t =
185                                    t.substring(0, t.length() - 1);
186                         this.type = t.getBytes();
187                         this.dtnf = DimeTypeNameFormat.URI;
188                         return;
189                      }
190                   }
191                   else if (t.toLowerCase().startsWith("uri="))
192                   {
193                      if (-1 != t.indexOf('='))
194                      {
195                         t = t.substring(t.indexOf('=')).trim();
196                         if (t.length() != 0)
197                         {
198                            t = t.trim();
199                            if (t.startsWith("\""))
200                               t =
201                                       t.substring(1);
202
203                            if (t.endsWith("\""))
204                               t = t.substring(0, t.length() - 1);
205                            this.type = t.getBytes();
206                            this.dtnf = DimeTypeNameFormat.URI;
207                            return;
208
209                         }
210                      }
211                   }
212                }
213             }
214          }
215       }
216    }
217
218    /**
219     * Write to stream the data using maxchunk for the largest junk.
220     */

221    void write(java.io.OutputStream JavaDoc os, byte position, long maxchunk)
222            throws java.io.IOException JavaDoc
223    {
224       if (maxchunk < 1)
225          throw new IllegalArgumentException JavaDoc(Messages.getMessage("attach.dimeMaxChunkSize0", "" + maxchunk));
226       if (maxchunk > MAX_DWORD)
227          throw new IllegalArgumentException JavaDoc(Messages.getMessage("attach.dimeMaxChunkSize1", "" + maxchunk));
228       if (data instanceof byte[])
229          send(os, position, (byte[])data,
230                  maxchunk);
231       if (data instanceof DataHandler JavaDoc)
232          send(os, position,
233                  (DataHandler JavaDoc)data, maxchunk);
234    }
235
236    /**
237     * Write to stream the data.
238     */

239    void write(java.io.OutputStream JavaDoc os, byte position)
240            throws java.io.IOException JavaDoc
241    {
242       write(os, position, MAX_DWORD);
243    }
244
245    private static final byte[] pad = new byte[4];
246
247    void send(java.io.OutputStream JavaDoc os, byte position, byte[] data,
248              final long maxchunk) throws java.io.IOException JavaDoc
249    {
250       send(os, position, data, 0, data.length, maxchunk);
251    }
252
253    void send(java.io.OutputStream JavaDoc os, byte position, byte[] data,
254              int offset, final int length, final long maxchunk)
255            throws java.io.IOException JavaDoc
256    {
257
258       byte chunknext = 0;
259
260       do
261       {
262          int sendlength = (int)Math.min(maxchunk, length - offset);
263
264          sendChunk(os, position, data, offset, sendlength, (byte)
265                  ((sendlength < (length - offset) ? CHUNK : 0)
266                  | chunknext));
267          offset += sendlength;
268          chunknext = CHUNK_NEXT;
269       }
270       while (offset < length);
271    }
272
273    void send(java.io.OutputStream JavaDoc os, byte position, DataHandler JavaDoc dh,
274              final long maxchunk) throws java.io.IOException JavaDoc
275    {
276 // START FIX: http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17001
277
java.io.InputStream JavaDoc in = null;
278       try
279       {
280          byte chunknext = 0;
281
282          long dataSize = getDataSize();
283          in = dh.getInputStream();
284          byte[] readbuf = new byte[64 * 1024];
285          int bytesread;
286
287          sendHeader(os, position, dataSize, (byte)0);
288          long totalsent = 0;
289
290          do
291          {
292             bytesread = in.read(readbuf);
293             if (bytesread > 0)
294             {
295                os.write(readbuf, 0, bytesread);
296                totalsent += bytesread;
297             }
298          }
299          while (bytesread > -1);
300          os.write(pad, 0, dimePadding(totalsent));
301       }
302       finally
303       {
304          if (in != null)
305          {
306             try
307             {
308                in.close();
309             }
310             catch (IOException JavaDoc e)
311             {
312                // ignore
313
}
314          }
315       }
316 // END FIX: http://nagoya.apache.org/bugzilla/show_bug.cgi?id=17001
317
}
318
319    protected void sendChunk(java.io.OutputStream JavaDoc os,
320                             final byte position,
321                             byte[] data, byte chunk) throws java.io.IOException JavaDoc
322    {
323
324       sendChunk(os, position, data, 0, data.length, chunk);
325    }
326
327    protected void sendChunk(java.io.OutputStream JavaDoc os,
328                             final byte position, byte[] data, int offset, int length,
329                             byte chunk) throws java.io.IOException JavaDoc
330    {
331
332       sendHeader(os, position, length, chunk);
333       os.write(data, offset, length);
334       os.write(pad, 0, dimePadding(length));
335    }
336
337    static final byte CURRENT_OPT_T = (byte)0;
338
339    protected void sendHeader(java.io.OutputStream JavaDoc os,
340                              final byte position,
341                              long length, byte chunk) throws java.io.IOException JavaDoc
342    {
343       byte[] fixedHeader = new byte[12];
344
345       //VERSION
346
fixedHeader[0] = (byte)((DimeMultiPart.CURRENT_VERSION << 3) & 0xf8);
347
348       // B, E, and C
349
fixedHeader[0] |= (byte)((position & (byte)0x6)
350               & ((chunk & CHUNK) != 0 ? ~POSITION_LAST : ~0) &
351               ((chunk & CHUNK_NEXT) != 0 ? ~POSITION_FIRST : ~0));
352       fixedHeader[0] |= (chunk & CHUNK);
353
354       //TYPE_T
355
if ((chunk & CHUNK_NEXT) == 0) //If this is a follow on chunk dont send id again.
356
fixedHeader[1] = (byte)((dtnf.toByte() << 4) & 0xf0);
357
358       //OPT_T
359
fixedHeader[1] |= (byte)(CURRENT_OPT_T & 0xf);
360
361       //OPTION_LENGTH
362
fixedHeader[2] = (byte)0;
363       fixedHeader[3] = (byte)0;
364
365       //ID_LENGTH
366
if ((chunk & CHUNK_NEXT) == 0)
367       { //If this is a follow on chunk dont send id again.
368
fixedHeader[4] = (byte)((id.length >>> 8) & 0xff);
369          fixedHeader[5] = (byte)((id.length) & 0xff);
370       }
371
372       //TYPE_LENGTH
373
if ((chunk & CHUNK_NEXT) == 0)
374       {
375          fixedHeader[6] = (byte)((type.length >>> 8) & 0xff);
376          fixedHeader[7] = (byte)((type.length) & 0xff);
377       }
378
379       //DATA_LENGTH
380
fixedHeader[8] = (byte)((length >>> 24) & 0xff);
381       fixedHeader[9] = (byte)((length >>> 16) & 0xff);
382       fixedHeader[10] = (byte)((length >>> 8) & 0xff);
383       fixedHeader[11] = (byte)(length & 0xff);
384
385       os.write(fixedHeader);
386
387       //OPTIONS + PADDING
388
// (NONE)
389

390       //ID + PADDING
391
if ((chunk & CHUNK_NEXT) == 0)
392       {
393          os.write(id);
394          os.write(pad, 0, dimePadding(id.length));
395       }
396
397       //TYPE + PADDING
398
if ((chunk & CHUNK_NEXT) == 0)
399       {
400          os.write(type);
401          os.write(pad, 0, dimePadding(type.length));
402       }
403    }
404
405    static final int dimePadding(long l)
406    {
407       return (int)((4L - (l & 0x3L)) & 0x03L);
408    }
409
410    long getTransmissionSize(long chunkSize)
411    {
412       long size = 0;
413       size += id.length;
414       size += dimePadding(id.length);
415       size += type.length;
416       size += dimePadding(type.length);
417       //no options.
418
long dataSize = getDataSize();
419
420       if (0 == dataSize)
421       {
422          size += 12; //header size.
423
}
424       else
425       {
426
427          long fullChunks = dataSize / chunkSize;
428          long lastChunkSize = dataSize % chunkSize;
429
430          if (0 != lastChunkSize) size += 12; //12 bytes for fixed header
431
size += 12 * fullChunks; //add additional header size for each chunk.
432
size += fullChunks * dimePadding(chunkSize);
433          size += dimePadding(lastChunkSize);
434          size += dataSize;
435       }
436       return size;
437    }
438
439    long getTransmissionSize()
440    {
441       return getTransmissionSize(MAX_DWORD);
442    }
443
444    protected long getDataSize()
445    {
446       if (data instanceof byte[]) return ((byte[])(data)).length;
447       if (data instanceof DataHandler JavaDoc)
448          return getDataSize((DataHandler JavaDoc)data);
449       return -1;
450    }
451
452    protected long getDataSize(DataHandler JavaDoc dh)
453    {
454       long dataSize = -1L;
455
456       try
457       {
458          DataSource JavaDoc ds = dh.getDataSource();
459
460          //Do files our selfs since this is costly to read in. Ask the file system.
461
// This is 90% of the use of attachments.
462
if (ds instanceof javax.activation.FileDataSource JavaDoc)
463          {
464             javax.activation.FileDataSource JavaDoc fdh =
465                     (javax.activation.FileDataSource JavaDoc)ds;
466             java.io.File JavaDoc df = fdh.getFile();
467
468             if (!df.exists())
469             {
470                throw new RuntimeException JavaDoc(Messages.getMessage("noFile",
471                        df.getAbsolutePath()));
472             }
473             dataSize = df.length();
474          }
475          else
476          {
477             dataSize = 0;
478             java.io.InputStream JavaDoc in = ds.getInputStream();
479             byte[] readbuf = new byte[64 * 1024];
480             int bytesread;
481
482             do
483             {
484                bytesread = in.read(readbuf);
485                if (bytesread > 0) dataSize += bytesread;
486             }
487             while (bytesread > -1);
488
489             if (in.markSupported())
490             {
491                //Leave the stream open for future reading
492
// and reset the stream pointer to the first byte
493
in.reset();
494             }
495             else
496             {
497                in.close();
498             }
499          }
500       }
501       catch (Exception JavaDoc e)
502       {
503          log.error(Messages.getMessage("exception00"), e);
504       }
505       return dataSize;
506    }
507 }
508
Popular Tags