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