src/share/jaxws_classes/com/sun/xml/internal/messaging/saaj/soap/MessageImpl.java

Print this page


   1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.xml.internal.messaging.saaj.soap;
  27 
  28 import java.io.*;
  29 import java.util.*;
  30 import java.util.logging.Level;
  31 import java.util.logging.Logger;
  32 
  33 import javax.activation.DataHandler;
  34 import javax.activation.DataSource;
  35 import javax.xml.soap.*;

  36 import javax.xml.transform.Source;

  37 import javax.xml.transform.stream.StreamSource;
  38 
  39 import com.sun.xml.internal.messaging.saaj.packaging.mime.Header;
  40 import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.*;
  41 import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*;
  42 import com.sun.xml.internal.messaging.saaj.packaging.mime.MessagingException;
  43 
  44 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
  45 import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl;
  46 import com.sun.xml.internal.messaging.saaj.util.*;
  47 import com.sun.xml.internal.org.jvnet.mimepull.MIMEPart;
  48 
  49 /**
  50  * The message implementation for SOAP messages with
  51  * attachments. Messages for specific profiles will likely extend this
  52  * MessageImpl class and add more value for that particular profile.
  53  *
  54  * @author Anil Vijendran (akv@eng.sun.com)
  55  * @author Rajiv Mordani (rajiv.mordani@sun.com)
  56  * @author Manveen Kaur (manveen.kaur@sun.com)


  93 
  94     /**
  95      * True if this part is encoded using Fast Infoset.
  96      * MIME -> application/fastinfoset
  97      */
  98     protected boolean isFastInfoset = false;
  99 
 100     /**
 101      * True if the Accept header of this message includes
 102      * application/fastinfoset
 103      */
 104     protected boolean acceptFastInfoset = false;
 105 
 106     protected MimeMultipart mmp = null;
 107 
 108     // if attachments are present, don't read the entire message in byte stream in saveTo()
 109     private boolean optimizeAttachmentProcessing = true;
 110 
 111     private InputStream inputStreamAfterSaveChanges = null;
 112 


 113     // switch back to old MimeMultipart incase of problem
 114     private static boolean switchOffBM = false;
 115     private static boolean switchOffLazyAttachment = false;
 116     private static boolean useMimePull = false;
 117 
 118     static {
 119             String s = SAAJUtil.getSystemProperty("saaj.mime.optimization");
 120             if ((s != null) && s.equals("false")) {
 121                 switchOffBM = true;
 122             }
 123             s = SAAJUtil.getSystemProperty("saaj.lazy.mime.optimization");
 124             if ((s != null) && s.equals("false")) {
 125                 switchOffLazyAttachment = true;
 126             }
 127             useMimePull = SAAJUtil.getSystemBoolean("saaj.use.mimepull");
 128 
 129     }
 130 
 131     //property to indicate optimized serialization for lazy attachments
 132     private boolean lazyAttachments = false;


 324     }
 325 
 326     /**
 327      * Construct a message from an input stream. When messages are
 328      * received, there's two parts -- the transport headers and the
 329      * message content in a transport specific stream.
 330      *
 331      * @param contentType
 332      *      The parsed content type header from the headers variable.
 333      *      This is redundant parameter, but it avoids reparsing this header again.
 334      * @param stat
 335      *      The result of {@link #identifyContentType(ContentType)} over
 336      *      the contentType parameter. This redundant parameter, but it avoids
 337      *      recomputing this information again.
 338      */
 339     protected MessageImpl(MimeHeaders headers, final ContentType contentType, int stat, final InputStream in) throws SOAPExceptionImpl {
 340         init(headers, stat, contentType, in);
 341 
 342     }
 343 
 344     private void init(MimeHeaders headers, int stat, final ContentType contentType, final InputStream in) throws SOAPExceptionImpl {





 345         this.headers = headers;
 346 
 347         try {
 348 
 349             // Set isFastInfoset/acceptFastInfoset flag based on MIME type
 350             if ((stat & FI_ENCODED_FLAG) > 0) {
 351                 isFastInfoset = acceptFastInfoset = true;
 352             }
 353 
 354             // If necessary, inspect Accept header to set acceptFastInfoset
 355             if (!isFastInfoset) {
 356                 String[] values = headers.getHeader("Accept");
 357                 if (values != null) {
 358                     for (int i = 0; i < values.length; i++) {
 359                         StringTokenizer st = new StringTokenizer(values[i], ",");
 360                         while (st.hasMoreTokens()) {
 361                             final String token = st.nextToken().trim();
 362                             if (token.equalsIgnoreCase("application/fastinfoset") ||
 363                                 token.equalsIgnoreCase("application/soap+fastinfoset")) {
 364                                 acceptFastInfoset = true;
 365                                 break;
 366                             }
 367                         }
 368                     }
 369                 }
 370             }
 371 
 372             if (!isCorrectSoapVersion(stat)) {
 373                 log.log(
 374                     Level.SEVERE,
 375                     "SAAJ0533.soap.incorrect.Content-Type",
 376                     new String[] {
 377                         contentType.toString(),
 378                         getExpectedContentType()});
 379                 throw new SOAPVersionMismatchException(
 380                     "Cannot create message: incorrect content-type for SOAP version. Got: "
 381                         + contentType
 382                         + " Expected: "
 383                         + getExpectedContentType());
 384             }
 385 







 386             if ((stat & PLAIN_XML_FLAG) != 0) {

 387                 if (isFastInfoset) {
 388                     getSOAPPart().setContent(
 389                         FastInfosetReflection.FastInfosetSource_new(in));
 390                 } else {
 391                     initCharsetProperty(contentType);
 392                     getSOAPPart().setContent(new StreamSource(in));
 393                 }









 394             }
 395             else if ((stat & MIME_MULTIPART_FLAG) != 0) {





 396                 DataSource ds = new DataSource() {
 397                     public InputStream getInputStream() {
 398                         return in;
 399                     }
 400 
 401                     public OutputStream getOutputStream() {
 402                         return null;
 403                     }
 404 
 405                     public String getContentType() {
 406                         return contentType.toString();
 407                     }
 408 
 409                     public String getName() {
 410                         return "";
 411                     }
 412                 };
 413 
 414                 multiPart = null;
 415                 if (useMimePull) {
 416                     multiPart = new MimePullMultipart(ds,contentType);
 417                 } else if (switchOffBM) {
 418                     multiPart = new MimeMultipart(ds,contentType);


 470                             MimeBodyPart bp = null;
 471                             try {
 472                                while (!startParam.equals(contentID) && !startParam.equals(contentIDNoAngle)) {
 473                                     bp = bmMultipart.getNextPart(
 474                                             stream, bndbytes, sin);
 475                                     contentID = bp.getContentID();
 476                                     // Old versions of AXIS2 put angle brackets around the content
 477                                     // id but not the start param
 478                                     contentIDNoAngle = (contentID != null) ?
 479                                         contentID.replaceFirst("^<", "").replaceFirst(">$", "") : null;
 480                                 }
 481                                 soapMessagePart = bp;
 482                                 bmMultipart.removeBodyPart(bp);
 483                             } catch (Exception e) {
 484                                 throw new SOAPExceptionImpl(e);
 485                             }
 486                         }
 487                     }
 488                 }
 489 
 490                 if (soapPartInputStream == null && soapMessagePart != null) {










 491                     soapPartInputStream = soapMessagePart.getInputStream();
 492                 }
 493 
 494                 ContentType soapPartCType = new ContentType(
 495                                             soapMessagePart.getContentType());
 496                 initCharsetProperty(soapPartCType);
 497                 String baseType = soapPartCType.getBaseType().toLowerCase();
 498                 if(!(isEqualToSoap1_1Type(baseType)
 499                   || isEqualToSoap1_2Type(baseType)
 500                   || isSOAPBodyXOPPackage(soapPartCType))) {
 501                     log.log(Level.SEVERE,
 502                             "SAAJ0549.soap.part.invalid.Content-Type",
 503                             new Object[] {baseType});
 504                     throw new SOAPExceptionImpl(
 505                             "Bad Content-Type for SOAP Part : " +
 506                             baseType);
 507                 }
 508 
 509                 SOAPPart soapPart = getSOAPPart();
 510                 setMimeHeaders(soapPart, soapMessagePart);


 524     }
 525 
 526     public boolean isFastInfoset() {
 527         return isFastInfoset;
 528     }
 529 
 530     public boolean acceptFastInfoset() {
 531         return acceptFastInfoset;
 532     }
 533 
 534     public void setIsFastInfoset(boolean value) {
 535         if (value != isFastInfoset) {
 536             isFastInfoset = value;
 537             if (isFastInfoset) {
 538                 acceptFastInfoset = true;
 539             }
 540             saved = false;      // ensure transcoding if necessary
 541         }
 542     }
 543 









 544     public Object getProperty(String property) {
 545         return (String) properties.get(property);
 546     }
 547 
 548     public void setProperty(String property, Object value) {
 549         verify(property, value);
 550         properties.put(property, value);
 551     }
 552 
 553     private void verify(String property, Object value) {
 554         if (property.equalsIgnoreCase(SOAPMessage.WRITE_XML_DECLARATION)) {
 555             if (!("true".equals(value) || "false".equals(value)))
 556                 throw new RuntimeException(
 557                     property + " must have value false or true");
 558 
 559             try {
 560                 EnvelopeImpl env = (EnvelopeImpl) getSOAPPart().getEnvelope();
 561                 if ("true".equalsIgnoreCase((String)value)) {
 562                     env.setOmitXmlDecl("no");
 563                 } else if ("false".equalsIgnoreCase((String)value)) {


   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)


  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;


 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);


 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);


 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)) {