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