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

Mon, 04 May 2009 21:10:41 -0700

author
tbell
date
Mon, 04 May 2009 21:10:41 -0700
changeset 50
42dfec6871f6
parent 45
31822b475baa
child 78
860b95cc8d1d
permissions
-rw-r--r--

6658158: Mutable statics in SAAJ (findbugs)
6658163: txw2.DatatypeWriter.BUILDIN is a mutable static (findbugs)
Reviewed-by: darcy

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

mercurial