1 /*
   2  * Copyright (c) 1997, 2010, 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      */
 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      */
 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      */
 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      */
 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       */
 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       */
 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      */
 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      */
 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      */
 241     protected static boolean isSoap1_2Content(int stat) {
 242         return (stat & SOAP1_2_FLAG) != 0;
 243     }
 244 
 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) {
 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 
 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      */
 298     protected MessageImpl(MimeHeaders headers, final InputStream in)
 299         throws SOAPExceptionImpl {
 300         contentType = parseContentType(headers);
 301         init(headers,identifyContentType(contentType),contentType,in);
 302     }
 303 
 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      */
 339     protected MessageImpl(MimeHeaders headers, final ContentType contentType, int stat, final InputStream in) throws SOAPExceptionImpl {
 340         init(headers, stat, contentType, in);
 341 
 342     }
 343 
 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 
 526     public boolean isFastInfoset() {
 527         return isFastInfoset;
 528     }
 529 
 530     public boolean acceptFastInfoset() {
 531         return acceptFastInfoset;
 532     }
 533 
 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 
 544     public Object getProperty(String property) {
 545         return (String) properties.get(property);
 546     }
 547 
 548     public void setProperty(String property, Object value) {
 549         verify(property, value);
 550         properties.put(property, value);
 551     }
 552 
 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 
 585     protected abstract boolean isCorrectSoapVersion(int contentTypeId);
 586 
 587     protected abstract String getExpectedContentType();
 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
 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      */
 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 
 675     public MimeHeaders getMimeHeaders() {
 676         return this.headers;
 677     }
 678 
 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      */
 690     public String getContentType() {
 691         return getContentType(this.headers);
 692     }
 693 
 694     public void setContentType(String type) {
 695         headers.setHeader("Content-Type", type);
 696         needsSave();
 697     }
 698 
 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      */
 716     public String getBaseType() {
 717         return contentType().getBaseType();
 718     }
 719 
 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 
 727     public String getAction() {
 728         return contentType().getParameter("action");
 729     }
 730 
 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 
 738     public String getCharset() {
 739         return contentType().getParameter("charset");
 740     }
 741 
 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      */
 754     private final void needsSave() {
 755         saved = false;
 756     }
 757 
 758     public  boolean saveRequired() {
 759         return saved != true;
 760     }
 761 
 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 
 769     public void setContentDescription(String description) {
 770         headers.setHeader("Content-Description", description);
 771         needsSave();
 772     }
 773 
 774     public abstract SOAPPart getSOAPPart();
 775 
 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 
 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 
 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 
 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 
 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 {
 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 
 850         public boolean hasNext() {
 851             if (nextAttachment == null)
 852                 nextAttachment = nextMatch();
 853             return nextAttachment != null;
 854         }
 855 
 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 
 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 
 878         public void remove() {
 879             iter.remove();
 880         }
 881     }
 882 
 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 
 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 
 919     public AttachmentPart createAttachmentPart() {
 920         return new AttachmentPartImpl();
 921     }
 922 
 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 
 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 
 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 
1012     private final InputStream getHeaderBytes()
1013         throws IOException {
1014         SOAPPartImpl sp = (SOAPPartImpl) getSOAPPart();
1015         return sp.getContentAsStream();
1016     }
1017 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
1432     public void setLazyAttachments(boolean flag) {
1433         lazyAttachments = flag;
1434     }
1435 
1436 }