1 /*
2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.xml.internal.messaging.saaj.soap;
27 
28 import java.io.*;
29 import java.util.*;
30 import java.util.logging.Level;
31 import java.util.logging.Logger;
32 
33 import javax.activation.DataHandler;
34 import javax.activation.DataSource;
35 import javax.xml.soap.*;
36 import javax.xml.transform.Source;
37 import javax.xml.transform.stream.StreamSource;
38 
39 import com.sun.xml.internal.messaging.saaj.packaging.mime.Header;
40 import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.*;
41 import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*;
42 import com.sun.xml.internal.messaging.saaj.packaging.mime.MessagingException;
43 
44 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
45 import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl;
46 import com.sun.xml.internal.messaging.saaj.util.*;
47 import com.sun.xml.internal.org.jvnet.mimepull.MIMEPart;
48 
49 /**
50  * The message implementation for SOAP messages with
51  * attachments. Messages for specific profiles will likely extend this
52  * MessageImpl class and add more value for that particular profile.
53  *
54  * @author Anil Vijendran (akv@eng.sun.com)
55  * @author Rajiv Mordani (rajiv.mordani@sun.com)
56  * @author Manveen Kaur (manveen.kaur@sun.com)
57  */
58 
59 public abstract class MessageImpl
60     extends SOAPMessage
61     implements SOAPConstants {
62 
63 
64     public static final String CONTENT_ID             = "Content-ID";
65     public static final String CONTENT_LOCATION       = "Content-Location";
66 
67     protected static final Logger log =
68         Logger.getLogger(LogDomainConstants.SOAP_DOMAIN,
69                          "com.sun.xml.internal.messaging.saaj.soap.LocalStrings");
70 
71     protected static final int PLAIN_XML_FLAG      = 1;      // 00001
72     protected static final int MIME_MULTIPART_FLAG = 2;      // 00010
73     protected static final int SOAP1_1_FLAG = 4;             // 00100
74     protected static final int SOAP1_2_FLAG = 8;             // 01000
75     //protected static final int MIME_MULTIPART_XOP_FLAG = 14; // 01110
76     protected static final int MIME_MULTIPART_XOP_SOAP1_1_FLAG = 6;  // 00110
77     protected static final int MIME_MULTIPART_XOP_SOAP1_2_FLAG = 10; // 01010
78     protected static final int XOP_FLAG = 13;                // 01101
79     protected static final int FI_ENCODED_FLAG     = 16;     // 10000
80 
81     protected MimeHeaders headers;
82     protected ContentType contentType;
83     protected SOAPPartImpl soapPartImpl;
84     protected FinalArrayList attachments;
85     protected boolean saved = false;
86     protected byte[] messageBytes;
87     protected int messageByteCount;
88     protected HashMap properties = new HashMap();
89 
90     // used for lazy attachment initialization
91     protected MimeMultipart multiPart = null;
92     protected boolean attachmentsInitialized = false;
93 
94     /**
95      * True if this part is encoded using Fast Infoset.
96      * MIME -> application/fastinfoset
97      */
98     protected boolean isFastInfoset = false;
99 
100     /**
101      * True if the Accept header of this message includes
102      * application/fastinfoset
103      */
104     protected boolean acceptFastInfoset = false;
105 
106     protected MimeMultipart mmp = null;
107 
108     // if attachments are present, don't read the entire message in byte stream in saveTo()
109     private boolean optimizeAttachmentProcessing = true;
110 
111     private InputStream inputStreamAfterSaveChanges = null;
112 
113     // switch back to old MimeMultipart incase of problem
114     private static boolean switchOffBM = false;
115     private static boolean switchOffLazyAttachment = false;
116     private static boolean useMimePull = false;
117 
118     static {
119             String s = SAAJUtil.getSystemProperty("saaj.mime.optimization");
120             if ((s != null) && s.equals("false")) {
121                 switchOffBM = true;
122             }
123             s = SAAJUtil.getSystemProperty("saaj.lazy.mime.optimization");
124             if ((s != null) && s.equals("false")) {
125                 switchOffLazyAttachment = true;
126             }
127             useMimePull = SAAJUtil.getSystemBoolean("saaj.use.mimepull");
128 
129     }
130 
131     //property to indicate optimized serialization for lazy attachments
132     private boolean lazyAttachments = false;
133 
134     // most of the times, Content-Types are already all lower cased.
135     // String.toLowerCase() works faster in this case, so even if you
136     // are only doing one comparison, it pays off to use String.toLowerCase()
137     // than String.equalsIgnoreCase(). When you do more than one comparison,
138     // the benefits of String.toLowerCase() dominates.
139     //
140     //
141     // for FI,
142     //   use application/fastinfoset for SOAP 1.1
143     //   use application/soap+fastinfoset for SOAP 1.2
144     // to speed up comparisons, test methods always use lower cases.
145 
146     /**
147      * @param primary
148      *      must be all lower case
149      * @param sub
150      *      must be all lower case
151      */
isSoap1_1Type(String primary, String sub)152     private static boolean isSoap1_1Type(String primary, String sub) {
153         return primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml")
154             || primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml-soap")
155             || primary.equals("application")
156                && sub.equals("fastinfoset");
157     }
158 
159     /**
160      * @param type
161      *      must be all lower case
162      */
isEqualToSoap1_1Type(String type)163     private static boolean isEqualToSoap1_1Type(String type) {
164         return type.startsWith("text/xml") ||
165                type.startsWith("application/fastinfoset");
166     }
167 
168     /**
169      * @param primary
170      *      must be all lower case
171      * @param sub
172      *      must be all lower case
173      */
isSoap1_2Type(String primary, String sub)174     private static boolean isSoap1_2Type(String primary, String sub) {
175         return primary.equals("application")
176                && (sub.equals("soap+xml")
177                    || sub.equals("soap+fastinfoset"));
178     }
179 
180     /**
181      * @param type
182      *      must be all lower case
183      */
isEqualToSoap1_2Type(String type)184     private static boolean isEqualToSoap1_2Type(String type) {
185         return type.startsWith("application/soap+xml") ||
186                type.startsWith("application/soap+fastinfoset");
187     }
188 
189     /**
190       * Construct a new message. This will be invoked before message
191       * sends.
192       */
MessageImpl()193     protected MessageImpl() {
194         this(false, false);
195         attachmentsInitialized = true;
196     }
197 
198     /**
199       * Construct a new message. This will be invoked before message
200       * sends.
201       */
MessageImpl(boolean isFastInfoset, boolean acceptFastInfoset)202     protected MessageImpl(boolean isFastInfoset, boolean acceptFastInfoset) {
203         this.isFastInfoset = isFastInfoset;
204         this.acceptFastInfoset = acceptFastInfoset;
205 
206         headers = new MimeHeaders();
207         headers.setHeader("Accept", getExpectedAcceptHeader());
208         contentType = new ContentType();
209     }
210 
211     /**
212      * Shallow copy.
213      */
MessageImpl(SOAPMessage msg)214     protected MessageImpl(SOAPMessage msg) {
215         if (!(msg instanceof MessageImpl)) {
216             // don't know how to handle this.
217         }
218         MessageImpl src = (MessageImpl) msg;
219         this.headers = src.headers;
220         this.soapPartImpl = src.soapPartImpl;
221         this.attachments = src.attachments;
222         this.saved = src.saved;
223         this.messageBytes = src.messageBytes;
224         this.messageByteCount = src.messageByteCount;
225         this.properties = src.properties;
226         this.contentType = src.contentType;
227     }
228 
229     /**
230      * @param stat
231      *      the mask value obtained from {@link #identifyContentType(ContentType)}
232      */
isSoap1_1Content(int stat)233     protected static boolean isSoap1_1Content(int stat) {
234         return (stat & SOAP1_1_FLAG) != 0;
235     }
236 
237     /**
238      * @param stat
239      *      the mask value obtained from {@link #identifyContentType(ContentType)}
240      */
isSoap1_2Content(int stat)241     protected static boolean isSoap1_2Content(int stat) {
242         return (stat & SOAP1_2_FLAG) != 0;
243     }
244 
isMimeMultipartXOPSoap1_2Package(ContentType contentType)245      private static boolean isMimeMultipartXOPSoap1_2Package(ContentType contentType) {
246         String type = contentType.getParameter("type");
247         if (type == null) {
248             return false;
249         }
250         type = type.toLowerCase();
251         if (!type.startsWith("application/xop+xml")) {
252             return false;
253         }
254         String startinfo = contentType.getParameter("start-info");
255         if (startinfo == null) {
256             return false;
257         }
258         startinfo = startinfo.toLowerCase();
259         return isEqualToSoap1_2Type(startinfo);
260     }
261 
262 
263      //private static boolean isMimeMultipartXOPPackage(ContentType contentType) {
isMimeMultipartXOPSoap1_1Package(ContentType contentType)264      private static boolean isMimeMultipartXOPSoap1_1Package(ContentType contentType) {
265         String type = contentType.getParameter("type");
266         if(type==null)
267             return false;
268 
269         type = type.toLowerCase();
270         if(!type.startsWith("application/xop+xml"))
271             return false;
272 
273         String startinfo = contentType.getParameter("start-info");
274         if(startinfo == null)
275             return false;
276         startinfo = startinfo.toLowerCase();
277         return isEqualToSoap1_1Type(startinfo);
278     }
279 
isSOAPBodyXOPPackage(ContentType contentType)280     private static boolean isSOAPBodyXOPPackage(ContentType contentType){
281         String primary = contentType.getPrimaryType();
282         String sub = contentType.getSubType();
283 
284         if (primary.equalsIgnoreCase("application")) {
285             if (sub.equalsIgnoreCase("xop+xml")) {
286                 String type = getTypeParameter(contentType);
287                 return isEqualToSoap1_2Type(type) || isEqualToSoap1_1Type(type);
288             }
289         }
290         return false;
291     }
292 
293     /**
294      * Construct a message from an input stream. When messages are
295      * received, there's two parts -- the transport headers and the
296      * message content in a transport specific stream.
297      */
MessageImpl(MimeHeaders headers, final InputStream in)298     protected MessageImpl(MimeHeaders headers, final InputStream in)
299         throws SOAPExceptionImpl {
300         contentType = parseContentType(headers);
301         init(headers,identifyContentType(contentType),contentType,in);
302     }
303 
parseContentType(MimeHeaders headers)304     private static ContentType parseContentType(MimeHeaders headers) throws SOAPExceptionImpl {
305         final String ct;
306         if (headers != null)
307             ct = getContentType(headers);
308         else {
309             log.severe("SAAJ0550.soap.null.headers");
310             throw new SOAPExceptionImpl("Cannot create message: " +
311                                         "Headers can't be null");
312         }
313 
314         if (ct == null) {
315             log.severe("SAAJ0532.soap.no.Content-Type");
316             throw new SOAPExceptionImpl("Absent Content-Type");
317         }
318         try {
319             return new ContentType(ct);
320         } catch (Throwable ex) {
321             log.severe("SAAJ0535.soap.cannot.internalize.message");
322             throw new SOAPExceptionImpl("Unable to internalize message", ex);
323         }
324     }
325 
326     /**
327      * Construct a message from an input stream. When messages are
328      * received, there's two parts -- the transport headers and the
329      * message content in a transport specific stream.
330      *
331      * @param contentType
332      *      The parsed content type header from the headers variable.
333      *      This is redundant parameter, but it avoids reparsing this header again.
334      * @param stat
335      *      The result of {@link #identifyContentType(ContentType)} over
336      *      the contentType parameter. This redundant parameter, but it avoids
337      *      recomputing this information again.
338      */
MessageImpl(MimeHeaders headers, final ContentType contentType, int stat, final InputStream in)339     protected MessageImpl(MimeHeaders headers, final ContentType contentType, int stat, final InputStream in) throws SOAPExceptionImpl {
340         init(headers, stat, contentType, in);
341 
342     }
343 
init(MimeHeaders headers, int stat, final ContentType contentType, final InputStream in)344     private void init(MimeHeaders headers, int stat, final ContentType contentType, final InputStream in) throws SOAPExceptionImpl {
345         this.headers = headers;
346 
347         try {
348 
349             // Set isFastInfoset/acceptFastInfoset flag based on MIME type
350             if ((stat & FI_ENCODED_FLAG) > 0) {
351                 isFastInfoset = acceptFastInfoset = true;
352             }
353 
354             // If necessary, inspect Accept header to set acceptFastInfoset
355             if (!isFastInfoset) {
356                 String[] values = headers.getHeader("Accept");
357                 if (values != null) {
358                     for (int i = 0; i < values.length; i++) {
359                         StringTokenizer st = new StringTokenizer(values[i], ",");
360                         while (st.hasMoreTokens()) {
361                             final String token = st.nextToken().trim();
362                             if (token.equalsIgnoreCase("application/fastinfoset") ||
363                                 token.equalsIgnoreCase("application/soap+fastinfoset")) {
364                                 acceptFastInfoset = true;
365                                 break;
366                             }
367                         }
368                     }
369                 }
370             }
371 
372             if (!isCorrectSoapVersion(stat)) {
373                 log.log(
374                     Level.SEVERE,
375                     "SAAJ0533.soap.incorrect.Content-Type",
376                     new String[] {
377                         contentType.toString(),
378                         getExpectedContentType()});
379                 throw new SOAPVersionMismatchException(
380                     "Cannot create message: incorrect content-type for SOAP version. Got: "
381                         + contentType
382                         + " Expected: "
383                         + getExpectedContentType());
384             }
385 
386             if ((stat & PLAIN_XML_FLAG) != 0) {
387                 if (isFastInfoset) {
388                     getSOAPPart().setContent(
389                         FastInfosetReflection.FastInfosetSource_new(in));
390                 } else {
391                     initCharsetProperty(contentType);
392                     getSOAPPart().setContent(new StreamSource(in));
393                 }
394             }
395             else if ((stat & MIME_MULTIPART_FLAG) != 0) {
396                 DataSource ds = new DataSource() {
397                     public InputStream getInputStream() {
398                         return in;
399                     }
400 
401                     public OutputStream getOutputStream() {
402                         return null;
403                     }
404 
405                     public String getContentType() {
406                         return contentType.toString();
407                     }
408 
409                     public String getName() {
410                         return "";
411                     }
412                 };
413 
414                 multiPart = null;
415                 if (useMimePull) {
416                     multiPart = new MimePullMultipart(ds,contentType);
417                 } else if (switchOffBM) {
418                     multiPart = new MimeMultipart(ds,contentType);
419                 } else {
420                     multiPart = new BMMimeMultipart(ds,contentType);
421                 }
422 
423                 String startParam = contentType.getParameter("start");
424                 MimeBodyPart soapMessagePart = null;
425                 InputStream soapPartInputStream = null;
426                 String contentID = null;
427                 String contentIDNoAngle = null;
428                 if (switchOffBM || switchOffLazyAttachment) {
429                     if(startParam == null) {
430                         soapMessagePart = multiPart.getBodyPart(0);
431                         for (int i = 1; i < multiPart.getCount(); i++) {
432                             initializeAttachment(multiPart, i);
433                         }
434                     } else {
435                         soapMessagePart = multiPart.getBodyPart(startParam);
436                         for (int i = 0; i < multiPart.getCount(); i++) {
437                             contentID = multiPart.getBodyPart(i).getContentID();
438                             // Old versions of AXIS2 put angle brackets around the content
439                             // id but not the start param
440                             contentIDNoAngle = (contentID != null) ?
441                                 contentID.replaceFirst("^<", "").replaceFirst(">$", "") : null;
442                             if(!startParam.equals(contentID) && !startParam.equals(contentIDNoAngle))
443                                 initializeAttachment(multiPart, i);
444                         }
445                     }
446                 } else {
447                     if (useMimePull) {
448                         MimePullMultipart mpMultipart = (MimePullMultipart)multiPart;
449                         MIMEPart sp = mpMultipart.readAndReturnSOAPPart();
450                         soapMessagePart = new MimeBodyPart(sp);
451                         soapPartInputStream = sp.readOnce();
452                     } else {
453                         BMMimeMultipart bmMultipart =
454                                 (BMMimeMultipart) multiPart;
455                         InputStream stream = bmMultipart.initStream();
456 
457                         SharedInputStream sin = null;
458                         if (stream instanceof SharedInputStream) {
459                             sin = (SharedInputStream) stream;
460                         }
461 
462                         String boundary = "--" +
463                                 contentType.getParameter("boundary");
464                         byte[] bndbytes = ASCIIUtility.getBytes(boundary);
465                         if (startParam == null) {
466                             soapMessagePart =
467                                     bmMultipart.getNextPart(stream, bndbytes, sin);
468                             bmMultipart.removeBodyPart(soapMessagePart);
469                         } else {
470                             MimeBodyPart bp = null;
471                             try {
472                                while (!startParam.equals(contentID) && !startParam.equals(contentIDNoAngle)) {
473                                     bp = bmMultipart.getNextPart(
474                                             stream, bndbytes, sin);
475                                     contentID = bp.getContentID();
476                                     // Old versions of AXIS2 put angle brackets around the content
477                                     // id but not the start param
478                                     contentIDNoAngle = (contentID != null) ?
479                                         contentID.replaceFirst("^<", "").replaceFirst(">$", "") : null;
480                                 }
481                                 soapMessagePart = bp;
482                                 bmMultipart.removeBodyPart(bp);
483                             } catch (Exception e) {
484                                 throw new SOAPExceptionImpl(e);
485                             }
486                         }
487                     }
488                 }
489 
490                 if (soapPartInputStream == null && soapMessagePart != null) {
491                     soapPartInputStream = soapMessagePart.getInputStream();
492                 }
493 
494                 ContentType soapPartCType = new ContentType(
495                                             soapMessagePart.getContentType());
496                 initCharsetProperty(soapPartCType);
497                 String baseType = soapPartCType.getBaseType().toLowerCase();
498                 if(!(isEqualToSoap1_1Type(baseType)
499                   || isEqualToSoap1_2Type(baseType)
500                   || isSOAPBodyXOPPackage(soapPartCType))) {
501                     log.log(Level.SEVERE,
502                             "SAAJ0549.soap.part.invalid.Content-Type",
503                             new Object[] {baseType});
504                     throw new SOAPExceptionImpl(
505                             "Bad Content-Type for SOAP Part : " +
506                             baseType);
507                 }
508 
509                 SOAPPart soapPart = getSOAPPart();
510                 setMimeHeaders(soapPart, soapMessagePart);
511                 soapPart.setContent(isFastInfoset ?
512                      (Source) FastInfosetReflection.FastInfosetSource_new(
513                          soapPartInputStream) :
514                      (Source) new StreamSource(soapPartInputStream));
515             } else {
516                 log.severe("SAAJ0534.soap.unknown.Content-Type");
517                 throw new SOAPExceptionImpl("Unrecognized Content-Type");
518             }
519         } catch (Throwable ex) {
520             log.severe("SAAJ0535.soap.cannot.internalize.message");
521             throw new SOAPExceptionImpl("Unable to internalize message", ex);
522         }
523         needsSave();
524     }
525 
isFastInfoset()526     public boolean isFastInfoset() {
527         return isFastInfoset;
528     }
529 
acceptFastInfoset()530     public boolean acceptFastInfoset() {
531         return acceptFastInfoset;
532     }
533 
setIsFastInfoset(boolean value)534     public void setIsFastInfoset(boolean value) {
535         if (value != isFastInfoset) {
536             isFastInfoset = value;
537             if (isFastInfoset) {
538                 acceptFastInfoset = true;
539             }
540             saved = false;      // ensure transcoding if necessary
541         }
542     }
543 
getProperty(String property)544     public Object getProperty(String property) {
545         return (String) properties.get(property);
546     }
547 
setProperty(String property, Object value)548     public void setProperty(String property, Object value) {
549         verify(property, value);
550         properties.put(property, value);
551     }
552 
verify(String property, Object value)553     private void verify(String property, Object value) {
554         if (property.equalsIgnoreCase(SOAPMessage.WRITE_XML_DECLARATION)) {
555             if (!("true".equals(value) || "false".equals(value)))
556                 throw new RuntimeException(
557                     property + " must have value false or true");
558 
559             try {
560                 EnvelopeImpl env = (EnvelopeImpl) getSOAPPart().getEnvelope();
561                 if ("true".equalsIgnoreCase((String)value)) {
562                     env.setOmitXmlDecl("no");
563                 } else if ("false".equalsIgnoreCase((String)value)) {
564                     env.setOmitXmlDecl("yes");
565                 }
566             } catch (Exception e) {
567                 log.log(Level.SEVERE, "SAAJ0591.soap.exception.in.set.property",
568                     new Object[] {e.getMessage(), "javax.xml.soap.write-xml-declaration"});
569                 throw new RuntimeException(e);
570             }
571             return;
572         }
573 
574         if (property.equalsIgnoreCase(SOAPMessage.CHARACTER_SET_ENCODING)) {
575             try {
576                 ((EnvelopeImpl) getSOAPPart().getEnvelope()).setCharsetEncoding((String)value);
577             } catch (Exception e) {
578                 log.log(Level.SEVERE, "SAAJ0591.soap.exception.in.set.property",
579                     new Object[] {e.getMessage(), "javax.xml.soap.character-set-encoding"});
580                 throw new RuntimeException(e);
581             }
582         }
583     }
584 
isCorrectSoapVersion(int contentTypeId)585     protected abstract boolean isCorrectSoapVersion(int contentTypeId);
586 
getExpectedContentType()587     protected abstract String getExpectedContentType();
getExpectedAcceptHeader()588     protected abstract String getExpectedAcceptHeader();
589 
590     /**
591      * Sniffs the Content-Type header so that we can determine how to process.
592      *
593      * <p>
594      * In the absence of type attribute we assume it to be text/xml.
595      * That would mean we're easy on accepting the message and
596      * generate the correct thing (as the SWA spec also specifies
597      * that the type parameter should always be text/xml)
598      *
599      * @return
600      *      combination of flags, such as PLAIN_XML_CODE and MIME_MULTIPART_CODE.
601      */
602     // SOAP1.2 allow SOAP1.2 content type
identifyContentType(ContentType ct)603     static int identifyContentType(ContentType ct)
604         throws SOAPExceptionImpl {
605         // TBD
606         //    Is there anything else we need to verify here?
607 
608         String primary = ct.getPrimaryType().toLowerCase();
609         String sub = ct.getSubType().toLowerCase();
610 
611         if (primary.equals("multipart")) {
612             if (sub.equals("related")) {
613                 String type = getTypeParameter(ct);
614                 if (isEqualToSoap1_1Type(type)) {
615                     return (type.equals("application/fastinfoset") ?
616                            FI_ENCODED_FLAG : 0) | MIME_MULTIPART_FLAG | SOAP1_1_FLAG;
617                 }
618                 else if (isEqualToSoap1_2Type(type)) {
619                     return (type.equals("application/soap+fastinfoset") ?
620                            FI_ENCODED_FLAG : 0) | MIME_MULTIPART_FLAG | SOAP1_2_FLAG;
621                 /*} else if (isMimeMultipartXOPPackage(ct)) {
622                     return MIME_MULTIPART_XOP_FLAG;*/
623                 } else if (isMimeMultipartXOPSoap1_1Package(ct)) {
624                     return MIME_MULTIPART_XOP_SOAP1_1_FLAG;
625                 } else if (isMimeMultipartXOPSoap1_2Package(ct)) {
626                     return MIME_MULTIPART_XOP_SOAP1_2_FLAG;
627                 } else {
628                     log.severe("SAAJ0536.soap.content-type.mustbe.multipart");
629                     throw new SOAPExceptionImpl(
630                         "Content-Type needs to be Multipart/Related "
631                             + "and with \"type=text/xml\" "
632                             + "or \"type=application/soap+xml\"");
633                 }
634             } else {
635                 log.severe("SAAJ0537.soap.invalid.content-type");
636                 throw new SOAPExceptionImpl(
637                     "Invalid Content-Type: " + primary + '/' + sub);
638             }
639         }
640         else if (isSoap1_1Type(primary, sub)) {
641             return (primary.equalsIgnoreCase("application")
642                     && sub.equalsIgnoreCase("fastinfoset") ?
643                         FI_ENCODED_FLAG : 0)
644                    | PLAIN_XML_FLAG | SOAP1_1_FLAG;
645         }
646         else if (isSoap1_2Type(primary, sub)) {
647             return (primary.equalsIgnoreCase("application")
648                     && sub.equalsIgnoreCase("soap+fastinfoset") ?
649                         FI_ENCODED_FLAG : 0)
650                    | PLAIN_XML_FLAG | SOAP1_2_FLAG;
651         } else if(isSOAPBodyXOPPackage(ct)){
652             return XOP_FLAG;
653         } else {
654             log.severe("SAAJ0537.soap.invalid.content-type");
655             throw new SOAPExceptionImpl(
656                 "Invalid Content-Type:"
657                     + primary
658                     + '/'
659                     + sub
660                     + ". Is this an error message instead of a SOAP response?");
661         }
662     }
663 
664     /**
665      * Obtains the type parameter of the Content-Type header. Defaults to "text/xml".
666      */
getTypeParameter(ContentType contentType)667     private static String getTypeParameter(ContentType contentType) {
668         String p = contentType.getParameter("type");
669         if(p!=null)
670             return p.toLowerCase();
671         else
672             return "text/xml";
673     }
674 
getMimeHeaders()675     public MimeHeaders getMimeHeaders() {
676         return this.headers;
677     }
678 
getContentType(MimeHeaders headers)679     final static String getContentType(MimeHeaders headers) {
680         String[] values = headers.getHeader("Content-Type");
681         if (values == null)
682             return null;
683         else
684             return values[0];
685     }
686 
687     /*
688      * Get the complete ContentType value along with optional parameters.
689      */
getContentType()690     public String getContentType() {
691         return getContentType(this.headers);
692     }
693 
setContentType(String type)694     public void setContentType(String type) {
695         headers.setHeader("Content-Type", type);
696         needsSave();
697     }
698 
contentType()699     private ContentType contentType() {
700         ContentType ct = null;
701         try {
702             String currentContent = getContentType();
703             if (currentContent == null) {
704                 return this.contentType;
705             }
706             ct = new ContentType(currentContent);
707         } catch (Exception e) {
708             // what to do here?
709         }
710         return ct;
711     }
712 
713     /*
714      * Return the MIME type string, without the parameters.
715      */
getBaseType()716     public String getBaseType() {
717         return contentType().getBaseType();
718     }
719 
setBaseType(String type)720     public void setBaseType(String type) {
721         ContentType ct = contentType();
722         ct.setParameter("type", type);
723         headers.setHeader("Content-Type", ct.toString());
724         needsSave();
725     }
726 
getAction()727     public String getAction() {
728         return contentType().getParameter("action");
729     }
730 
setAction(String action)731     public void setAction(String action) {
732         ContentType ct = contentType();
733         ct.setParameter("action", action);
734         headers.setHeader("Content-Type", ct.toString());
735         needsSave();
736     }
737 
getCharset()738     public String getCharset() {
739         return contentType().getParameter("charset");
740     }
741 
setCharset(String charset)742     public void setCharset(String charset) {
743         ContentType ct = contentType();
744         ct.setParameter("charset", charset);
745         headers.setHeader("Content-Type", ct.toString());
746         needsSave();
747     }
748 
749     /**
750      * All write methods (i.e setters) should call this method in
751      * order to make sure that a save is necessary since the state
752      * has been modified.
753      */
needsSave()754     private final void needsSave() {
755         saved = false;
756     }
757 
saveRequired()758     public  boolean saveRequired() {
759         return saved != true;
760     }
761 
getContentDescription()762     public String getContentDescription() {
763         String[] values = headers.getHeader("Content-Description");
764         if (values != null && values.length > 0)
765             return values[0];
766         return null;
767     }
768 
setContentDescription(String description)769     public void setContentDescription(String description) {
770         headers.setHeader("Content-Description", description);
771         needsSave();
772     }
773 
getSOAPPart()774     public abstract SOAPPart getSOAPPart();
775 
removeAllAttachments()776     public void removeAllAttachments() {
777         try {
778             initializeAllAttachments();
779         } catch (Exception e) {
780             throw new RuntimeException(e);
781         }
782 
783         if (attachments != null) {
784             attachments.clear();
785             needsSave();
786         }
787     }
788 
countAttachments()789     public int countAttachments() {
790         try {
791             initializeAllAttachments();
792         } catch (Exception e) {
793             throw new RuntimeException(e);
794         }
795         if (attachments != null)
796             return attachments.size();
797         return 0;
798     }
799 
addAttachmentPart(AttachmentPart attachment)800     public void addAttachmentPart(AttachmentPart attachment) {
801         try {
802             initializeAllAttachments();
803             this.optimizeAttachmentProcessing = true;
804         } catch (Exception e) {
805             throw new RuntimeException(e);
806         }
807         if (attachments == null)
808             attachments = new FinalArrayList();
809 
810         attachments.add(attachment);
811 
812         needsSave();
813     }
814 
815     static private final Iterator nullIter = Collections.EMPTY_LIST.iterator();
816 
getAttachments()817     public Iterator getAttachments() {
818         try {
819             initializeAllAttachments();
820         } catch (Exception e) {
821             throw new RuntimeException(e);
822         }
823         if (attachments == null)
824             return nullIter;
825         return attachments.iterator();
826     }
827 
setFinalContentType(String charset)828     private void setFinalContentType(String charset) {
829         ContentType ct = contentType();
830         if (ct == null) {
831             ct = new ContentType();
832         }
833         String[] split = getExpectedContentType().split("/");
834         ct.setPrimaryType(split[0]);
835         ct.setSubType(split[1]);
836         ct.setParameter("charset", charset);
837         headers.setHeader("Content-Type", ct.toString());
838     }
839 
840     private class MimeMatchingIterator implements Iterator {
MimeMatchingIterator(MimeHeaders headers)841         public MimeMatchingIterator(MimeHeaders headers) {
842             this.headers = headers;
843             this.iter = attachments.iterator();
844         }
845 
846         private Iterator iter;
847         private MimeHeaders headers;
848         private Object nextAttachment;
849 
hasNext()850         public boolean hasNext() {
851             if (nextAttachment == null)
852                 nextAttachment = nextMatch();
853             return nextAttachment != null;
854         }
855 
next()856         public Object next() {
857             if (nextAttachment != null) {
858                 Object ret = nextAttachment;
859                 nextAttachment = null;
860                 return ret;
861             }
862 
863             if (hasNext())
864                 return nextAttachment;
865 
866             return null;
867         }
868 
nextMatch()869         Object nextMatch() {
870             while (iter.hasNext()) {
871                 AttachmentPartImpl ap = (AttachmentPartImpl) iter.next();
872                 if (ap.hasAllHeaders(headers))
873                     return ap;
874             }
875             return null;
876         }
877 
remove()878         public void remove() {
879             iter.remove();
880         }
881     }
882 
getAttachments(MimeHeaders headers)883     public Iterator getAttachments(MimeHeaders headers) {
884         try {
885             initializeAllAttachments();
886         } catch (Exception e) {
887             throw new RuntimeException(e);
888         }
889         if (attachments == null)
890             return nullIter;
891 
892         return new MimeMatchingIterator(headers);
893     }
894 
removeAttachments(MimeHeaders headers)895     public void removeAttachments(MimeHeaders headers) {
896         try {
897             initializeAllAttachments();
898         } catch (Exception e) {
899             throw new RuntimeException(e);
900         }
901         if (attachments == null)
902             return ;
903 
904         Iterator it =  new MimeMatchingIterator(headers);
905         while (it.hasNext()) {
906             int index = attachments.indexOf(it.next());
907             attachments.set(index, null);
908         }
909         FinalArrayList f = new FinalArrayList();
910         for (int i = 0; i < attachments.size(); i++) {
911             if (attachments.get(i) != null) {
912                 f.add(attachments.get(i));
913             }
914         }
915         attachments = f;
916        // needsSave();
917     }
918 
createAttachmentPart()919     public AttachmentPart createAttachmentPart() {
920         return new AttachmentPartImpl();
921     }
922 
getAttachment(SOAPElement element)923     public  AttachmentPart getAttachment(SOAPElement element)
924         throws SOAPException {
925         try {
926             initializeAllAttachments();
927         } catch (Exception e) {
928             throw new RuntimeException(e);
929         }
930         String uri;
931         String hrefAttr = element.getAttribute("href");
932         if ("".equals(hrefAttr)) {
933             Node node = getValueNodeStrict(element);
934             String swaRef = null;
935             if (node != null) {
936                 swaRef = node.getValue();
937             }
938             if (swaRef == null || "".equals(swaRef)) {
939                 return null;
940             } else {
941                 uri = swaRef;
942             }
943         } else {
944             uri = hrefAttr;
945         }
946         return getAttachmentPart(uri);
947     }
948 
getValueNodeStrict(SOAPElement element)949     private Node getValueNodeStrict(SOAPElement element) {
950         Node node = (Node)element.getFirstChild();
951         if (node != null) {
952             if (node.getNextSibling() == null
953                 && node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
954                 return node;
955             } else {
956                 return null;
957             }
958         }
959         return null;
960     }
961 
962 
getAttachmentPart(String uri)963     private AttachmentPart getAttachmentPart(String uri) throws SOAPException {
964         AttachmentPart _part;
965         try {
966             if (uri.startsWith("cid:")) {
967                 // rfc2392
968                 uri = '<'+uri.substring("cid:".length())+'>';
969 
970                 MimeHeaders headersToMatch = new MimeHeaders();
971                 headersToMatch.addHeader(CONTENT_ID, uri);
972 
973                 Iterator i = this.getAttachments(headersToMatch);
974                 _part = (i == null) ? null : (AttachmentPart)i.next();
975             } else {
976                 // try content-location
977                 MimeHeaders headersToMatch = new MimeHeaders();
978                 headersToMatch.addHeader(CONTENT_LOCATION, uri);
979 
980                 Iterator i = this.getAttachments(headersToMatch);
981                 _part = (i == null) ? null : (AttachmentPart)i.next();
982             }
983 
984             // try  auto-generated JAXRPC CID
985             if (_part == null) {
986                 Iterator j = this.getAttachments();
987 
988                 while (j.hasNext()) {
989                     AttachmentPart p = (AttachmentPart)j.next();
990                     String cl = p.getContentId();
991                     if (cl != null) {
992                         // obtain the partname
993                         int eqIndex = cl.indexOf("=");
994                         if (eqIndex > -1) {
995                             cl = cl.substring(1, eqIndex);
996                             if (cl.equalsIgnoreCase(uri)) {
997                                 _part = p;
998                                  break;
999                             }
1000                         }
1001                     }
1002                 }
1003             }
1004 
1005         } catch (Exception se) {
1006             log.log(Level.SEVERE, "SAAJ0590.soap.unable.to.locate.attachment", new Object[] {uri});
1007             throw new SOAPExceptionImpl(se);
1008         }
1009         return _part;
1010     }
1011 
getHeaderBytes()1012     private final InputStream getHeaderBytes()
1013         throws IOException {
1014         SOAPPartImpl sp = (SOAPPartImpl) getSOAPPart();
1015         return sp.getContentAsStream();
1016     }
1017 
convertToSingleLine(String contentType)1018     private String convertToSingleLine(String contentType) {
1019         StringBuffer buffer = new StringBuffer();
1020         for (int i = 0; i < contentType.length(); i ++) {
1021             char c = contentType.charAt(i);
1022             if (c != '\r' && c != '\n' && c != '\t')
1023                 buffer.append(c);
1024         }
1025         return buffer.toString();
1026     }
1027 
getMimeMessage()1028     private MimeMultipart getMimeMessage() throws SOAPException {
1029         try {
1030             SOAPPartImpl soapPart = (SOAPPartImpl) getSOAPPart();
1031             MimeBodyPart mimeSoapPart = soapPart.getMimePart();
1032 
1033             /*
1034              * Get content type from this message instead of soapPart
1035              * to ensure agreement if soapPart is transcoded (XML <-> FI)
1036              */
1037             ContentType soapPartCtype = new ContentType(getExpectedContentType());
1038 
1039             if (!isFastInfoset) {
1040                 soapPartCtype.setParameter("charset", initCharset());
1041             }
1042             mimeSoapPart.setHeader("Content-Type", soapPartCtype.toString());
1043 
1044             MimeMultipart headerAndBody = null;
1045 
1046             if (!switchOffBM && !switchOffLazyAttachment &&
1047                    (multiPart != null) && !attachmentsInitialized) {
1048                 headerAndBody = new BMMimeMultipart();
1049                 headerAndBody.addBodyPart(mimeSoapPart);
1050                 if (attachments != null) {
1051                     for (Iterator eachAttachment = attachments.iterator();
1052                          eachAttachment.hasNext();) {
1053                         headerAndBody.addBodyPart(
1054                             ((AttachmentPartImpl) eachAttachment.next())
1055                                 .getMimePart());
1056                     }
1057                 }
1058                 InputStream in = ((BMMimeMultipart)multiPart).getInputStream();
1059                 if (!((BMMimeMultipart)multiPart).lastBodyPartFound() &&
1060                     !((BMMimeMultipart)multiPart).isEndOfStream()) {
1061                     ((BMMimeMultipart)headerAndBody).setInputStream(in);
1062                     ((BMMimeMultipart)headerAndBody).setBoundary(
1063                         ((BMMimeMultipart)multiPart).getBoundary());
1064                     ((BMMimeMultipart)headerAndBody).
1065                         setLazyAttachments(lazyAttachments);
1066                 }
1067 
1068             } else {
1069                 headerAndBody = new MimeMultipart();
1070                 headerAndBody.addBodyPart(mimeSoapPart);
1071 
1072                 for (Iterator eachAttachement = getAttachments();
1073                     eachAttachement.hasNext();
1074                     ) {
1075                     headerAndBody.addBodyPart(
1076                         ((AttachmentPartImpl) eachAttachement.next())
1077                             .getMimePart());
1078                 }
1079             }
1080 
1081             ContentType contentType = headerAndBody.getContentType();
1082 
1083             ParameterList l = contentType.getParameterList();
1084 
1085             // set content type depending on SOAP version
1086             l.set("type", getExpectedContentType());
1087             l.set("boundary", contentType.getParameter("boundary"));
1088             ContentType nct = new ContentType("multipart", "related", l);
1089 
1090             headers.setHeader(
1091                 "Content-Type",
1092                 convertToSingleLine(nct.toString()));
1093           // TBD
1094           //    Set content length MIME header here.
1095 
1096             return headerAndBody;
1097         } catch (SOAPException ex) {
1098             throw ex;
1099         } catch (Throwable ex) {
1100             log.severe("SAAJ0538.soap.cannot.convert.msg.to.multipart.obj");
1101             throw new SOAPExceptionImpl(
1102                 "Unable to convert SOAP message into "
1103                     + "a MimeMultipart object",
1104                 ex);
1105         }
1106     }
1107 
initCharset()1108     private String initCharset() {
1109 
1110         String charset = null;
1111 
1112         String[] cts = getMimeHeaders().getHeader("Content-Type");
1113         if ((cts != null) && (cts[0] != null)) {
1114             charset = getCharsetString(cts[0]);
1115         }
1116 
1117         if (charset == null) {
1118             charset = (String) getProperty(CHARACTER_SET_ENCODING);
1119         }
1120 
1121         if (charset != null) {
1122             return charset;
1123         }
1124 
1125         return "utf-8";
1126     }
1127 
getCharsetString(String s)1128     private String getCharsetString(String s) {
1129         try {
1130             int index = s.indexOf(";");
1131             if(index < 0)
1132                 return null;
1133             ParameterList pl = new ParameterList(s.substring(index));
1134             return pl.get("charset");
1135         } catch(Exception e) {
1136             return null;
1137         }
1138     }
1139 
saveChanges()1140     public void saveChanges() throws SOAPException {
1141 
1142         // suck in all the data from the attachments and have it
1143         // ready for writing/sending etc.
1144 
1145         String charset = initCharset();
1146 
1147         /*if (countAttachments() == 0) {*/
1148         int attachmentCount = (attachments == null) ? 0 : attachments.size();
1149         if (attachmentCount == 0) {
1150             if (!switchOffBM && !switchOffLazyAttachment &&
1151                 !attachmentsInitialized && (multiPart != null)) {
1152                 // so there might be attachments
1153                 attachmentCount = 1;
1154             }
1155         }
1156 
1157         try {
1158             if ((attachmentCount == 0) && !hasXOPContent()) {
1159                 InputStream in;
1160                 try{
1161                 /*
1162                  * Not sure why this is called getHeaderBytes(), but it actually
1163                  * returns the whole message as a byte stream. This stream could
1164                  * be either XML of Fast depending on the mode.
1165                  */
1166                     in = getHeaderBytes();
1167                     // no attachments, hence this property can be false
1168                     this.optimizeAttachmentProcessing = false;
1169                     if (SOAPPartImpl.lazyContentLength) {
1170                         inputStreamAfterSaveChanges = in;
1171                     }
1172                 } catch (IOException ex) {
1173                     log.severe("SAAJ0539.soap.cannot.get.header.stream");
1174                     throw new SOAPExceptionImpl(
1175                             "Unable to get header stream in saveChanges: ",
1176                             ex);
1177                 }
1178 
1179                 if (in instanceof ByteInputStream) {
1180                     ByteInputStream bIn = (ByteInputStream)in;
1181                     messageBytes = bIn.getBytes();
1182                     messageByteCount = bIn.getCount();
1183                 }
1184 
1185                 setFinalContentType(charset);
1186                 /*
1187                 headers.setHeader(
1188                         "Content-Type",
1189                         getExpectedContentType() +
1190                         (isFastInfoset ? "" : "; charset=" + charset));*/
1191                 if (messageByteCount > 0) {
1192                     headers.setHeader(
1193                             "Content-Length",
1194                             Integer.toString(messageByteCount));
1195                 }
1196             } else {
1197                 if(hasXOPContent())
1198                     mmp = getXOPMessage();
1199                 else
1200                     mmp = getMimeMessage();
1201             }
1202         } catch (Throwable ex) {
1203             log.severe("SAAJ0540.soap.err.saving.multipart.msg");
1204             throw new SOAPExceptionImpl(
1205                     "Error during saving a multipart message",
1206                     ex);
1207         }
1208 
1209         // FIX ME -- SOAP Action replaced by Content-Type optional parameter action
1210         /*
1211         if(isCorrectSoapVersion(SOAP1_1_FLAG)) {
1212 
1213             String[] soapAction = headers.getHeader("SOAPAction");
1214 
1215             if (soapAction == null || soapAction.length == 0)
1216                 headers.setHeader("SOAPAction", "\"\"");
1217 
1218         }
1219         */
1220 
1221         saved = true;
1222     }
1223 
getXOPMessage()1224     private MimeMultipart getXOPMessage() throws SOAPException {
1225         try {
1226             MimeMultipart headerAndBody = new MimeMultipart();
1227             SOAPPartImpl soapPart =  (SOAPPartImpl)getSOAPPart();
1228             MimeBodyPart mimeSoapPart = soapPart.getMimePart();
1229             ContentType soapPartCtype =
1230                 new ContentType("application/xop+xml");
1231             soapPartCtype.setParameter("type", getExpectedContentType());
1232             String charset = initCharset();
1233             soapPartCtype.setParameter("charset", charset);
1234             mimeSoapPart.setHeader("Content-Type", soapPartCtype.toString());
1235             headerAndBody.addBodyPart(mimeSoapPart);
1236 
1237             for (Iterator eachAttachement = getAttachments();
1238                 eachAttachement.hasNext();
1239                 ) {
1240                 headerAndBody.addBodyPart(
1241                     ((AttachmentPartImpl) eachAttachement.next())
1242                         .getMimePart());
1243             }
1244 
1245             ContentType contentType = headerAndBody.getContentType();
1246 
1247             ParameterList l = contentType.getParameterList();
1248 
1249             //lets not write start-info for now till we get servlet fix done
1250             l.set("start-info", getExpectedContentType());//+";charset="+initCharset());
1251 
1252             // set content type depending on SOAP version
1253             l.set("type", "application/xop+xml");
1254 
1255             if (isCorrectSoapVersion(SOAP1_2_FLAG)) {
1256                  String action = getAction();
1257                  if(action != null)
1258                      l.set("action", action);
1259             }
1260 
1261             l.set("boundary", contentType.getParameter("boundary"));
1262             ContentType nct = new ContentType("Multipart", "Related", l);
1263             headers.setHeader(
1264                 "Content-Type",
1265                 convertToSingleLine(nct.toString()));
1266             // TBD
1267             //    Set content length MIME header here.
1268 
1269             return headerAndBody;
1270         } catch (SOAPException ex) {
1271             throw ex;
1272         } catch (Throwable ex) {
1273             log.severe("SAAJ0538.soap.cannot.convert.msg.to.multipart.obj");
1274             throw new SOAPExceptionImpl(
1275                 "Unable to convert SOAP message into "
1276                     + "a MimeMultipart object",
1277                 ex);
1278         }
1279 
1280     }
1281 
hasXOPContent()1282     private boolean hasXOPContent() throws ParseException {
1283         String type = getContentType();
1284         if(type == null)
1285             return false;
1286         ContentType ct = new ContentType(type);
1287         //return isMimeMultipartXOPPackage(ct) || isSOAPBodyXOPPackage(ct);
1288         return isMimeMultipartXOPSoap1_1Package(ct) ||
1289             isMimeMultipartXOPSoap1_2Package(ct) || isSOAPBodyXOPPackage(ct);
1290 
1291     }
1292 
writeTo(OutputStream out)1293     public void writeTo(OutputStream out) throws SOAPException, IOException {
1294         if (saveRequired()){
1295             this.optimizeAttachmentProcessing = true;
1296             saveChanges();
1297         }
1298 
1299         if(!optimizeAttachmentProcessing){
1300             if (SOAPPartImpl.lazyContentLength && messageByteCount <= 0) {
1301                 byte[] buf = new byte[1024];
1302 
1303                 int length = 0;
1304                 while( (length = inputStreamAfterSaveChanges.read(buf)) != -1) {
1305                     out.write(buf,0, length);
1306                     messageByteCount += length;
1307                 }
1308                 if (messageByteCount > 0) {
1309                     headers.setHeader(
1310                             "Content-Length",
1311                             Integer.toString(messageByteCount));
1312                 }
1313             } else {
1314                 out.write(messageBytes, 0, messageByteCount);
1315             }
1316         }
1317         else{
1318             try{
1319                 if(hasXOPContent()){
1320                     mmp.writeTo(out);
1321                 }else{
1322                     mmp.writeTo(out);
1323                     if (!switchOffBM && !switchOffLazyAttachment &&
1324                             (multiPart != null) && !attachmentsInitialized) {
1325                         ((BMMimeMultipart)multiPart).setInputStream(
1326                                 ((BMMimeMultipart)mmp).getInputStream());
1327                     }
1328                 }
1329             } catch(Exception ex){
1330                 log.severe("SAAJ0540.soap.err.saving.multipart.msg");
1331                 throw new SOAPExceptionImpl(
1332                         "Error during saving a multipart message",
1333                         ex);
1334             }
1335         }
1336 
1337         if(isCorrectSoapVersion(SOAP1_1_FLAG)) {
1338 
1339             String[] soapAction = headers.getHeader("SOAPAction");
1340 
1341             if (soapAction == null || soapAction.length == 0)
1342                 headers.setHeader("SOAPAction", "\"\"");
1343 
1344         }
1345 
1346         messageBytes = null;
1347         needsSave();
1348     }
1349 
getSOAPBody()1350     public SOAPBody getSOAPBody() throws SOAPException {
1351         SOAPBody body = getSOAPPart().getEnvelope().getBody();
1352         /*if (body == null) {
1353              throw new SOAPException("No SOAP Body was found in the SOAP Message");
1354         }*/
1355         return body;
1356     }
1357 
getSOAPHeader()1358     public SOAPHeader getSOAPHeader() throws SOAPException {
1359         SOAPHeader hdr = getSOAPPart().getEnvelope().getHeader();
1360         /*if (hdr == null) {
1361             throw new SOAPException("No SOAP Header was found in the SOAP Message");
1362         }*/
1363         return hdr;
1364     }
1365 
initializeAllAttachments()1366     private void initializeAllAttachments ()
1367         throws MessagingException, SOAPException {
1368         if (switchOffBM || switchOffLazyAttachment) {
1369             return;
1370         }
1371 
1372         if (attachmentsInitialized || (multiPart == null)) {
1373             return;
1374         }
1375 
1376         if (attachments == null)
1377             attachments = new FinalArrayList();
1378 
1379         int count = multiPart.getCount();
1380         for (int i=0; i < count; i++ ) {
1381             initializeAttachment(multiPart.getBodyPart(i));
1382         }
1383         attachmentsInitialized = true;
1384         //multiPart = null;
1385         needsSave();
1386      }
1387 
initializeAttachment(MimeBodyPart mbp)1388     private void initializeAttachment(MimeBodyPart mbp) throws SOAPException {
1389         AttachmentPartImpl attachmentPart = new AttachmentPartImpl();
1390         DataHandler attachmentHandler = mbp.getDataHandler();
1391         attachmentPart.setDataHandler(attachmentHandler);
1392 
1393         AttachmentPartImpl.copyMimeHeaders(mbp, attachmentPart);
1394         attachments.add(attachmentPart);
1395     }
1396 
initializeAttachment(MimeMultipart multiPart, int i)1397     private void initializeAttachment(MimeMultipart multiPart, int i)
1398         throws Exception {
1399         MimeBodyPart currentBodyPart = multiPart.getBodyPart(i);
1400         AttachmentPartImpl attachmentPart = new AttachmentPartImpl();
1401 
1402         DataHandler attachmentHandler = currentBodyPart.getDataHandler();
1403         attachmentPart.setDataHandler(attachmentHandler);
1404 
1405         AttachmentPartImpl.copyMimeHeaders(currentBodyPart, attachmentPart);
1406         addAttachmentPart(attachmentPart);
1407     }
1408 
setMimeHeaders(SOAPPart soapPart, MimeBodyPart soapMessagePart)1409     private void setMimeHeaders(SOAPPart soapPart,
1410             MimeBodyPart soapMessagePart) throws Exception {
1411 
1412         // first remove the existing content-type
1413         soapPart.removeAllMimeHeaders();
1414         // add everything present in soapMessagePart
1415         List headers = soapMessagePart.getAllHeaders();
1416         int sz = headers.size();
1417         for( int i=0; i<sz; i++ ) {
1418             Header h = (Header) headers.get(i);
1419             soapPart.addMimeHeader(h.getName(), h.getValue());
1420         }
1421     }
1422 
initCharsetProperty(ContentType contentType)1423     private void initCharsetProperty(ContentType contentType) {
1424         String charset = contentType.getParameter("charset");
1425         if (charset != null) {
1426             ((SOAPPartImpl) getSOAPPart()).setSourceCharsetEncoding(charset);
1427             if(!charset.equalsIgnoreCase("utf-8"))
1428                 setProperty(CHARACTER_SET_ENCODING, charset);
1429         }
1430     }
1431 
setLazyAttachments(boolean flag)1432     public void setLazyAttachments(boolean flag) {
1433         lazyAttachments = flag;
1434     }
1435 
1436 }
1437