Source code: org/apache/axis/SOAPPart.java
1 /*
2 * Copyright 2001-2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.axis ;
18
19 import org.apache.axis.components.logger.LogFactory;
20 import org.apache.axis.encoding.DeserializationContext;
21 import org.apache.axis.encoding.SerializationContext;
22 import org.apache.axis.message.InputStreamBody;
23 import org.apache.axis.message.MimeHeaders;
24 import org.apache.axis.message.SOAPDocumentImpl;
25 import org.apache.axis.message.SOAPEnvelope;
26 import org.apache.axis.message.SOAPHeaderElement;
27 import org.apache.axis.transport.http.HTTPConstants;
28 import org.apache.axis.utils.ByteArray;
29 import org.apache.axis.utils.Messages;
30 import org.apache.axis.utils.SessionUtils;
31 import org.apache.axis.utils.XMLUtils;
32 import org.apache.axis.handlers.HandlerChainImpl;
33 import org.apache.commons.logging.Log;
34 import org.w3c.dom.Attr;
35 import org.w3c.dom.CDATASection;
36 import org.w3c.dom.Comment;
37 import org.w3c.dom.DOMException;
38 import org.w3c.dom.DOMImplementation;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.DocumentFragment;
41 import org.w3c.dom.DocumentType;
42 import org.w3c.dom.Element;
43 import org.w3c.dom.EntityReference;
44 import org.w3c.dom.NamedNodeMap;
45 import org.w3c.dom.Node;
46 import org.w3c.dom.NodeList;
47 import org.w3c.dom.ProcessingInstruction;
48 import org.w3c.dom.Text;
49 import org.xml.sax.InputSource;
50 import org.xml.sax.SAXException;
51
52 import javax.xml.soap.SOAPException;
53 import javax.xml.soap.SOAPMessage;
54 import javax.xml.transform.Source;
55 import javax.xml.transform.dom.DOMSource;
56 import javax.xml.transform.stream.StreamSource;
57 import java.io.BufferedOutputStream;
58 import java.io.BufferedReader;
59 import java.io.BufferedWriter;
60 import java.io.ByteArrayInputStream;
61 import java.io.ByteArrayOutputStream;
62 import java.io.IOException;
63 import java.io.InputStream;
64 import java.io.OutputStreamWriter;
65 import java.io.PrintWriter;
66 import java.io.Reader;
67 import java.io.StringReader;
68 import java.io.StringWriter;
69 import java.io.UnsupportedEncodingException;
70 import java.io.Writer;
71 import java.util.Iterator;
72 import java.util.Vector;
73
74 /**
75 * The SOAPPart provides access to the root part of the Message which
76 * contains the envelope.
77 * <p>
78 * SOAPPart implements Part, providing common MIME operations.
79 * <p>
80 * SOAPPart also allows access to its envelope,
81 * as a string, byte[], InputStream, or SOAPEnvelope. (This functionality
82 * used to be in Message, and has been moved here more or less verbatim
83 * pending further cleanup.)
84 *
85 * @author Rob Jellinghaus (robj@unrealities.com)
86 * @author Doug Davis (dug@us.ibm.com)
87 * @author Glen Daniels (gdaniels@allaire.com)
88 * @author Heejune Ahn (cityboy@tmax.co.kr)
89 */
90 public class SOAPPart extends javax.xml.soap.SOAPPart implements Part
91 {
92 protected static Log log =
93 LogFactory.getLog(SOAPPart.class.getName());
94
95 public static final int FORM_STRING = 1;
96 public static final int FORM_INPUTSTREAM = 2;
97 public static final int FORM_SOAPENVELOPE = 3;
98 public static final int FORM_BYTES = 4;
99 public static final int FORM_BODYINSTREAM = 5;
100 public static final int FORM_FAULT = 6;
101 public static final int FORM_OPTIMIZED = 7;
102 private int currentForm;
103
104 /**
105 * property used to set SOAPEnvelope as default form
106 */
107 public static final String ALLOW_FORM_OPTIMIZATION = "axis.form.optimization";
108
109
110 //private Hashtable headers = new Hashtable();
111 private MimeHeaders mimeHeaders = new MimeHeaders();
112
113 private static final String[] formNames =
114 { "", "FORM_STRING", "FORM_INPUTSTREAM", "FORM_SOAPENVELOPE",
115 "FORM_BYTES", "FORM_BODYINSTREAM", "FORM_FAULT", "FORM_OPTIMIZED" };
116
117 /**
118 * The current representation of the SOAP contents of this part.
119 * May be a String, byte[], InputStream, or SOAPEnvelope, depending
120 * on whatever was last asked for. (ack)
121 * <p>
122 * currentForm must have the corresponding value.
123 * <p>
124 * As someone once said: "Just a placeholder until we figure out what the actual Message
125 * object is."
126 */
127 private Object currentMessage ;
128
129 /**
130 * default message encoding charset
131 */
132 private String currentEncoding = "UTF-8";
133
134 // These two fields are used for caching in getAsString and getAsBytes
135 private String currentMessageAsString = null;
136 private byte[] currentMessageAsBytes = null;
137 private org.apache.axis.message.SOAPEnvelope currentMessageAsEnvelope= null;
138
139 /**
140 * Message object this part is tied to. Used for serialization settings.
141 */
142 private Message msgObject;
143
144 /** Field contentSource. */
145 private Source contentSource = null;
146
147 /**
148 * The original message. Again, may be String, byte[], InputStream,
149 * or SOAPEnvelope.
150 */
151 // private Object originalMessage ; //free up reference this is not in use.
152
153 /**
154 * Create a new SOAPPart.
155 * <p>
156 * Do not call this directly! Should only be called by Message.
157 *
158 * @param parent the parent <code>Message</code>
159 * @param initialContents the initial contens <code>Object</code>
160 * @param isBodyStream if the body is in a stream
161 */
162 public SOAPPart(Message parent, Object initialContents, boolean isBodyStream) {
163
164 setMimeHeader(HTTPConstants.HEADER_CONTENT_ID , SessionUtils.generateSessionId());
165 setMimeHeader(HTTPConstants.HEADER_CONTENT_TYPE , "text/xml");
166
167 msgObject=parent;
168 // originalMessage = initialContents;
169 int form = FORM_STRING;
170 if (initialContents instanceof SOAPEnvelope) {
171 form = FORM_SOAPENVELOPE;
172 ((SOAPEnvelope)initialContents).setOwnerDocument(this);
173 } else if (initialContents instanceof InputStream) {
174 form = isBodyStream ? FORM_BODYINSTREAM : FORM_INPUTSTREAM;
175 } else if (initialContents instanceof byte[]) {
176 form = FORM_BYTES;
177 } else if (initialContents instanceof AxisFault) {
178 form = FORM_FAULT;
179 }
180
181 if (log.isDebugEnabled()) {
182 log.debug("Enter: SOAPPart ctor(" + formNames[form] + ")");
183 }
184
185 setCurrentMessage(initialContents, form);
186
187 if (log.isDebugEnabled()) {
188 log.debug("Exit: SOAPPart ctor()");
189 }
190 }
191
192
193 /**
194 * Get the <code>Message</code> for this <code>Part</code>.
195 *
196 * @return the <code>Message</code> for this <code>Part</code>
197 */
198 public Message getMessage(){
199 return msgObject;
200 }
201
202 /**
203 * Set the Message for this Part.
204 * Do not call this Directly. Called by Message.
205 *
206 * @param msg the <code>Message</code> for this part
207 */
208 public void setMessage (Message msg) {
209 this.msgObject= msg;
210 }
211
212 /**
213 * Content type is always "text/xml" for SOAPParts.
214 *
215 * @return the content type
216 */
217 public String getContentType() {
218 return "text/xml";
219 }
220
221 /**
222 * Get the content length for this SOAPPart.
223 * This will force buffering of the SOAPPart, but it will
224 * also cache the byte[] form of the SOAPPart.
225 *
226 * @return the content length in bytes
227 */
228 public long getContentLength() throws AxisFault {
229 saveChanges();
230 if (currentForm == FORM_OPTIMIZED) {
231 return ((ByteArray) currentMessage).size();
232 } else if (currentForm == FORM_BYTES) {
233 return ((byte[]) currentMessage).length;
234 }
235 byte[] bytes = this.getAsBytes();
236 return bytes.length;
237 }
238
239 /**
240 * This set the SOAP Envelope for this part.
241 * <p>
242 * Note: It breaks the chicken/egg created.
243 * I need a message to create an attachment...
244 * From the attachment I should be able to get a reference...
245 * I now want to edit elements in the envelope in order to
246 * place the attachment reference to it.
247 * How do I now update the SOAP envelope with what I've changed?
248 *
249 * @param env the <code>SOAPEnvelope</CODE> for this <code>SOAPPart</code>
250 */
251
252 public void setSOAPEnvelope(org.apache.axis.message.SOAPEnvelope env){
253 setCurrentMessage(env, FORM_SOAPENVELOPE) ;
254 }
255
256 /**
257 * Write the contents to the specified stream.
258 *
259 * @param os the <code>java.io.OutputStream</code> to write to
260 */
261 public void writeTo(java.io.OutputStream os) throws IOException {
262 if ( currentForm == FORM_BYTES ) {
263 os.write((byte[])currentMessage);
264 } else if ( currentForm == FORM_OPTIMIZED ) {
265 ((ByteArray) currentMessage).writeTo(os);
266 } else {
267 Writer writer = new OutputStreamWriter(os, currentEncoding);
268 writer = new BufferedWriter(new PrintWriter(writer));
269 writeTo(writer);
270 writer.flush();
271 }
272 }
273
274 /**
275 * Write the contents to the specified writer.
276 *
277 * @param writer the <code>Writer</code> to write to
278 */
279 public void writeTo(Writer writer) throws IOException {
280 boolean inclXmlDecl = false;
281
282 if (msgObject.getMessageContext() != null) { // if we have message context (JAX-RPC), write xml decl always.
283 inclXmlDecl = true;
284 } else { // if we have no message context (SAAJ), write xml decl according to property.
285 try {
286 String xmlDecl = (String)msgObject.getProperty(SOAPMessage.WRITE_XML_DECLARATION);
287 if (xmlDecl != null && xmlDecl.equals("true")) {
288 inclXmlDecl = true;
289 }
290 } catch (SOAPException e) {
291 throw new IOException(e.getMessage());
292 }
293 }
294
295 if ( currentForm == FORM_FAULT ) {
296 AxisFault env = (AxisFault)currentMessage;
297 try {
298 SerializationContext serContext = new SerializationContext(writer, getMessage().getMessageContext());
299 serContext.setSendDecl(inclXmlDecl);
300 serContext.setEncoding(currentEncoding);
301 env.output(serContext);
302 } catch (Exception e) {
303 log.error(Messages.getMessage("exception00"), e);
304 throw env;
305 }
306 return;
307 }
308
309 if ( currentForm == FORM_SOAPENVELOPE ) {
310 SOAPEnvelope env = (SOAPEnvelope)currentMessage;
311 try {
312 SerializationContext serContext = new SerializationContext(writer, getMessage().getMessageContext());
313 serContext.setSendDecl(inclXmlDecl);
314 serContext.setEncoding(currentEncoding);
315 env.output(serContext);
316 } catch (Exception e) {
317 throw AxisFault.makeFault(e);
318 }
319 return;
320 }
321
322 String xml = this.getAsString();
323 if(inclXmlDecl){
324 if(!xml.startsWith("<?xml")){
325 writer.write("<?xml version=\"1.0\" encoding=\"");
326 writer.write(currentEncoding);
327 writer.write("\"?>");
328 }
329 }
330 writer.write(xml);
331 }
332
333 /**
334 * Get the current message, in whatever form it happens to be right now.
335 * Will return a String, byte[], InputStream, or SOAPEnvelope, depending
336 * on circumstances.
337 * <p>
338 * The method name is historical.
339 * TODO: rename this for clarity; should be more like getContents.
340 *
341 * @return the current content
342 */
343 public Object getCurrentMessage() {
344 return currentMessage;
345 }
346
347 /**
348 * Set the current message
349 * @param currMsg
350 * @param form
351 */
352 public void setCurrentMessage(Object currMsg, int form) {
353 currentMessageAsString = null; //Get rid of any cached stuff this is new.
354 currentMessageAsBytes = null;
355 currentMessageAsEnvelope= null;
356 setCurrentForm(currMsg, form);
357 }
358 /**
359 * Set the current contents of this Part.
360 * The method name is historical.
361 * TODO: rename this for clarity to something more like setContents???
362 *
363 * @param currMsg the new content of this part
364 * @param form the form of the message
365 */
366 private void setCurrentForm(Object currMsg, int form) {
367 if (log.isDebugEnabled()) {
368 String msgStr;
369 if (currMsg instanceof String) {
370 msgStr = (String)currMsg;
371 } else {
372 msgStr = currMsg.getClass().getName();
373 }
374 log.debug(Messages.getMessage("setMsgForm", formNames[form],
375 "" + msgStr));
376 }
377
378 // only change form if allowed
379 if (isFormOptimizationAllowed()) {
380 currentMessage = currMsg;
381 currentForm = form;
382 if (currentForm == FORM_SOAPENVELOPE) {
383 currentMessageAsEnvelope = (org.apache.axis.message.SOAPEnvelope) currMsg;
384 }
385 }
386 }
387
388 /**
389 * check if the allow optimization flag is on
390 * @return form optimization flag
391 */
392 private boolean isFormOptimizationAllowed() {
393 boolean allowFormOptimization = true;
394 Message msg = getMessage();
395 if (msg != null) {
396 MessageContext ctx = msg.getMessageContext();
397 if (ctx != null) {
398 Boolean propFormOptimization = (Boolean)ctx.getProperty(ALLOW_FORM_OPTIMIZATION);
399 if (propFormOptimization != null) {
400 allowFormOptimization = propFormOptimization.booleanValue();
401 }
402 }
403 }
404 return allowFormOptimization;
405 }
406
407 public int getCurrentForm() {
408 return currentForm;
409 }
410
411 /**
412 * Get the contents of this Part (not the headers!), as a byte
413 * array. This will force buffering of the message.
414 *
415 * @return an array of bytes containing a byte representation of this Part
416 * @throws AxisFault if this Part can't be serialized to the byte array
417 */
418 public byte[] getAsBytes() throws AxisFault {
419 log.debug("Enter: SOAPPart::getAsBytes");
420 if ( currentForm == FORM_OPTIMIZED ) {
421 log.debug("Exit: SOAPPart::getAsBytes");
422 try {
423 return ((ByteArray) currentMessage).toByteArray();
424 } catch (IOException e) {
425 throw AxisFault.makeFault(e);
426 }
427 }
428 if ( currentForm == FORM_BYTES ) {
429 log.debug("Exit: SOAPPart::getAsBytes");
430 return (byte[])currentMessage;
431 }
432
433 if ( currentForm == FORM_BODYINSTREAM ) {
434 try {
435 getAsSOAPEnvelope();
436 } catch (Exception e) {
437 log.fatal(Messages.getMessage("makeEnvFail00"), e);
438 log.debug("Exit: SOAPPart::getAsBytes");
439 return null;
440 }
441 }
442
443 if ( currentForm == FORM_INPUTSTREAM ) {
444 // Assumes we don't need a content length
445 try {
446 InputStream inp = null;
447 byte[] buf = null;
448 try{
449 inp = (InputStream) currentMessage ;
450 ByteArrayOutputStream baos = new ByteArrayOutputStream();
451 buf = new byte[4096];
452 int len ;
453 while ( (len = inp.read(buf,0,4096)) != -1 )
454 baos.write( buf, 0, len );
455 buf = baos.toByteArray();
456 }finally{
457 if(inp != null &&
458 currentMessage instanceof org.apache.axis.transport.http.SocketInputStream )
459 inp.close();
460 }
461 setCurrentForm( buf, FORM_BYTES );
462 log.debug("Exit: SOAPPart::getAsBytes");
463 return (byte[])currentMessage;
464 }
465 catch( Exception e ) {
466 log.error(Messages.getMessage("exception00"), e);
467 }
468 log.debug("Exit: SOAPPart::getAsBytes");
469 return null;
470 }
471
472 if ( currentForm == FORM_SOAPENVELOPE ||
473 currentForm == FORM_FAULT ){
474 currentEncoding = XMLUtils.getEncoding(msgObject, null);
475 ByteArrayOutputStream baos = new ByteArrayOutputStream();
476 BufferedOutputStream os = new BufferedOutputStream(baos);
477 try {
478 this.writeTo(os);
479 os.flush();
480 } catch (Exception e) {
481 throw AxisFault.makeFault(e);
482 }
483 setCurrentForm(baos.toByteArray(), FORM_BYTES);
484 if (log.isDebugEnabled()) {
485 log.debug("Exit: SOAPPart::getAsBytes(): " + currentMessage);
486 }
487 return (byte[]) currentMessage;
488 }
489
490 if ( currentForm == FORM_STRING ) {
491 // If the current message was already converted from
492 // a byte[] to String, return the byte[] representation
493 // (this is done to avoid unnecessary conversions)
494 if (currentMessage == currentMessageAsString &&
495 currentMessageAsBytes != null) {
496 if (log.isDebugEnabled()) {
497 log.debug("Exit: SOAPPart::getAsBytes()");
498 }
499 return currentMessageAsBytes;
500 }
501 // Save this message in case it is requested later in getAsString
502 currentMessageAsString = (String) currentMessage;
503 try{
504 currentEncoding = XMLUtils.getEncoding(msgObject, null);
505 setCurrentForm( ((String)currentMessage).getBytes(currentEncoding),
506 FORM_BYTES );
507 }catch(UnsupportedEncodingException ue){
508 setCurrentForm( ((String)currentMessage).getBytes(),
509 FORM_BYTES );
510 }
511 currentMessageAsBytes = (byte[]) currentMessage;
512
513 log.debug("Exit: SOAPPart::getAsBytes");
514 return (byte[])currentMessage;
515 }
516
517 log.error(Messages.getMessage("cantConvert00", ""+currentForm));
518
519 log.debug("Exit: SOAPPart::getAsBytes");
520 return null;
521 }
522
523 public void saveChanges() throws AxisFault {
524 log.debug("Enter: SOAPPart::saveChanges");
525 if ( currentForm == FORM_SOAPENVELOPE ||
526 currentForm == FORM_FAULT ){
527 currentEncoding = XMLUtils.getEncoding(msgObject, null);
528 ByteArray array = new ByteArray();
529 try {
530 writeTo(array);
531 array.flush();
532 } catch (Exception e) {
533 throw AxisFault.makeFault(e);
534 }
535 setCurrentForm( array, FORM_OPTIMIZED );
536 if (log.isDebugEnabled()) {
537 log.debug("Exit: SOAPPart::saveChanges(): " + currentMessage);
538 }
539 }
540 }
541 /**
542 * Get the contents of this Part (not the headers!), as a String.
543 * This will force buffering of the message.
544 *
545 * @return a <code>String</code> containing the content of this message
546 * @throws AxisFault if there is an error serializing this part
547 */
548 public String getAsString() throws AxisFault {
549 log.debug("Enter: SOAPPart::getAsString");
550 if ( currentForm == FORM_STRING ) {
551 if (log.isDebugEnabled()) {
552 log.debug("Exit: SOAPPart::getAsString(): " + currentMessage);
553 }
554 return (String)currentMessage;
555 }
556
557 if ( currentForm == FORM_INPUTSTREAM ||
558 currentForm == FORM_BODYINSTREAM ) {
559 getAsBytes();
560 // Fall thru to "Bytes"
561 }
562
563 if ( currentForm == FORM_OPTIMIZED) {
564 try {
565 currentMessageAsBytes =
566 ((ByteArray) currentMessage).toByteArray();
567 } catch (IOException e) {
568 throw AxisFault.makeFault(e);
569 }
570
571 try{
572 setCurrentForm(new String((byte[])currentMessageAsBytes,
573 currentEncoding),
574 FORM_STRING);
575 }catch(UnsupportedEncodingException ue){
576 setCurrentForm( new String((byte[]) currentMessageAsBytes),
577 FORM_STRING );
578 }
579 if (log.isDebugEnabled()) {
580 log.debug("Exit: SOAPPart::getAsString(): " + currentMessage);
581 }
582 return (String)currentMessage;
583 }
584
585 if ( currentForm == FORM_BYTES ) {
586 // If the current message was already converted from
587 // a String to byte[], return the String representation
588 // (this is done to avoid unnecessary conversions)
589 if (currentMessage == currentMessageAsBytes &&
590 currentMessageAsString != null) {
591 if (log.isDebugEnabled()) {
592 log.debug("Exit: SOAPPart::getAsString(): " + currentMessageAsString);
593 }
594 return currentMessageAsString;
595 }
596
597 // Save this message in case it is requested later in getAsBytes
598 currentMessageAsBytes = (byte[]) currentMessage;
599 try{
600 setCurrentForm(new String((byte[])currentMessage,
601 currentEncoding),
602 FORM_STRING);
603 }catch(UnsupportedEncodingException ue){
604 setCurrentForm( new String((byte[]) currentMessage),
605 FORM_STRING );
606 }
607 currentMessageAsString = (String) currentMessage;
608 if (log.isDebugEnabled()) {
609 log.debug("Exit: SOAPPart::getAsString(): " + currentMessage);
610 }
611 return (String)currentMessage;
612 }
613
614 if ( currentForm == FORM_FAULT ) {
615 StringWriter writer = new StringWriter();
616 try {
617 this.writeTo(writer);
618 } catch (Exception e) {
619 log.error(Messages.getMessage("exception00"), e);
620 return null;
621 }
622 setCurrentForm(writer.getBuffer().toString(), FORM_STRING);
623 if (log.isDebugEnabled()) {
624 log.debug("Exit: SOAPPart::getAsString(): " + currentMessage);
625 }
626 return (String)currentMessage;
627 }
628
629 if ( currentForm == FORM_SOAPENVELOPE ) {
630 StringWriter writer = new StringWriter();
631 try {
632 this.writeTo(writer);
633 } catch (Exception e) {
634 throw AxisFault.makeFault(e);
635 }
636 setCurrentForm(writer.getBuffer().toString(), FORM_STRING);
637 if (log.isDebugEnabled()) {
638 log.debug("Exit: SOAPPart::getAsString(): " + currentMessage);
639 }
640 return (String)currentMessage;
641 }
642
643 log.error( Messages.getMessage("cantConvert01", ""+currentForm));
644
645 log.debug("Exit: SOAPPart::getAsString()");
646 return null;
647 }
648
649 /**
650 * Get the contents of this Part (not the MIME headers!), as a
651 * SOAPEnvelope. This will force a complete parse of the
652 * message.
653 *
654 * @return a <code>SOAPEnvelope</code> containing the message content
655 * @throws AxisFault if the envelope could not be constructed
656 */
657 public SOAPEnvelope getAsSOAPEnvelope()
658 throws AxisFault
659 {
660 if (log.isDebugEnabled()) {
661 log.debug("Enter: SOAPPart::getAsSOAPEnvelope()");
662 log.debug(Messages.getMessage("currForm", formNames[currentForm]));
663 }
664 if ( currentForm == FORM_SOAPENVELOPE )
665 return (SOAPEnvelope)currentMessage;
666
667
668 if (currentForm == FORM_BODYINSTREAM) {
669 InputStreamBody bodyEl =
670 new InputStreamBody((InputStream)currentMessage);
671 SOAPEnvelope env = new SOAPEnvelope();
672 env.setOwnerDocument(this);
673 env.addBodyElement(bodyEl);
674 setCurrentForm(env, FORM_SOAPENVELOPE);
675 return env;
676 }
677
678 InputSource is;
679
680 if ( currentForm == FORM_INPUTSTREAM ) {
681 is = new InputSource( (InputStream) currentMessage );
682 String encoding = XMLUtils.getEncoding(msgObject, null, null);
683 if (encoding != null) {
684 currentEncoding = encoding;
685 is.setEncoding(currentEncoding);
686 }
687 } else {
688 is = new InputSource(new StringReader(getAsString()));
689 }
690 DeserializationContext dser = new DeserializationContext(is,
691 getMessage().getMessageContext(),
692 getMessage().getMessageType());
693 dser.getEnvelope().setOwnerDocument(this);
694 // This may throw a SAXException
695 try {
696 dser.parse();
697 } catch (SAXException e) {
698 Exception real = e.getException();
699 if (real == null)
700 real = e;
701 throw AxisFault.makeFault(real);
702 }
703
704 SOAPEnvelope nse= dser.getEnvelope();
705 if(currentMessageAsEnvelope != null){
706 //Need to synchronize back processed header info.
707 Vector newHeaders= nse.getHeaders();
708 Vector oldHeaders= currentMessageAsEnvelope.getHeaders();
709 if( null != newHeaders && null != oldHeaders){
710 Iterator ohi= oldHeaders.iterator();
711 Iterator nhi= newHeaders.iterator();
712 while( ohi.hasNext() && nhi.hasNext()){
713 SOAPHeaderElement nhe= (SOAPHeaderElement)nhi.next();
714 SOAPHeaderElement ohe= (SOAPHeaderElement)ohi.next();
715
716 if(ohe.isProcessed()) nhe.setProcessed(true);
717 }
718 }
719
720 }
721
722 setCurrentForm(nse, FORM_SOAPENVELOPE);
723
724 log.debug("Exit: SOAPPart::getAsSOAPEnvelope");
725 SOAPEnvelope env = (SOAPEnvelope)currentMessage;
726 env.setOwnerDocument(this);
727 return env;
728 }
729
730 /**
731 * Add the specified MIME header, as per JAXM.
732 *
733 * @param header the header to add
734 * @param value the value of that header
735 */
736 public void addMimeHeader (String header, String value) {
737 mimeHeaders.addHeader(header, value);
738 }
739
740 /**
741 * Get the specified MIME header.
742 *
743 * @param header the name of a MIME header
744 * @return the value of the first header named <code>header</code>
745 */
746 private String getFirstMimeHeader (String header) {
747 String[] values = mimeHeaders.getHeader(header);
748 if(values != null && values.length>0)
749 return values[0];
750 return null;
751 }
752
753 /**
754 * Total size in bytes (of all content and headers, as encoded).
755 public abstract int getSize();
756 */
757
758 /**
759 * Content location.
760 *
761 * @return the content location
762 */
763 public String getContentLocation() {
764 return getFirstMimeHeader(HTTPConstants.HEADER_CONTENT_LOCATION);
765 }
766
767 /**
768 * Set content location.
769 *
770 * @param loc the content location
771 */
772 public void setContentLocation(String loc) {
773 setMimeHeader(HTTPConstants.HEADER_CONTENT_LOCATION, loc);
774 }
775
776 /**
777 * Sets Content-Id of this part.
778 * already defined.
779 * @param newCid new Content-Id
780 */
781 public void setContentId(String newCid){
782 setMimeHeader(HTTPConstants.HEADER_CONTENT_ID,newCid);
783 }
784
785 /**
786 * Content ID.
787 *
788 * @return the content ID
789 */
790 public String getContentId() {
791 return getFirstMimeHeader(HTTPConstants.HEADER_CONTENT_ID);
792 }
793 /**
794 * Content ID.
795 *
796 * @return the contentId reference value that should be used directly
797 * as an href in a SOAP element to reference this attachment.
798 * <B>Not part of JAX-RPC, JAX-M, SAAJ, etc. </B>
799 */
800 public String getContentIdRef() {
801 return org.apache.axis.attachments.Attachments.CIDprefix +
802 getContentId();
803 }
804
805
806 /**
807 * Get all headers that match.
808 *
809 * @param match an array of <code>String</code>s giving mime header names
810 * @return an <code>Iterator</code> over all values matching these headers
811 */
812 public java.util.Iterator getMatchingMimeHeaders( final String[] match){
813 return mimeHeaders.getMatchingHeaders(match);
814 }
815
816 /**
817 * Get all headers that do not match.
818 *
819 * @param match an array of <code>String</code>s giving mime header names
820 * @return an <code>Iterator</code> over all values not matching these
821 * headers
822 */
823 public java.util.Iterator getNonMatchingMimeHeaders( final String[] match){
824 return mimeHeaders.getNonMatchingHeaders(match);
825 }
826
827 /**
828 * Sets the content of the <CODE>SOAPEnvelope</CODE> object
829 * with the data from the given <CODE>Source</CODE> object.
830 * @param source javax.xml.transform.Source</CODE> object with the data to
831 * be set
832 * @throws SOAPException if there is a problem in
833 * setting the source
834 * @see #getContent() getContent()
835 */
836 public void setContent(Source source) throws SOAPException {
837 if(source == null)
838 throw new SOAPException(Messages.getMessage("illegalArgumentException00"));
839
840 // override the checks in HandlerChainImpl for JAXRPCHandler kludge
841 MessageContext ctx = getMessage().getMessageContext();
842 if (ctx != null) {
843 ctx.setProperty(org.apache.axis.SOAPPart.ALLOW_FORM_OPTIMIZATION,
844 Boolean.TRUE);
845 }
846
847 contentSource = source;
848 InputSource in = org.apache.axis.utils.XMLUtils.sourceToInputSource(contentSource);
849 InputStream is = in.getByteStream();
850 if(is != null) {
851 setCurrentMessage(is, FORM_INPUTSTREAM);
852 } else {
853 Reader r = in.getCharacterStream();
854 if(r == null) {
855 throw new SOAPException(Messages.getMessage("noCharacterOrByteStream"));
856 }
857 BufferedReader br = new BufferedReader(r);
858 String line = null;
859 StringBuffer sb = new StringBuffer();
860 try {
861 while((line = br.readLine()) != null) {
862 sb.append(line);
863 }
864 } catch (IOException e) {
865 throw new SOAPException(Messages.getMessage("couldNotReadFromCharStream"), e);
866 }
867 setCurrentMessage(sb.toString(), FORM_STRING);
868 }
869 }
870
871 /**
872 * Returns the content of the SOAPEnvelope as a JAXP <CODE>
873 * Source</CODE> object.
874 * @return the content as a <CODE>
875 * javax.xml.transform.Source</CODE> object
876 * @throws SOAPException if the implementation cannot
877 * convert the specified <CODE>Source</CODE> object
878 * @see #setContent(javax.xml.transform.Source) setContent(javax.xml.transform.Source)
879 */
880 public Source getContent() throws SOAPException {
881 if(contentSource == null) {
882 switch(currentForm) {
883 case FORM_STRING:
884 String s = (String) currentMessage;
885 contentSource = new StreamSource(new StringReader(s));
886 break;
887 case FORM_INPUTSTREAM:
888 contentSource =
889 new StreamSource((InputStream) currentMessage);
890 break;
891 case FORM_SOAPENVELOPE:
892 SOAPEnvelope se = (SOAPEnvelope) currentMessage;
893 try {
894 contentSource = new DOMSource(se.getAsDocument());
895 } catch (Exception e) {
896 throw new SOAPException(Messages.getMessage("errorGetDocFromSOAPEnvelope"),
897 e);
898 }
899 break;
900 case FORM_OPTIMIZED:
901 try {
902 ByteArrayInputStream baos = new ByteArrayInputStream(((ByteArray) currentMessage).toByteArray());
903 contentSource = new StreamSource(baos);
904 } catch (IOException e) {
905 throw new SOAPException(Messages.getMessage("errorGetDocFromSOAPEnvelope"),
906 e);
907 }
908 break;
909 case FORM_BYTES:
910 byte[] bytes = (byte[]) currentMessage;
911 contentSource =
912 new StreamSource(new ByteArrayInputStream(bytes));
913 break;
914 case FORM_BODYINSTREAM:
915 contentSource =
916 new StreamSource((InputStream) currentMessage);
917 break;
918 }
919 }
920 return contentSource;
921 }
922
923 /**
924 * Retrieves all the headers for this <CODE>SOAPPart</CODE>
925 * object as an iterator over the <CODE>MimeHeader</CODE>
926 * objects.
927 * @return an <CODE>Iterator</CODE> object with all of the Mime
928 * headers for this <CODE>SOAPPart</CODE> object
929 */
930 public Iterator getAllMimeHeaders() {
931 return mimeHeaders.getAllHeaders();
932 }
933
934 /**
935 * Changes the first header entry that matches the given
936 * header name so that its value is the given value, adding a
937 * new header with the given name and value if no existing
938 * header is a match. If there is a match, this method clears
939 * all existing values for the first header that matches and
940 * sets the given value instead. If more than one header has
941 * the given name, this method removes all of the matching
942 * headers after the first one.
943 *
944 * <P>Note that RFC822 headers can contain only US-ASCII
945 * characters.</P>
946 * @param name a <CODE>String</CODE> giving the
947 * header name for which to search
948 * @param value a <CODE>String</CODE> giving the
949 * value to be set. This value will be substituted for the
950 * current value(s) of the first header that is a match if
951 * there is one. If there is no match, this value will be
952 * the value for a new <CODE>MimeHeader</CODE> object.
953 * @ throws java.lang.IllegalArgumentException if
954 * there was a problem with the specified mime header name
955 * or value
956 * @see #getMimeHeader(java.lang.String) getMimeHeader(java.lang.String)
957 */
958 public void setMimeHeader(String name, String value) {
959 mimeHeaders.setHeader(name,value);
960 }
961
962 /**
963 * Gets all the values of the <CODE>MimeHeader</CODE> object
964 * in this <CODE>SOAPPart</CODE> object that is identified by
965 * the given <CODE>String</CODE>.
966 * @param name the name of the header; example:
967 * "Content-Type"
968 * @return a <CODE>String</CODE> array giving all the values for
969 * the specified header
970 * @see #setMimeHeader(java.lang.String, java.lang.String) setMimeHeader(java.lang.String, java.lang.String)
971 */
972 public String[] getMimeHeader(String name) {
973 return mimeHeaders.getHeader(name);
974 }
975
976 /**
977 * Removes all the <CODE>MimeHeader</CODE> objects for this
978 * <CODE>SOAPEnvelope</CODE> object.
979 */
980 public void removeAllMimeHeaders() {
981 mimeHeaders.removeAllHeaders();
982 }
983
984 /**
985 * Removes all MIME headers that match the given name.
986 * @param header a <CODE>String</CODE> giving
987 * the name of the MIME header(s) to be removed
988 */
989 public void removeMimeHeader(String header) {
990 mimeHeaders.removeHeader(header);
991 }
992
993 /**
994 * Gets the <CODE>SOAPEnvelope</CODE> object associated with
995 * this <CODE>SOAPPart</CODE> object. Once the SOAP envelope is
996 * obtained, it can be used to get its contents.
997 * @return the <CODE>SOAPEnvelope</CODE> object for this <CODE>
998 * SOAPPart</CODE> object
999 * @throws SOAPException if there is a SOAP error
1000 */
1001 public javax.xml.soap.SOAPEnvelope getEnvelope() throws SOAPException {
1002 try {
1003 return getAsSOAPEnvelope();
1004 } catch (AxisFault af) {
1005 throw new SOAPException(af);
1006 }
1007 }
1008
1009 /**
1010 * Implementation of org.w3c.Document
1011 * Most of methods will be implemented using the delgate
1012 * instance of SOAPDocumentImpl
1013 * This is for two reasons:
1014 * - possible change of message classes, by extenstion of xerces implementation
1015 * - we cannot extends SOAPPart (multiple inheritance),
1016 * since it is defined as Abstract class
1017 * ***********************************************************
1018 */
1019
1020 private Document document = new SOAPDocumentImpl(this);
1021 /**
1022 * @since SAAJ 1.2
1023 */
1024 public Document getSOAPDocument(){
1025 if(document == null){
1026 document = new SOAPDocumentImpl(this);
1027 }
1028 return document;
1029 }
1030
1031 /**
1032 * @return
1033 */
1034 public DocumentType getDoctype(){
1035 return document.getDoctype();
1036 }
1037
1038 /**
1039 * @return
1040 */
1041 public DOMImplementation getImplementation(){
1042 return document.getImplementation();
1043 }
1044
1045 /**
1046 * SOAPEnvelope is the Document Elements of this XML docuement
1047 */
1048 protected Document mDocument;
1049
1050 public Element getDocumentElement()
1051 {
1052 try{
1053 return getEnvelope();
1054 }catch(SOAPException se){
1055 return null;
1056 }
1057 }
1058
1059 /**
1060 *
1061 * @param tagName
1062 * @return
1063 * @throws DOMException
1064 */
1065 public Element createElement(String tagName) throws DOMException {
1066 return document.createElement(tagName);
1067 }
1068
1069 public DocumentFragment createDocumentFragment() {
1070 return document.createDocumentFragment();
1071 }
1072
1073 public Text createTextNode(String data) {
1074 return document.createTextNode(data);
1075 }
1076
1077 public Comment createComment(String data){
1078 return document.createComment(data);
1079 }
1080
1081 public CDATASection createCDATASection(String data) throws DOMException {
1082 return document.createCDATASection(data);
1083 }
1084
1085 public ProcessingInstruction createProcessingInstruction(String target, String data)
1086 throws DOMException {
1087 return document.createProcessingInstruction(target,data);
1088 }
1089
1090 public Attr createAttribute(String name)throws DOMException {
1091 return document.createAttribute(name);
1092 }
1093
1094 public EntityReference createEntityReference(String name) throws DOMException {
1095 return document.createEntityReference(name);
1096 }
1097
1098 public NodeList getElementsByTagName(String tagname) {
1099 return document.getElementsByTagName(tagname);
1100 }
1101
1102 public Node importNode(Node importedNode, boolean deep)
1103 throws DOMException {
1104 return document.importNode(importedNode, deep);
1105 }
1106
1107 public Element createElementNS(String namespaceURI, String qualifiedName)
1108 throws DOMException {
1109 return document.createElementNS(namespaceURI, qualifiedName);
1110 }
1111
1112 public Attr createAttributeNS(String namespaceURI, String qualifiedName)
1113 throws DOMException {
1114 return document.createAttributeNS(namespaceURI, qualifiedName);
1115 }
1116
1117 public NodeList getElementsByTagNameNS(String namespaceURI, String localName) {
1118 return document.getElementsByTagNameNS(namespaceURI,localName);
1119 }
1120
1121 public Element getElementById(String elementId){
1122 return document.getElementById(elementId);
1123 }
1124
1125 /////////////////////////////////////////////////////////////
1126
1127 public String getEncoding()
1128 {
1129 return currentEncoding;
1130 }
1131
1132 public void setEncoding(String s)
1133 {
1134 currentEncoding = s;
1135 }
1136
1137 public boolean getStandalone()
1138 {
1139 throw new UnsupportedOperationException("Not yet implemented.71");
1140 }
1141
1142
1143 public void setStandalone(boolean flag)
1144 {
1145 throw new UnsupportedOperationException("Not yet implemented.72");
1146 }
1147
1148 public boolean getStrictErrorChecking()
1149 {
1150 throw new UnsupportedOperationException("Not yet implemented.73");
1151 }
1152
1153
1154 public void setStrictErrorChecking(boolean flag)
1155 {
1156 throw new UnsupportedOperationException("Not yet implemented. 74");
1157 }
1158
1159
1160 public String getVersion()
1161 {
1162 throw new UnsupportedOperationException("Not yet implemented. 75");
1163 }
1164
1165
1166 public void setVersion(String s)
1167 {
1168 throw new UnsupportedOperationException("Not yet implemented.76");
1169 }
1170
1171
1172 public Node adoptNode(Node node)
1173 throws DOMException
1174 {
1175 throw new UnsupportedOperationException("Not yet implemented.77");
1176 }
1177
1178 /**
1179 * Node Implementation
1180 */
1181
1182 public String getNodeName(){
1183 return document.getNodeName();
1184 }
1185
1186 public String getNodeValue() throws DOMException {
1187 return document.getNodeValue();
1188 }
1189
1190 public void setNodeValue(String nodeValue) throws DOMException{
1191 document.setNodeValue(nodeValue);
1192 }
1193
1194 public short getNodeType() {
1195 return document.getNodeType();
1196 }
1197
1198 public Node getParentNode(){
1199 return document.getParentNode();
1200 }
1201
1202 public NodeList getChildNodes() {
1203 return document.getChildNodes();
1204 }
1205
1206 public Node getFirstChild() {
1207 return document.getFirstChild();
1208 }
1209
1210 public Node getLastChild(){
1211 return document.getLastChild();
1212 }
1213
1214 public Node getPreviousSibling(){
1215 return document.getPreviousSibling();
1216 }
1217
1218 public Node getNextSibling(){
1219 return document.getNextSibling();
1220 }
1221
1222 public NamedNodeMap getAttributes(){
1223 return document.getAttributes();
1224 }
1225
1226 public Document getOwnerDocument(){
1227 return document.getOwnerDocument();
1228 }
1229
1230 public Node insertBefore(Node newChild, Node refChild) throws DOMException {
1231 return document.insertBefore(newChild, refChild);
1232 }
1233
1234 public Node replaceChild(Node newChild, Node oldChild) throws DOMException {
1235 return document.replaceChild(newChild, oldChild);
1236 }
1237
1238 public Node removeChild(Node oldChild) throws DOMException {
1239 return document.removeChild(oldChild);
1240 }
1241
1242 public Node appendChild(Node newChild) throws DOMException {
1243 return document.appendChild(newChild);
1244 }
1245
1246 public boolean hasChildNodes(){
1247 return document.hasChildNodes();
1248 }
1249 public Node cloneNode(boolean deep) {
1250 return document.cloneNode(deep);
1251 }
1252
1253 public void normalize(){
1254 document.normalize();
1255 }
1256
1257 public boolean isSupported(String feature, String version){
1258 return document.isSupported(feature, version);
1259 }
1260
1261 public String getNamespaceURI() {
1262 return document.getNamespaceURI();
1263 }
1264
1265 public String getPrefix() {
1266 return document.getPrefix();
1267 }
1268
1269 public void setPrefix(String prefix) throws DOMException {
1270 document.setPrefix(prefix);
1271 }
1272 public String getLocalName() {
1273 return document.getLocalName();
1274 }
1275
1276 public boolean hasAttributes(){
1277 return document.hasAttributes();
1278 }
1279
1280 public boolean isBodyStream() {
1281 return (currentForm == SOAPPart.FORM_INPUTSTREAM || currentForm == SOAPPart.FORM_BODYINSTREAM);
1282 }
1283}
1284