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