KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 /* @author Rob Jellinghaus (robj@unrealities.com) */
18 /* @author Rick Rineholt */
19 package org.jboss.axis.attachments;
20
21 import org.jboss.axis.AxisFault;
22 import org.jboss.axis.Message;
23 import org.jboss.axis.MessagePart;
24 import org.jboss.axis.Part;
25 import org.jboss.axis.utils.Messages;
26 import org.jboss.logging.Logger;
27
28 import javax.activation.DataHandler JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.util.Collection JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.LinkedList JavaDoc;
33 import java.util.StringTokenizer JavaDoc;
34
35 /**
36  * Implements the Attachment interface, via an actual Hashmap of actual
37  * AttachmentParts.
38  */

39 public class AttachmentsImpl implements Attachments
40 {
41    private static Logger log = Logger.getLogger(AttachmentsImpl.class.getName());
42
43    /**
44     * Field attachments.
45     */

46    private HashMap JavaDoc attachments = new java.util.HashMap JavaDoc();
47
48    /**
49     * Field orderedAttachments.
50     */

51    private LinkedList JavaDoc orderedAttachments = new LinkedList JavaDoc();
52
53    /**
54     * Field soapPart.
55     */

56    protected MessagePart soapPart = null;
57
58    /**
59     * The actual stream to manage the multi-related input stream.
60     */

61    protected MultiPartInputStream mpartStream =
62            null;
63    /**
64     * The form of the attachments, whether MIME or DIME.
65     */

66    protected int sendtype = Attachments.SEND_TYPE_NOTSET;
67
68    /**
69     * This is the content location as specified in SOAP with Attachments.
70     * This maybe null if the message had no Content-Location specifed.
71     */

72    protected String JavaDoc contentLocation = null;
73
74    /**
75     * The HashMap for DataHandler Managements.
76     */

77    private HashMap JavaDoc stackDataHandler = new HashMap JavaDoc();
78
79    /**
80     * Construct one of these on a parent Message.
81     * Should only ever be called by Message constructor!
82     * <p/>
83     * 1. mime-type: [unknown]
84     * do nothing
85     * <p/>
86     * 2. mime-type: multipart/related
87     * 2.1 create a MultiPartRelatedInputStream that does the parsing of the input stream
88     * 2.2 create a SOAPPart from the MultiPartRelatedInputStream
89     * <p/>
90     * 3. mime-type: application/dime
91     * 3.1 create a MultiPartDimeInputStream that does the parsing of the input stream
92     * 3.2 create a SOAPPart from the MultiPartDimeInputStream
93     *
94     * @param intialContents should be anything but today only a stream is
95     * supported.
96     * @param contentType The mime content type of the stream for transports
97     * that provide it.
98     * @param contentLocation
99     * @throws org.jboss.axis.AxisFault
100     */

101    public AttachmentsImpl(Object JavaDoc intialContents, String JavaDoc contentType, String JavaDoc contentLocation)
102            throws org.jboss.axis.AxisFault
103    {
104
105       if (contentLocation != null)
106       {
107          contentLocation = contentLocation.trim();
108
109          if (contentLocation.length() == 0)
110          {
111             contentLocation = null;
112          }
113       }
114
115       this.contentLocation = contentLocation;
116
117       if (contentType != null)
118       {
119          if (contentType.equals(Message.MIME_UNKNOWN))
120          {
121             log.warn("Unknown contentType");
122          }
123          else
124          {
125             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(contentType, " \t;");
126
127             if (st.hasMoreTokens())
128             {
129                String JavaDoc mimetype = st.nextToken();
130
131                if (mimetype.equalsIgnoreCase(Message.MIME_MULTIPART_RELATED))
132                {
133                   sendtype = SEND_TYPE_MIME;
134                   mpartStream = new MultiPartRelatedInputStream(contentType, (InputStream JavaDoc)intialContents);
135
136                   if (null == contentLocation)
137                   {
138
139                      // If the content location is not specified as
140
// of the main message use the SOAP content location.
141
contentLocation = mpartStream.getContentLocation();
142
143                      if (contentLocation != null)
144                      {
145                         contentLocation = contentLocation.trim();
146
147                         if (contentLocation.length() == 0)
148                         {
149                            contentLocation = null;
150                         }
151                      }
152                   }
153
154                   soapPart = new MessagePart(null, mpartStream, false);
155                }
156                else if (mimetype.equalsIgnoreCase(Message.MIME_APPLICATION_DIME))
157                {
158                   try
159                   {
160                      mpartStream = new MultiPartDimeInputStream((InputStream JavaDoc)intialContents);
161                      soapPart = new MessagePart(null, mpartStream, false);
162                   }
163                   catch (Exception JavaDoc e)
164                   {
165                      throw AxisFault.makeFault(e);
166                   }
167                   sendtype = SEND_TYPE_DIME;
168                }
169             }
170          }
171       }
172    }
173
174    /**
175     * Copies attachment references from the multipartStream to local list.
176     * Done only once per object creation.
177     *
178     * @throws AxisFault
179     */

180    private void mergeinAttachments() throws AxisFault
181    {
182
183       if (mpartStream != null)
184       {
185          Collection JavaDoc atts = mpartStream.getAttachments();
186
187          if (contentLocation == null)
188             contentLocation = mpartStream.getContentLocation();
189
190          mpartStream = null;
191
192          setAttachmentParts(atts);
193       }
194    }
195
196    /**
197     * This method uses getAttacmentByReference() to look for attachment.
198     * If attachment has been found, it will be removed from the list, and
199     * returned to the user.
200     *
201     * @param reference The reference that referers to an attachment.
202     * @return The part associated with the removed attachment, or null.
203     * @throws org.jboss.axis.AxisFault
204     */

205    public Part removeAttachmentPart(String JavaDoc reference)
206            throws org.jboss.axis.AxisFault
207    {
208
209       multipart = null;
210
211       dimemultipart = null;
212
213       mergeinAttachments();
214
215       Part removedPart = getAttachmentByReference(reference);
216
217       if (removedPart != null)
218       {
219          attachments.remove(removedPart.getContentId());
220          attachments.remove(removedPart.getContentLocation());
221          orderedAttachments.remove(removedPart);
222       }
223
224       return removedPart;
225    }
226
227    /**
228     * Adds an existing attachment to this list.
229     * Note: Passed part will be bound to this message.
230     *
231     * @param newPart new part to add
232     * @return Part old attachment with the same Content-ID, or null.
233     * @throws org.jboss.axis.AxisFault
234     */

235    public Part addAttachmentPart(Part newPart)
236            throws org.jboss.axis.AxisFault
237    {
238
239
240       multipart = null;
241       dimemultipart = null;
242
243       mergeinAttachments();
244
245       Part oldPart = (Part)attachments.put(newPart.getContentId(), newPart);
246
247       if (oldPart != null)
248       {
249          orderedAttachments.remove(oldPart);
250          attachments.remove(oldPart.getContentLocation());
251       }
252
253       orderedAttachments.add(newPart);
254
255       if (newPart.getContentLocation() != null)
256       {
257          attachments.put(newPart.getContentLocation(), newPart);
258       }
259
260       return oldPart;
261    }
262
263    public Part createAttachmentPart(Object JavaDoc datahandler)
264            throws org.jboss.axis.AxisFault
265    {
266
267       // Searching for the same attachements
268
Integer JavaDoc key = new Integer JavaDoc(datahandler.hashCode());
269       if (stackDataHandler.containsKey(key))
270       {
271          return (Part)stackDataHandler.get(key);
272       }
273
274       multipart = null;
275
276       dimemultipart = null;
277
278       mergeinAttachments();
279
280       if (!(datahandler instanceof javax.activation.DataHandler JavaDoc))
281       {
282          throw new org.jboss.axis.AxisFault(Messages.getMessage("unsupportedAttach", datahandler.getClass().getName(),
283                  javax.activation.DataHandler JavaDoc.class.getName()));
284       }
285
286       Part ret =
287               new AttachmentPartImpl((javax.activation.DataHandler JavaDoc)datahandler);
288
289       addAttachmentPart(ret);
290
291       // Store the current DataHandler with its key
292
stackDataHandler.put(key, ret);
293
294       return ret;
295    }
296
297    /**
298     * Add the collection of parts.
299     *
300     * @param parts
301     * @throws org.jboss.axis.AxisFault
302     */

303    public void setAttachmentParts(java.util.Collection JavaDoc parts)
304            throws org.jboss.axis.AxisFault
305    {
306
307       removeAllAttachments();
308
309       if ((parts != null) && !parts.isEmpty())
310       {
311          for (java.util.Iterator JavaDoc i = parts.iterator(); i.hasNext();)
312          {
313             Object JavaDoc part = i.next();
314
315             if (null != part)
316             {
317                if (part instanceof Part)
318                   addAttachmentPart((Part)part);
319                else
320                   createAttachmentPart(part);
321             }
322          }
323       }
324    }
325
326    /**
327     * This method should look at a refernce and determine if it is a CID: or
328     * url to look for attachment.
329     * <br>
330     * Note: if Content-Id or Content-Location headers have changed by outside
331     * code, lookup will not return proper values. In order to change these
332     * values attachment should be removed, then added again.
333     *
334     * @param reference The reference in the xml that referers to an attachment.
335     * @return The part associated with the attachment.
336     * @throws org.jboss.axis.AxisFault
337     */

338    public Part getAttachmentByReference(String JavaDoc reference)
339            throws org.jboss.axis.AxisFault
340    {
341
342       if (null == reference)
343       {
344          return null;
345       }
346
347       reference = reference.trim();
348
349       if (0 == reference.length())
350       {
351          return null;
352       }
353
354       mergeinAttachments();
355
356       //This search will pickit up if its fully qualified location or if it's a content-id
357
// that is not prefixed by the cid.
358

359       Part ret = (Part)attachments.get(reference);
360       if (null != ret) return ret;
361
362
363       if (!reference.startsWith(Attachments.CIDprefix) && (null != contentLocation))
364       {
365          //Not a content-id check to see if its a relative location id.
366

367          String JavaDoc fqreference = contentLocation;
368
369          if (!fqreference.endsWith("/"))
370          {
371             fqreference += "/";
372          }
373
374          if (reference.startsWith("/"))
375          {
376             fqreference += reference.substring(1);
377          }
378          else
379          {
380             fqreference += reference;
381          }
382
383          // lets see if we can get it as Content-Location
384
ret = (AttachmentPartImpl)attachments.get(fqreference);
385       }
386
387       if (null == ret && reference.startsWith(Attachments.CIDprefix))
388       {
389          //This is a content-id lets see if we have it.
390
ret = (Part)attachments.get(reference.substring(4));
391       }
392
393       return ret;
394    }
395
396    /**
397     * This method will return all attachments as a collection.
398     *
399     * @return A collection of attachments.
400     * @throws org.jboss.axis.AxisFault
401     */

402    public java.util.Collection JavaDoc getAttachments()
403            throws org.jboss.axis.AxisFault
404    {
405
406       mergeinAttachments();
407
408       return new LinkedList JavaDoc(orderedAttachments);
409    }
410
411    /**
412     * From the complex stream return the root part.
413     * Today this is SOAP.
414     *
415     * @return the root <code>Part</code>
416     */

417    public Part getRootPart()
418    {
419       return soapPart;
420    }
421
422    public void setRootPart(Part newRoot)
423    {
424
425       try
426       {
427          this.soapPart = (MessagePart)newRoot;
428          multipart = null;
429          dimemultipart = null;
430       }
431       catch (ClassCastException JavaDoc e)
432       {
433          throw new ClassCastException JavaDoc(Messages.getMessage("onlySOAPParts"));
434       }
435    }
436
437    /**
438     * multipart , cached entries for the stream of attachment that are going to be sent.
439     */

440    javax.mail.internet.MimeMultipart JavaDoc multipart = null;
441    DimeMultiPart dimemultipart = null;
442
443    /**
444     * Get the content length of the stream.
445     *
446     * @return the content length of the stream
447     * @throws org.jboss.axis.AxisFault
448     */

449    public long getContentLength() throws org.jboss.axis.AxisFault
450    {
451
452       mergeinAttachments();
453
454       int sendtype = this.sendtype == SEND_TYPE_NOTSET ? SEND_TYPE_DEFAULT : this.sendtype;
455
456       try
457       {
458          if (sendtype == SEND_TYPE_MIME)
459             return org.jboss.axis.attachments.MimeUtils.getContentLength(multipart != null ? multipart : (multipart = org.jboss.axis.attachments.MimeUtils.createMP(soapPart.getAsString(), orderedAttachments)));
460          else if (sendtype == SEND_TYPE_DIME) return createDimeMessage().getTransmissionSize();
461       }
462       catch (Exception JavaDoc e)
463       {
464          throw AxisFault.makeFault(e);
465       }
466       return 0;
467    }
468
469    /**
470     * Creates the DIME message
471     *
472     * @return a DIME part
473     * @throws org.jboss.axis.AxisFault if the part could not be built
474     */

475    protected DimeMultiPart createDimeMessage() throws org.jboss.axis.AxisFault
476    {
477       int sendtype = this.sendtype == SEND_TYPE_NOTSET ? SEND_TYPE_DEFAULT : this.sendtype;
478       if (sendtype == SEND_TYPE_DIME)
479       {
480          if (dimemultipart == null)
481          {
482
483             dimemultipart = new DimeMultiPart();
484             dimemultipart.addBodyPart(new DimeBodyPart(soapPart.getAsBytes(), DimeTypeNameFormat.URI,
485                     "http://schemas.xmlsoap.org/soap/envelope/",
486                     "uuid:714C6C40-4531-442E-A498-3AC614200295"));
487
488             for (java.util.Iterator JavaDoc i = orderedAttachments.iterator();
489                  i.hasNext();)
490             {
491                AttachmentPartImpl part = (AttachmentPartImpl)i.next();
492                DataHandler JavaDoc dh = AttachmentUtils.
493                        getActivationDataHandler(part);
494                dimemultipart.addBodyPart(new
495                        DimeBodyPart(dh, part.getContentId()));
496             }
497          }
498       }
499       return dimemultipart;
500    }
501
502    /**
503     * Write the content to the stream.
504     *
505     * @param os
506     * @throws org.jboss.axis.AxisFault
507     */

508    public void writeContentToStream(java.io.OutputStream JavaDoc os)
509            throws org.jboss.axis.AxisFault
510    {
511       int sendtype = this.sendtype == SEND_TYPE_NOTSET ?
512               SEND_TYPE_DEFAULT : this.sendtype;
513       try
514       {
515
516          mergeinAttachments();
517          if (sendtype == SEND_TYPE_MIME)
518          {
519             org.jboss.axis.attachments.MimeUtils.writeToMultiPartStream(os,
520                     (multipart != null) ? multipart : (multipart =
521                     org.jboss.axis.attachments.MimeUtils.createMP(soapPart.getAsString(), orderedAttachments)));
522          }
523          else if (sendtype == SEND_TYPE_DIME) createDimeMessage().write(os);
524       }
525       catch (Exception JavaDoc e)
526       {
527          throw org.jboss.axis.AxisFault.makeFault(e);
528       }
529    }
530
531    /**
532     * Gets the content type for the whole stream.
533     *
534     * @return the content type for the whole stream
535     * @throws org.jboss.axis.AxisFault
536     */

537    public String JavaDoc getContentType() throws org.jboss.axis.AxisFault
538    {
539
540       mergeinAttachments();
541
542       int sendtype = this.sendtype == SEND_TYPE_NOTSET ? SEND_TYPE_DEFAULT :
543               this.sendtype;
544       if (sendtype == SEND_TYPE_MIME)
545          return org.jboss.axis.attachments.MimeUtils.getContentType((multipart
546                  != null)
547                  ? multipart
548                  : (multipart =
549                  org.jboss.axis.attachments.MimeUtils.createMP(soapPart.getAsString(),
550                          orderedAttachments)));
551       else
552          return org.jboss.axis.Message.MIME_APPLICATION_DIME;
553    }
554
555    /**
556     * This is the number of attachments.
557     *
558     * @return the number of attachments
559     */

560    public int getAttachmentCount()
561    {
562
563       try
564       {
565          mergeinAttachments();
566
567          // force a serialization of the message so that
568
// any attachments will be added
569
soapPart.getAsString();
570
571          return orderedAttachments.size();
572       }
573       catch (AxisFault e)
574       {
575          log.warn(Messages.getMessage("exception00"), e);
576       }
577
578       return 0;
579    }
580
581    /**
582     * Determine if an object is to be treated as an attchment.
583     *
584     * @param value the value that is to be determined if
585     * its an attachment.
586     * @return True if value should be treated as an attchment.
587     */

588    public boolean isAttachment(Object JavaDoc value)
589    {
590       return AttachmentUtils.isAttachment(value);
591    }
592
593    /**
594     * Removes all <CODE>AttachmentPart</CODE> objects that have
595     * been added to this <CODE>SOAPMessage</CODE> object.
596     * <p/>
597     * <P>This method does not touch the SOAP part.</P>
598     */

599    public void removeAllAttachments()
600    {
601       try
602       {
603          multipart = null;
604          dimemultipart = null;
605          mergeinAttachments();
606          attachments.clear();
607          orderedAttachments.clear();
608          stackDataHandler.clear();
609       }
610       catch (AxisFault af)
611       {
612          log.warn(Messages.getMessage("exception00"), af);
613       }
614    }
615
616    /**
617     * Retrieves all the <CODE>AttachmentPart</CODE> objects
618     * that have header entries that match the specified headers.
619     * Note that a returned attachment could have headers in
620     * addition to those specified.
621     *
622     * @param headers a <CODE>MimeHeaders</CODE>
623     * object containing the MIME headers for which to
624     * search
625     * @return an iterator over all attachments that have a header
626     * that matches one of the given headers
627     */

628    public java.util.Iterator JavaDoc getAttachments(javax.xml.soap.MimeHeaders JavaDoc headers)
629    {
630       java.util.Vector JavaDoc vecParts = new java.util.Vector JavaDoc();
631       java.util.Iterator JavaDoc iterator = GetAttachmentsIterator();
632       while (iterator.hasNext())
633       {
634          Part part = (Part)iterator.next();
635          if (part instanceof AttachmentPartImpl)
636          {
637             if (((AttachmentPartImpl)part).matches(headers))
638             {
639                vecParts.add(part);
640             }
641          }
642       }
643       return vecParts.iterator();
644    }
645
646    /**
647     * get an iterator over all attachments. This
648     *
649     * @return iterator of Part Objects; some of which may be
650     * AttachmentPart instances
651     * @see org.jboss.axis.Part
652     * @see AttachmentPartImpl
653     */

654    private java.util.Iterator JavaDoc GetAttachmentsIterator()
655    {
656       java.util.Iterator JavaDoc iterator = attachments.values().iterator();
657       return iterator;
658    }
659
660    /**
661     * Create a new attachment Part in this Message.
662     * Will actually, and always, return an AttachmentPart.
663     *
664     * @return a new attachment Part
665     * @throws org.jboss.axis.AxisFault
666     */

667    public Part createAttachmentPart() throws org.jboss.axis.AxisFault
668    {
669       return new AttachmentPartImpl();
670    }
671
672    public void setSendType(int sendtype)
673    {
674       if (sendtype < 1)
675          throw new IllegalArgumentException JavaDoc("");
676       if (sendtype > SEND_TYPE_MAX)
677          throw new IllegalArgumentException JavaDoc("");
678       this.sendtype = sendtype;
679    }
680
681    public int getSendType()
682    {
683       return sendtype;
684    }
685
686    /**
687     * dispose of the attachments and their files; do not use the object
688     * after making this call.
689     */

690
691    public void dispose()
692    {
693       java.util.Iterator JavaDoc iterator = GetAttachmentsIterator();
694       while (iterator.hasNext())
695       {
696          Part part = (Part)iterator.next();
697          if (part instanceof AttachmentPartImpl)
698          {
699             AttachmentPartImpl apart = (AttachmentPartImpl)part;
700             apart.dispose();
701          }
702       }
703
704    }
705
706    // consider type-safe e-num here?
707
/**
708     * Determine how an object typically sent as attachments are to
709     * be represented. Currently, MIME DIME and NONE are reccognised.
710     *
711     * @param value a String representing a sending type, treated in a
712     * case-insensetive manner
713     * @return an <code>int</code> send type code
714     */

715    public static int getSendType(String JavaDoc value)
716    {
717       if (value.equalsIgnoreCase("MIME")) return SEND_TYPE_MIME;
718       if (value.equalsIgnoreCase("DIME")) return SEND_TYPE_DIME;
719       if (value.equalsIgnoreCase("NONE")) return SEND_TYPE_NONE;
720       return SEND_TYPE_NOTSET;
721    }
722
723    /**
724     * For a given sendType value, return a string representation.
725     *
726     * @param value a type code integer
727     * @return a <code>String</code> representation of <code>value</code>
728     */

729    public static String JavaDoc getSendTypeString(int value)
730    {
731       if (value == SEND_TYPE_MIME)
732       {
733          return "MIME";
734       }
735       if (value == SEND_TYPE_DIME)
736       {
737          return "DIME";
738       }
739       if (value == SEND_TYPE_NONE)
740       {
741          return "NONE";
742       }
743       return null;
744    }
745 }
Popular Tags