gt:                 for (Iterator eachAttachement = getAttachments();
context: /*
   * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Oracle in the LICENSE file that accompanied this code.
   *
   * This code is distributed in the hope that it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   * version 2 for more details (a copy is included in the LICENSE file that
   * accompanied this code).
   *
   * You should have received a copy of the GNU General Public License version
   * 2 along with this work; if not, write to the Free Software Foundation,
   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   *
   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   */
  
  package com.sun.xml.internal.messaging.saaj.soap;
  
  import java.io.*;
  import java.util.*;
  import java.util.logging.Level;
  import java.util.logging.Logger;
  
  import javax.activation.DataHandler;
  import javax.activation.DataSource;
  import javax.xml.soap.*;
  import javax.xml.stream.XMLStreamReader;
  import javax.xml.transform.Source;
  import javax.xml.transform.stax.StAXSource;
  import javax.xml.transform.stream.StreamSource;
  
  import com.sun.xml.internal.messaging.saaj.packaging.mime.Header;
  import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.*;
  import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*;
  import com.sun.xml.internal.messaging.saaj.packaging.mime.MessagingException;
  
  import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
  import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl;
  import com.sun.xml.internal.messaging.saaj.util.*;
  import com.sun.xml.internal.org.jvnet.mimepull.MIMEPart;
  
  /**
   * The message implementation for SOAP messages with
   * attachments. Messages for specific profiles will likely extend this
   * MessageImpl class and add more value for that particular profile.
   *
   * @author Anil Vijendran (akv@eng.sun.com)
   * @author Rajiv Mordani (rajiv.mordani@sun.com)
   * @author Manveen Kaur (manveen.kaur@sun.com)
   */
  
  public abstract class MessageImpl
      extends SOAPMessage
      implements SOAPConstants {
  
  
      public static final String CONTENT_ID             = "Content-ID";
      public static final String CONTENT_LOCATION       = "Content-Location";
  
      protected static final Logger log =
          Logger.getLogger(LogDomainConstants.SOAP_DOMAIN,
                           "com.sun.xml.internal.messaging.saaj.soap.LocalStrings");
  
      protected static final int PLAIN_XML_FLAG      = 1;      // 00001
      protected static final int MIME_MULTIPART_FLAG = 2;      // 00010
      protected static final int SOAP1_1_FLAG = 4;             // 00100
      protected static final int SOAP1_2_FLAG = 8;             // 01000
      //protected static final int MIME_MULTIPART_XOP_FLAG = 14; // 01110
      protected static final int MIME_MULTIPART_XOP_SOAP1_1_FLAG = 6;  // 00110
      protected static final int MIME_MULTIPART_XOP_SOAP1_2_FLAG = 10; // 01010
      protected static final int XOP_FLAG = 13;                // 01101
      protected static final int FI_ENCODED_FLAG     = 16;     // 10000
  
      protected MimeHeaders headers;
      protected ContentType contentType;
      protected SOAPPartImpl soapPartImpl;
      protected FinalArrayList attachments;
      protected boolean saved = false;
      protected byte[] messageBytes;
      protected int messageByteCount;
      protected HashMap properties = new HashMap();
  
      // used for lazy attachment initialization
      protected MimeMultipart multiPart = null;
      protected boolean attachmentsInitialized = false;
  
      /**
       * True if this part is encoded using Fast Infoset.
       * MIME -> application/fastinfoset
       */
      protected boolean isFastInfoset = false;
  
      /**
       * True if the Accept header of this message includes
       * application/fastinfoset
       */
      protected boolean acceptFastInfoset = false;
  
      protected MimeMultipart mmp = null;
  
      // if attachments are present, don't read the entire message in byte stream in saveTo()
      private boolean optimizeAttachmentProcessing = true;
  
      private InputStream inputStreamAfterSaveChanges = null;
  
      public static final String LAZY_SOAP_BODY_PARSING = "saaj.lazy.soap.body";
  
      // switch back to old MimeMultipart incase of problem
      private static boolean switchOffBM = false;
      private static boolean switchOffLazyAttachment = false;
      private static boolean useMimePull = false;
  
      static {
              String s = SAAJUtil.getSystemProperty("saaj.mime.optimization");
              if ((s != null) && s.equals("false")) {
                  switchOffBM = true;
              }
              s = SAAJUtil.getSystemProperty("saaj.lazy.mime.optimization");
              if ((s != null) && s.equals("false")) {
                  switchOffLazyAttachment = true;
              }
              useMimePull = SAAJUtil.getSystemBoolean("saaj.use.mimepull");
  
      }
  
      //property to indicate optimized serialization for lazy attachments
      private boolean lazyAttachments = false;
  
      // most of the times, Content-Types are already all lower cased.
      // String.toLowerCase() works faster in this case, so even if you
      // are only doing one comparison, it pays off to use String.toLowerCase()
      // than String.equalsIgnoreCase(). When you do more than one comparison,
      // the benefits of String.toLowerCase() dominates.
      //
      //
      // for FI,
      //   use application/fastinfoset for SOAP 1.1
      //   use application/soap+fastinfoset for SOAP 1.2
      // to speed up comparisons, test methods always use lower cases.
  
      /**
       * @param primary
       *      must be all lower case
       * @param sub
       *      must be all lower case
       */
      private static boolean isSoap1_1Type(String primary, String sub) {
          return primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml")
              || primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml-soap")
              || primary.equals("application")
                 && sub.equals("fastinfoset");
      }
  
      /**
       * @param type
       *      must be all lower case
       */
      private static boolean isEqualToSoap1_1Type(String type) {
          return type.startsWith("text/xml") ||
                 type.startsWith("application/fastinfoset");
      }
  
      /**
       * @param primary
       *      must be all lower case
       * @param sub
       *      must be all lower case
       */
      private static boolean isSoap1_2Type(String primary, String sub) {
          return primary.equals("application")
                 && (sub.equals("soap+xml")
                     || sub.equals("soap+fastinfoset"));
      }
  
      /**
       * @param type
       *      must be all lower case
       */
      private static boolean isEqualToSoap1_2Type(String type) {
          return type.startsWith("application/soap+xml") ||
                 type.startsWith("application/soap+fastinfoset");
      }
  
      /**
        * Construct a new message. This will be invoked before message
        * sends.
        */
      protected MessageImpl() {
          this(false, false);
          attachmentsInitialized = true;
      }
  
      /**
        * Construct a new message. This will be invoked before message
        * sends.
        */
      protected MessageImpl(boolean isFastInfoset, boolean acceptFastInfoset) {
          this.isFastInfoset = isFastInfoset;
          this.acceptFastInfoset = acceptFastInfoset;
  
          headers = new MimeHeaders();
          headers.setHeader("Accept", getExpectedAcceptHeader());
          contentType = new ContentType();
      }
  
      /**
       * Shallow copy.
       */
      protected MessageImpl(SOAPMessage msg) {
          if (!(msg instanceof MessageImpl)) {
              // don't know how to handle this.
          }
          MessageImpl src = (MessageImpl) msg;
          this.headers = src.headers;
          this.soapPartImpl = src.soapPartImpl;
          this.attachments = src.attachments;
          this.saved = src.saved;
          this.messageBytes = src.messageBytes;
          this.messageByteCount = src.messageByteCount;
          this.properties = src.properties;
          this.contentType = src.contentType;
      }
  
      /**
       * @param stat
       *      the mask value obtained from {@link #identifyContentType(ContentType)}
       */
      protected static boolean isSoap1_1Content(int stat) {
          return (stat & SOAP1_1_FLAG) != 0;
      }
  
      /**
       * @param stat
       *      the mask value obtained from {@link #identifyContentType(ContentType)}
       */
      protected static boolean isSoap1_2Content(int stat) {
          return (stat & SOAP1_2_FLAG) != 0;
      }
  
       private static boolean isMimeMultipartXOPSoap1_2Package(ContentType contentType) {
          String type = contentType.getParameter("type");
          if (type == null) {
              return false;
          }
          type = type.toLowerCase();
          if (!type.startsWith("application/xop+xml")) {
              return false;
          }
          String startinfo = contentType.getParameter("start-info");
          if (startinfo == null) {
              return false;
          }
          startinfo = startinfo.toLowerCase();
          return isEqualToSoap1_2Type(startinfo);
      }
  
  
       //private static boolean isMimeMultipartXOPPackage(ContentType contentType) {
       private static boolean isMimeMultipartXOPSoap1_1Package(ContentType contentType) {
          String type = contentType.getParameter("type");
          if(type==null)
              return false;
  
          type = type.toLowerCase();
          if(!type.startsWith("application/xop+xml"))
              return false;
  
          String startinfo = contentType.getParameter("start-info");
          if(startinfo == null)
              return false;
          startinfo = startinfo.toLowerCase();
          return isEqualToSoap1_1Type(startinfo);
      }
  
      private static boolean isSOAPBodyXOPPackage(ContentType contentType){
          String primary = contentType.getPrimaryType();
          String sub = contentType.getSubType();
  
          if (primary.equalsIgnoreCase("application")) {
              if (sub.equalsIgnoreCase("xop+xml")) {
                  String type = getTypeParameter(contentType);
                  return isEqualToSoap1_2Type(type) || isEqualToSoap1_1Type(type);
              }
          }
          return false;
      }
  
      /**
       * Construct a message from an input stream. When messages are
       * received, there's two parts -- the transport headers and the
       * message content in a transport specific stream.
       */
      protected MessageImpl(MimeHeaders headers, final InputStream in)
          throws SOAPExceptionImpl {
          contentType = parseContentType(headers);
          init(headers,identifyContentType(contentType),contentType,in);
      }
  
      private static ContentType parseContentType(MimeHeaders headers) throws SOAPExceptionImpl {
          final String ct;
          if (headers != null)
              ct = getContentType(headers);
          else {
              log.severe("SAAJ0550.soap.null.headers");
              throw new SOAPExceptionImpl("Cannot create message: " +
                                          "Headers can't be null");
          }
  
          if (ct == null) {
              log.severe("SAAJ0532.soap.no.Content-Type");
              throw new SOAPExceptionImpl("Absent Content-Type");
          }
          try {
              return new ContentType(ct);
          } catch (Throwable ex) {
              log.severe("SAAJ0535.soap.cannot.internalize.message");
              throw new SOAPExceptionImpl("Unable to internalize message", ex);
          }
      }
  
      /**
       * Construct a message from an input stream. When messages are
       * received, there's two parts -- the transport headers and the
       * message content in a transport specific stream.
       *
       * @param contentType
       *      The parsed content type header from the headers variable.
       *      This is redundant parameter, but it avoids reparsing this header again.
       * @param stat
       *      The result of {@link #identifyContentType(ContentType)} over
       *      the contentType parameter. This redundant parameter, but it avoids
       *      recomputing this information again.
       */
      protected MessageImpl(MimeHeaders headers, final ContentType contentType, int stat, final InputStream in) throws SOAPExceptionImpl {
          init(headers, stat, contentType, in);
  
      }
  
      public MessageImpl(MimeHeaders headers, ContentType ct, int stat,
              XMLStreamReader reader) throws SOAPExceptionImpl {
          init(headers, stat, ct, reader);
      }
  
      private void init(MimeHeaders headers, int stat, final ContentType contentType, final Object input) throws SOAPExceptionImpl {
          this.headers = headers;
  
          try {
  
              // Set isFastInfoset/acceptFastInfoset flag based on MIME type
              if ((stat & FI_ENCODED_FLAG) > 0) {
                  isFastInfoset = acceptFastInfoset = true;
              }
  
              // If necessary, inspect Accept header to set acceptFastInfoset
              if (!isFastInfoset) {
                  String[] values = headers.getHeader("Accept");
                  if (values != null) {
                      for (int i = 0; i < values.length; i++) {
                          StringTokenizer st = new StringTokenizer(values[i], ",");
                          while (st.hasMoreTokens()) {
                              final String token = st.nextToken().trim();
                              if (token.equalsIgnoreCase("application/fastinfoset") ||
                                  token.equalsIgnoreCase("application/soap+fastinfoset")) {
                                  acceptFastInfoset = true;
                                  break;
                              }
                          }
                      }
                  }
              }
  
              if (!isCorrectSoapVersion(stat)) {
                  log.log(
                      Level.SEVERE,
                      "SAAJ0533.soap.incorrect.Content-Type",
                      new String[] {
                          contentType.toString(),
                          getExpectedContentType()});
                  throw new SOAPVersionMismatchException(
                      "Cannot create message: incorrect content-type for SOAP version. Got: "
                          + contentType
                          + " Expected: "
                          + getExpectedContentType());
              }
              InputStream in = null;
              XMLStreamReader rdr = null;
              if (input instanceof InputStream) {
                 in = (InputStream) input;
              } else {
                //is a StAX reader
                  rdr = (XMLStreamReader) input;
              }
              if ((stat & PLAIN_XML_FLAG) != 0) {
                  if (in != null) {
                      if (isFastInfoset) {
                          getSOAPPart().setContent(
                                  FastInfosetReflection.FastInfosetSource_new(in));
                      } else {
                          initCharsetProperty(contentType);
                          getSOAPPart().setContent(new StreamSource(in));
                      }
                  } else {
                      //is a StAX reader
                      if (isFastInfoset) {
                          //need to get FI stax reader
                      } else {
                          initCharsetProperty(contentType);
                          getSOAPPart().setContent(new StAXSource(rdr));
                      }
                  }
              }
              else if ((stat & MIME_MULTIPART_FLAG) != 0 && in == null) {
                  //only parse multipart in the inputstream case
                  //in stax reader case, we would be given the attachments separately
                  getSOAPPart().setContent(new StAXSource(rdr));
              } else if ((stat & MIME_MULTIPART_FLAG) != 0) {
                  final InputStream finalIn = in;
                  DataSource ds = new DataSource() {
                      public InputStream getInputStream() {
                          return finalIn;
                      }
  
                      public OutputStream getOutputStream() {
                          return null;
                      }
  
                      public String getContentType() {
                          return contentType.toString();
                      }
  
                      public String getName() {
                          return "";
                      }
                  };
  
                  multiPart = null;
                  if (useMimePull) {
                      multiPart = new MimePullMultipart(ds,contentType);
                  } else if (switchOffBM) {
                      multiPart = new MimeMultipart(ds,contentType);
                  } else {
                      multiPart = new BMMimeMultipart(ds,contentType);
                  }
  
                  String startParam = contentType.getParameter("start");
                  MimeBodyPart soapMessagePart = null;
                  InputStream soapPartInputStream = null;
                  String contentID = null;
                  String contentIDNoAngle = null;
                  if (switchOffBM || switchOffLazyAttachment) {
                      if(startParam == null) {
                          soapMessagePart = multiPart.getBodyPart(0);
                          for (int i = 1; i < multiPart.getCount(); i++) {
                              initializeAttachment(multiPart, i);
                          }
                      } else {
                          soapMessagePart = multiPart.getBodyPart(startParam);
                          for (int i = 0; i < multiPart.getCount(); i++) {
                              contentID = multiPart.getBodyPart(i).getContentID();
                              // Old versions of AXIS2 put angle brackets around the content
                              // id but not the start param
                              contentIDNoAngle = (contentID != null) ?
                                  contentID.replaceFirst("^<", "").replaceFirst(">$", "") : null;
                              if(!startParam.equals(contentID) && !startParam.equals(contentIDNoAngle))
                                  initializeAttachment(multiPart, i);
                          }
                      }
                  } else {
                      if (useMimePull) {
                          MimePullMultipart mpMultipart = (MimePullMultipart)multiPart;
                          MIMEPart sp = mpMultipart.readAndReturnSOAPPart();
                          soapMessagePart = new MimeBodyPart(sp);
                          soapPartInputStream = sp.readOnce();
                      } else {
                          BMMimeMultipart bmMultipart =
                                  (BMMimeMultipart) multiPart;
                          InputStream stream = bmMultipart.initStream();
  
                          SharedInputStream sin = null;
                          if (stream instanceof SharedInputStream) {
                              sin = (SharedInputStream) stream;
                          }
  
                          String boundary = "--" +
                                  contentType.getParameter("boundary");
                          byte[] bndbytes = ASCIIUtility.getBytes(boundary);
                          if (startParam == null) {
                              soapMessagePart =
                                      bmMultipart.getNextPart(stream, bndbytes, sin);
                              bmMultipart.removeBodyPart(soapMessagePart);
                          } else {
                              MimeBodyPart bp = null;
                              try {
                                 while (!startParam.equals(contentID) && !startParam.equals(contentIDNoAngle)) {
                                      bp = bmMultipart.getNextPart(
                                              stream, bndbytes, sin);
                                      contentID = bp.getContentID();
                                      // Old versions of AXIS2 put angle brackets around the content
                                      // id but not the start param
                                      contentIDNoAngle = (contentID != null) ?
                                          contentID.replaceFirst("^<", "").replaceFirst(">$", "") : null;
                                  }
                                  soapMessagePart = bp;
                                  bmMultipart.removeBodyPart(bp);
                              } catch (Exception e) {
                                  throw new SOAPExceptionImpl(e);
                              }
                          }
                      }
                  }
  
                  // findbugs correctly points out that we'd NPE instantiating
                  // the ContentType (just below here) if soapMessagePart were
                  // null.  Hence are better off throwing a controlled exception
                  // at this point if it is null.
                  if (soapMessagePart == null) {
                      log.severe("SAAJ0510.soap.cannot.create.envelope");
                      throw new SOAPExceptionImpl(
                          "Unable to create envelope from given source: SOAP part not found");
                  }
  
                  if (soapPartInputStream == null) {
                      soapPartInputStream = soapMessagePart.getInputStream();
                  }
  
                  ContentType soapPartCType = new ContentType(
                                              soapMessagePart.getContentType());
                  initCharsetProperty(soapPartCType);
                  String baseType = soapPartCType.getBaseType().toLowerCase();
                  if(!(isEqualToSoap1_1Type(baseType)
                    || isEqualToSoap1_2Type(baseType)
                    || isSOAPBodyXOPPackage(soapPartCType))) {
                      log.log(Level.SEVERE,
                              "SAAJ0549.soap.part.invalid.Content-Type",
                              new Object[] {baseType});
                      throw new SOAPExceptionImpl(
                              "Bad Content-Type for SOAP Part : " +
                              baseType);
                  }
  
                  SOAPPart soapPart = getSOAPPart();
                  setMimeHeaders(soapPart, soapMessagePart);
                  soapPart.setContent(isFastInfoset ?
                       (Source) FastInfosetReflection.FastInfosetSource_new(
                           soapPartInputStream) :
                       (Source) new StreamSource(soapPartInputStream));
              } else {
                  log.severe("SAAJ0534.soap.unknown.Content-Type");
                  throw new SOAPExceptionImpl("Unrecognized Content-Type");
              }
          } catch (Throwable ex) {
              log.severe("SAAJ0535.soap.cannot.internalize.message");
              throw new SOAPExceptionImpl("Unable to internalize message", ex);
          }
          needsSave();
      }
  
      public boolean isFastInfoset() {
          return isFastInfoset;
      }
  
      public boolean acceptFastInfoset() {
          return acceptFastInfoset;
      }
  
      public void setIsFastInfoset(boolean value) {
          if (value != isFastInfoset) {
              isFastInfoset = value;
              if (isFastInfoset) {
                  acceptFastInfoset = true;
              }
              saved = false;      // ensure transcoding if necessary
          }
      }
  
      public boolean isLazySoapBodyParsing() {
          Object lazyParsingProp = getProperty(LAZY_SOAP_BODY_PARSING);
          if (lazyParsingProp == null) return false;
          if (lazyParsingProp instanceof Boolean) {
              return ((Boolean) lazyParsingProp).booleanValue();
          } else {
              return Boolean.valueOf(lazyParsingProp.toString());
          }
      }
      public Object getProperty(String property) {
          return (String) properties.get(property);
      }
  
      public void setProperty(String property, Object value) {
          verify(property, value);
          properties.put(property, value);
      }
  
      private void verify(String property, Object value) {
          if (property.equalsIgnoreCase(SOAPMessage.WRITE_XML_DECLARATION)) {
              if (!("true".equals(value) || "false".equals(value)))
                  throw new RuntimeException(
                      property + " must have value false or true");
  
              try {
                  EnvelopeImpl env = (EnvelopeImpl) getSOAPPart().getEnvelope();
                  if ("true".equalsIgnoreCase((String)value)) {
                      env.setOmitXmlDecl("no");
                  } else if ("false".equalsIgnoreCase((String)value)) {
                      env.setOmitXmlDecl("yes");
                  }
              } catch (Exception e) {
                  log.log(Level.SEVERE, "SAAJ0591.soap.exception.in.set.property",
                      new Object[] {e.getMessage(), "javax.xml.soap.write-xml-declaration"});
                  throw new RuntimeException(e);
              }
              return;
          }
  
          if (property.equalsIgnoreCase(SOAPMessage.CHARACTER_SET_ENCODING)) {
              try {
                  ((EnvelopeImpl) getSOAPPart().getEnvelope()).setCharsetEncoding((String)value);
              } catch (Exception e) {
                  log.log(Level.SEVERE, "SAAJ0591.soap.exception.in.set.property",
                      new Object[] {e.getMessage(), "javax.xml.soap.character-set-encoding"});
                  throw new RuntimeException(e);
              }
          }
      }
  
      protected abstract boolean isCorrectSoapVersion(int contentTypeId);
  
      protected abstract String getExpectedContentType();
      protected abstract String getExpectedAcceptHeader();
  
      /**
       * Sniffs the Content-Type header so that we can determine how to process.
       *
       * <p>
       * In the absence of type attribute we assume it to be text/xml.
       * That would mean we're easy on accepting the message and
       * generate the correct thing (as the SWA spec also specifies
       * that the type parameter should always be text/xml)
       *
       * @return
       *      combination of flags, such as PLAIN_XML_CODE and MIME_MULTIPART_CODE.
       */
      // SOAP1.2 allow SOAP1.2 content type
      static int identifyContentType(ContentType ct)
          throws SOAPExceptionImpl {
          // TBD
          //    Is there anything else we need to verify here?
  
          String primary = ct.getPrimaryType().toLowerCase();
          String sub = ct.getSubType().toLowerCase();
  
          if (primary.equals("multipart")) {
              if (sub.equals("related")) {
                  String type = getTypeParameter(ct);
                  if (isEqualToSoap1_1Type(type)) {
                      return (type.equals("application/fastinfoset") ?
                             FI_ENCODED_FLAG : 0) | MIME_MULTIPART_FLAG | SOAP1_1_FLAG;
                  }
                  else if (isEqualToSoap1_2Type(type)) {
                      return (type.equals("application/soap+fastinfoset") ?
                             FI_ENCODED_FLAG : 0) | MIME_MULTIPART_FLAG | SOAP1_2_FLAG;
                  /*} else if (isMimeMultipartXOPPackage(ct)) {
                      return MIME_MULTIPART_XOP_FLAG;*/
                  } else if (isMimeMultipartXOPSoap1_1Package(ct)) {
                      return MIME_MULTIPART_XOP_SOAP1_1_FLAG;
                  } else if (isMimeMultipartXOPSoap1_2Package(ct)) {
                      return MIME_MULTIPART_XOP_SOAP1_2_FLAG;
                  } else {
                      log.severe("SAAJ0536.soap.content-type.mustbe.multipart");
                      throw new SOAPExceptionImpl(
                          "Content-Type needs to be Multipart/Related "
                              + "and with \"type=text/xml\" "
                              + "or \"type=application/soap+xml\"");
                  }
              } else {
                  log.severe("SAAJ0537.soap.invalid.content-type");
                  throw new SOAPExceptionImpl(
                      "Invalid Content-Type: " + primary + '/' + sub);
              }
          }
          else if (isSoap1_1Type(primary, sub)) {
              return (primary.equalsIgnoreCase("application")
                      && sub.equalsIgnoreCase("fastinfoset") ?
                          FI_ENCODED_FLAG : 0)
                     | PLAIN_XML_FLAG | SOAP1_1_FLAG;
          }
          else if (isSoap1_2Type(primary, sub)) {
              return (primary.equalsIgnoreCase("application")
                      && sub.equalsIgnoreCase("soap+fastinfoset") ?
                          FI_ENCODED_FLAG : 0)
                     | PLAIN_XML_FLAG | SOAP1_2_FLAG;
          } else if(isSOAPBodyXOPPackage(ct)){
              return XOP_FLAG;
          } else {
              log.severe("SAAJ0537.soap.invalid.content-type");
              throw new SOAPExceptionImpl(
                  "Invalid Content-Type:"
                      + primary
                      + '/'
                      + sub
                      + ". Is this an error message instead of a SOAP response?");
          }
      }
  
      /**
       * Obtains the type parameter of the Content-Type header. Defaults to "text/xml".
       */
      private static String getTypeParameter(ContentType contentType) {
          String p = contentType.getParameter("type");
          if(p!=null)
              return p.toLowerCase();
          else
              return "text/xml";
      }
  
      public MimeHeaders getMimeHeaders() {
          return this.headers;
      }
  
      final static String getContentType(MimeHeaders headers) {
          String[] values = headers.getHeader("Content-Type");
          if (values == null)
              return null;
          else
              return values[0];
      }
  
      /*
       * Get the complete ContentType value along with optional parameters.
       */
      public String getContentType() {
          return getContentType(this.headers);
      }
  
      public void setContentType(String type) {
          headers.setHeader("Content-Type", type);
          needsSave();
      }
  
      private ContentType contentType() {
          ContentType ct = null;
          try {
              String currentContent = getContentType();
              if (currentContent == null) {
                  return this.contentType;
              }
              ct = new ContentType(currentContent);
          } catch (Exception e) {
              // what to do here?
          }
          return ct;
      }
  
      /*
       * Return the MIME type string, without the parameters.
       */
      public String getBaseType() {
          return contentType().getBaseType();
      }
  
      public void setBaseType(String type) {
          ContentType ct = contentType();
          ct.setParameter("type", type);
          headers.setHeader("Content-Type", ct.toString());
          needsSave();
      }
  
      public String getAction() {
          return contentType().getParameter("action");
      }
  
      public void setAction(String action) {
          ContentType ct = contentType();
          ct.setParameter("action", action);
          headers.setHeader("Content-Type", ct.toString());
          needsSave();
      }
  
      public String getCharset() {
          return contentType().getParameter("charset");
      }
  
      public void setCharset(String charset) {
          ContentType ct = contentType();
          ct.setParameter("charset", charset);
          headers.setHeader("Content-Type", ct.toString());
          needsSave();
      }
  
      /**
       * All write methods (i.e setters) should call this method in
       * order to make sure that a save is necessary since the state
       * has been modified.
       */
      private final void needsSave() {
          saved = false;
      }
  
      public  boolean saveRequired() {
          return saved != true;
      }
  
      public String getContentDescription() {
          String[] values = headers.getHeader("Content-Description");
          if (values != null && values.length > 0)
              return values[0];
          return null;
      }
  
      public void setContentDescription(String description) {
          headers.setHeader("Content-Description", description);
          needsSave();
      }
  
      public abstract SOAPPart getSOAPPart();
  
      public void removeAllAttachments() {
          try {
              initializeAllAttachments();
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
  
          if (attachments != null) {
              attachments.clear();
              needsSave();
          }
      }
  
      public int countAttachments() {
          try {
              initializeAllAttachments();
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
          if (attachments != null)
              return attachments.size();
          return 0;
      }
  
      public void addAttachmentPart(AttachmentPart attachment) {
          try {
              initializeAllAttachments();
              this.optimizeAttachmentProcessing = true;
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
          if (attachments == null)
              attachments = new FinalArrayList();
  
          attachments.add(attachment);
  
          needsSave();
      }
  
      static private final Iterator nullIter = Collections.EMPTY_LIST.iterator();
  
      public Iterator getAttachments() {
          try {
              initializeAllAttachments();
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
          if (attachments == null)
              return nullIter;
          return attachments.iterator();
      }
  
      private void setFinalContentType(String charset) {
          ContentType ct = contentType();
          if (ct == null) {
              ct = new ContentType();
          }
          String[] split = getExpectedContentType().split("/");
          ct.setPrimaryType(split[0]);
          ct.setSubType(split[1]);
          ct.setParameter("charset", charset);
          headers.setHeader("Content-Type", ct.toString());
      }
  
      private class MimeMatchingIterator implements Iterator {
          public MimeMatchingIterator(MimeHeaders headers) {
              this.headers = headers;
              this.iter = attachments.iterator();
          }
  
          private Iterator iter;
          private MimeHeaders headers;
          private Object nextAttachment;
  
          public boolean hasNext() {
              if (nextAttachment == null)
                  nextAttachment = nextMatch();
              return nextAttachment != null;
          }
  
          public Object next() {
              if (nextAttachment != null) {
                  Object ret = nextAttachment;
                  nextAttachment = null;
                  return ret;
              }
  
              if (hasNext())
                  return nextAttachment;
  
              return null;
          }
  
          Object nextMatch() {
              while (iter.hasNext()) {
                  AttachmentPartImpl ap = (AttachmentPartImpl) iter.next();
                  if (ap.hasAllHeaders(headers))
                      return ap;
              }
              return null;
          }
  
          public void remove() {
              iter.remove();
          }
      }
  
      public Iterator getAttachments(MimeHeaders headers) {
          try {
              initializeAllAttachments();
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
          if (attachments == null)
              return nullIter;
  
          return new MimeMatchingIterator(headers);
      }
  
      public void removeAttachments(MimeHeaders headers) {
          try {
              initializeAllAttachments();
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
          if (attachments == null)
              return ;
  
          Iterator it =  new MimeMatchingIterator(headers);
          while (it.hasNext()) {
              int index = attachments.indexOf(it.next());
              attachments.set(index, null);
          }
          FinalArrayList f = new FinalArrayList();
          for (int i = 0; i < attachments.size(); i++) {
              if (attachments.get(i) != null) {
                  f.add(attachments.get(i));
              }
          }
          attachments = f;
         // needsSave();
      }
  
      public AttachmentPart createAttachmentPart() {
          return new AttachmentPartImpl();
      }
  
      public  AttachmentPart getAttachment(SOAPElement element)
          throws SOAPException {
          try {
              initializeAllAttachments();
          } catch (Exception e) {
              throw new RuntimeException(e);
          }
          String uri;
          String hrefAttr = element.getAttribute("href");
          if ("".equals(hrefAttr)) {
              Node node = getValueNodeStrict(element);
              String swaRef = null;
              if (node != null) {
                  swaRef = node.getValue();
              }
              if (swaRef == null || "".equals(swaRef)) {
                  return null;
              } else {
                  uri = swaRef;
              }
          } else {
              uri = hrefAttr;
          }
          return getAttachmentPart(uri);
      }
  
      private Node getValueNodeStrict(SOAPElement element) {
          Node node = (Node)element.getFirstChild();
          if (node != null) {
              if (node.getNextSibling() == null
                  && node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) {
                  return node;
              } else {
                  return null;
              }
          }
          return null;
      }
  
  
      private AttachmentPart getAttachmentPart(String uri) throws SOAPException {
          AttachmentPart _part;
          try {
              if (uri.startsWith("cid:")) {
                  // rfc2392
                  uri = '<'+uri.substring("cid:".length())+'>';
  
                  MimeHeaders headersToMatch = new MimeHeaders();
                  headersToMatch.addHeader(CONTENT_ID, uri);
  
                  Iterator i = this.getAttachments(headersToMatch);
                  _part = (i == null) ? null : (AttachmentPart)i.next();
              } else {
                  // try content-location
                  MimeHeaders headersToMatch = new MimeHeaders();
                  headersToMatch.addHeader(CONTENT_LOCATION, uri);
  
                  Iterator i = this.getAttachments(headersToMatch);
                  _part = (i == null) ? null : (AttachmentPart)i.next();
              }
  
              // try  auto-generated JAXRPC CID
              if (_part == null) {
                  Iterator j = this.getAttachments();
  
                  while (j.hasNext()) {
                      AttachmentPart p = (AttachmentPart)j.next();
                      String cl = p.getContentId();
                      if (cl != null) {
                          // obtain the partname
                          int eqIndex = cl.indexOf("=");
                          if (eqIndex > -1) {
                              cl = cl.substring(1, eqIndex);
                              if (cl.equalsIgnoreCase(uri)) {
                                  _part = p;
                                   break;
                              }
                          }
                      }
                  }
              }
  
          } catch (Exception se) {
              log.log(Level.SEVERE, "SAAJ0590.soap.unable.to.locate.attachment", new Object[] {uri});
              throw new SOAPExceptionImpl(se);
          }
          return _part;
      }
  
      private final InputStream getHeaderBytes()
          throws IOException {
          SOAPPartImpl sp = (SOAPPartImpl) getSOAPPart();
          return sp.getContentAsStream();
      }
  
      private String convertToSingleLine(String contentType) {
          StringBuffer buffer = new StringBuffer();
          for (int i = 0; i < contentType.length(); i ++) {
              char c = contentType.charAt(i);
              if (c != '\r' && c != '\n' && c != '\t')
                  buffer.append(c);
          }
          return buffer.toString();
      }
  
      private MimeMultipart getMimeMessage() throws SOAPException {
          try {
              SOAPPartImpl soapPart = (SOAPPartImpl) getSOAPPart();
              MimeBodyPart mimeSoapPart = soapPart.getMimePart();
  
              /*
               * Get content type from this message instead of soapPart
               * to ensure agreement if soapPart is transcoded (XML <-> FI)
               */
              ContentType soapPartCtype = new ContentType(getExpectedContentType());
  
              if (!isFastInfoset) {
                  soapPartCtype.setParameter("charset", initCharset());
              }
              mimeSoapPart.setHeader("Content-Type", soapPartCtype.toString());
  
              MimeMultipart headerAndBody = null;
  
              if (!switchOffBM && !switchOffLazyAttachment &&
                     (multiPart != null) && !attachmentsInitialized) {
                  headerAndBody = new BMMimeMultipart();
                  headerAndBody.addBodyPart(mimeSoapPart);
                  if (attachments != null) {
                      for (Iterator eachAttachment = attachments.iterator();
                           eachAttachment.hasNext();) {
                          headerAndBody.addBodyPart(
                              ((AttachmentPartImpl) eachAttachment.next())
                                  .getMimePart());
                      }
                  }
                  InputStream in = ((BMMimeMultipart)multiPart).getInputStream();
                  if (!((BMMimeMultipart)multiPart).lastBodyPartFound() &&
                      !((BMMimeMultipart)multiPart).isEndOfStream()) {
                      ((BMMimeMultipart)headerAndBody).setInputStream(in);
                      ((BMMimeMultipart)headerAndBody).setBoundary(
                          ((BMMimeMultipart)multiPart).getBoundary());
                      ((BMMimeMultipart)headerAndBody).
                          setLazyAttachments(lazyAttachments);
                  }
  
              } else {
                  headerAndBody = new MimeMultipart();
                  headerAndBody.addBodyPart(mimeSoapPart);
  
  