View Javadoc

1   /*
2    *  Copyright (c) 2008 Rodrigo Ruiz
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  package org.apache.axis.message.addressing;
17  
18  import java.util.ArrayList;
19  import java.util.Iterator;
20  import java.util.List;
21  
22  import javax.xml.namespace.QName;
23  import javax.xml.soap.Name;
24  import javax.xml.soap.SOAPEnvelope;
25  import javax.xml.soap.SOAPException;
26  import javax.xml.soap.SOAPHeader;
27  import javax.xml.soap.SOAPHeaderElement;
28  
29  import org.apache.axis.AxisFault;
30  import org.apache.axis.MessageContext;
31  import org.apache.axis.message.MessageElement;
32  import org.apache.axis.message.addressing.util.AddressingUtils;
33  import org.apache.axis.message.addressing.util.TextExtractor;
34  import org.apache.axis.types.URI;
35  import org.apache.axis.types.URI.MalformedURIException;
36  import org.apache.commons.logging.Log;
37  import org.apache.commons.logging.LogFactory;
38  import org.w3c.dom.Element;
39  
40  /**
41   * Represents a set of message addressing headers as defined by the
42   * WS-Addressing specification.
43   *
44   * @author Davanum Srinivas
45   * @author Rodrigo Ruiz
46   * @version $Revision: 14 $
47   */
48  public class AddressingHeaders {
49  
50    /**
51     * Class logger.
52     */
53    private static final Log LOG = LogFactory.getLog(AddressingHeaders.class);
54  
55    /**
56     * Are we using the W3C spec rules? (no ref props, etc...)
57     */
58    public boolean isW3CVersion;
59  
60    /**
61     * Field action.
62     */
63    private Action action;
64  
65    /**
66     * Field replyTo.
67     */
68    private ReplyTo replyTo;
69  
70    /**
71     * Field to.
72     */
73    private To to;
74  
75    /**
76     * Field faultTo.
77     */
78    private FaultTo faultTo;
79  
80    /**
81     * Field from.
82     */
83    private From from;
84  
85    /**
86     * Field recipient.
87     */
88    private Recipient recipient;
89  
90    /**
91     * Field messageID.
92     */
93    private MessageID messageID;
94  
95    /**
96     * Field relatesTo.
97     */
98    private List<RelatesTo> relatesTo;
99  
100   /**
101    * Field ReferenceProperties.
102    */
103   private ReferencePropertiesType referenceProperties;
104 
105   /**
106    * Field ReferenceParameters.
107    */
108   private ReferenceParametersType referenceParameters;
109 
110   /**
111    * Option to set mustUnderstand="true" on the headers or not.
112    */
113   private boolean setMustUnderstand;
114 
115   /**
116    * If there is a fault while building the headers, it gets put here.
117    */
118   private AddressingHeaderFault addrHeaderFault;
119 
120   /**
121    * Constructor AddressingHeaders.
122    */
123   public AddressingHeaders() {
124     this.referenceProperties = new ReferencePropertiesType();
125     this.referenceParameters = new ReferenceParametersType();
126     this.relatesTo = new ArrayList<RelatesTo>();
127   }
128 
129   /**
130    * Copy constructor.
131    *
132    * @param epr Reference to copy from
133    */
134   public AddressingHeaders(EndpointReference epr) {
135     this.to = new To(epr.getAddress());
136     this.referenceProperties = epr.getProperties();
137     this.referenceParameters = epr.getParameters();
138   }
139 
140   /**
141    * Constructor AddressingHeaders.
142    *
143    * @param env Envelope to get the headers from
144    * @throws Exception If an error occurs
145    */
146   public AddressingHeaders(SOAPEnvelope env) throws Exception {
147     this(env, null, true, false, true, new ArrayList<QName>(0));
148   }
149 
150   /**
151    * Constructor AddressingHeaders.
152    *
153    * @param env        Parent Envelope
154    * @param process    Should the headers be marked as processed
155    * @param remove     Should the headers be removed after processing
156    * @throws Exception If an error occurs
157    */
158   public AddressingHeaders(SOAPEnvelope env, boolean process, boolean remove)
159     throws Exception {
160     this(env, null, process, remove, true, new ArrayList<QName>(0));
161   }
162 
163   /**
164    * Constructor AddressingHeaders.
165    *
166    * @param env        Parent Envelope
167    * @param actorURI   Actor URI
168    * @param process    Should the headers be marked as processed
169    * @param remove     Should the headers be removed after processing
170    * @throws Exception If an error occurs
171    */
172   public AddressingHeaders(SOAPEnvelope env, String actorURI, boolean process,
173     boolean remove) throws Exception {
174     this(env, actorURI, process, remove, true, new ArrayList<QName>(0));
175   }
176 
177   /**
178    * Constructor AddressingHeaders.
179    *
180    * @param env The SOAP Envelope
181    * @param actorURI The SOAP Actor URI
182    * @param process Should the headers be marked as processed
183    * @param remove Should the headers be removed after processing
184    * @param setMustUnderstand whether or not to set mustUnderstand="true" on the
185    *        headers
186    * @param allowNonSpecificActions whether or not to allow a non-specific
187    *        Action URI
188    * @param refPropsQNames A list of QNames for reference properties. If null
189    *        all non-WSA headers will be added as reference properties. If an
190    *        empty list is passed than no headers will be added reference
191    *        properties (default). If non empty list of qnames is passed then
192    *        only headers matching the qname in the list will be added as
193    *        reference properties.
194    * @throws Exception
195    */
196   public AddressingHeaders(SOAPEnvelope env, String actorURI, boolean process,
197     boolean remove, boolean setMustUnderstand, boolean allowNonSpecificActions,
198     List<QName> refPropsQNames) throws Exception {
199     this();
200 
201     this.setMustUnderstand = setMustUnderstand;
202 
203     SOAPHeader header = env.getHeader();
204     if (header == null) {
205       return;
206     }
207 
208     Iterator<?> iter = header.examineHeaderElements(actorURI);
209 
210     while (iter.hasNext()) {
211       SOAPHeaderElement elem = (SOAPHeaderElement) iter.next();
212       if (addHeader(elem, allowNonSpecificActions, refPropsQNames)) {
213 
214         // !!! We shouldn't be removing these headers here. The only
215         // reason to remove them is for use as an intermediary, and
216         // that should work via the infrastructure, NOT by removing
217         // headers here. Removing them here just means other handlers
218         // which run after this one don't see the whole message, which
219         // is bad. Change awaiting discussion on fx-dev. --Glen
220 
221         // must have found one
222         if (remove) {
223           elem.detachNode();
224         }
225 
226         // axis specific call
227         if (process && elem instanceof org.apache.axis.message.SOAPHeaderElement) {
228           ((org.apache.axis.message.SOAPHeaderElement) elem).setProcessed(true);
229         }
230 
231       }
232     }
233   }
234 
235   /**
236    * Constructor AddressingHeaders.
237    *
238    * @param env The SOAP Envelope
239    * @param actorURI The SOAP Actor URI
240    * @param process Should the headers be marked as processed
241    * @param remove Should the headers be removed after processing
242    * @param setMustUnderstand whether or not to set mustUnderstand="true" on the
243    *        headers
244    * @param refPropsQNames A list of QNames for reference properties. If null
245    *        all non-WSA headers will be added as reference properties. If an
246    *        empty list is passed than no headers will be added reference
247    *        properties (default). If non empty list of qnames is passed then
248    *        only headers matching the qname in the list will be added as
249    *        reference properties.
250    * @throws Exception
251    */
252   public AddressingHeaders(SOAPEnvelope env, String actorURI, boolean process,
253     boolean remove, boolean setMustUnderstand, List<QName> refPropsQNames)
254     throws Exception {
255     this(env, actorURI, process, remove, setMustUnderstand, false, refPropsQNames);
256   }
257 
258   /**
259    * Sets the Action header element, checking duplicates.
260    *
261    * @param elem Element to set
262    * @param allowNonSpecificActions Whether to allow relative Action URIs or not
263    * @throws MalformedURIException If an invalid URI is found
264    */
265   private void addAction(SOAPHeaderElement elem, boolean allowNonSpecificActions)
266     throws MalformedURIException {
267     // set the WSA namespace URI in the MessageContext,
268     // so we'll know how to serialize types associated
269     // with this request
270     MessageContext msgContext = MessageContext.getCurrentContext();
271     if (msgContext != null) {
272       msgContext.setProperty(Constants.ENV_ADDRESSING_NAMESPACE_URI,
273                              elem.getElementName().getURI());
274     }
275 
276     if (this.action != null) {
277       this.addrHeaderFault = new AddressingHeaderFault("duplicate Action header",
278         AddressingHeaderFault.INVALID_CARDINALITY, Constants.ACTION);
279     }
280 
281     URI uri = new URI(TextExtractor.getText(elem), allowNonSpecificActions);
282     this.action = new Action(uri);
283   }
284 
285   /**
286    * Adds a header element to the container.
287    *
288    * @param headerElement Element to add
289    * @param refPropsQNames A list of QNames for reference properties. If null
290    *        all non-WSA headers will be added as reference properties. If an
291    *        empty list is passed than no headers will be added reference
292    *        properties (default). If non empty list of QNames is passed then
293    *        only headers matching the QName in the list will be added as
294    *        reference properties.
295    * @param allowNonSpecificActions Whether to allow relative Action URIs or not
296    * @return <tt>true</tt> if the element is an addressing header
297    */
298   private boolean addHeader(SOAPHeaderElement headerElement,
299     boolean allowNonSpecificActions, List<QName> refPropsQNames)
300     throws MalformedURIException {
301 
302     Name name = headerElement.getElementName();
303 
304     // NOTE : This might want to check consistent use of a single
305     // namespace instead of allowing multiple versions....?
306 
307     AddressingVersion version = AddressingUtils.getAddressingVersion(name.getURI());
308 
309     if (version != null) {
310       // it's a WSA header
311       this.isW3CVersion = version.isW3C();
312       String localName = name.getLocalName();
313 
314       if (localName.equals(Constants.MESSAGE_ID)) {
315         addMessageID(headerElement);
316       } else if (localName.equals(Constants.TO)) {
317         addTo(headerElement);
318       } else if (localName.equals(Constants.ACTION)) {
319         addAction(headerElement, allowNonSpecificActions);
320       } else if (localName.equals(Constants.FROM)) {
321         addFrom(headerElement);
322       } else if (localName.equals(Constants.REPLY_TO)) {
323         addReplyTo(headerElement);
324       } else if (localName.equals(Constants.FAULT_TO)) {
325         addFaultTo(headerElement);
326       } else if (localName.equals(Constants.RECIPIENT)) {
327         this.recipient = new Recipient(headerElement);
328       } else if (localName.equals(Constants.RELATES_TO)) {
329         this.relatesTo.add(new RelatesTo(headerElement));
330       } else if (localName.equals(Constants.FAULT_DETAIL)) {
331         // TODO !!
332         LOG.debug("Not done yet");
333       } else {
334         this.addrHeaderFault = new AddressingHeaderFault(
335           "Unsupported addressing header: " + localName, localName);
336       }
337       return true;
338     } else {
339       this.isW3CVersion = false;
340       // it might be a reference property (wouldn't it be easier
341       // if they were all collected under, say wsa:To?)....
342       // check if it was added to refProps
343       return this.checkReferenceP(headerElement, refPropsQNames);
344     }
345   }
346 
347   /**
348    * Sets the FaultTo header element, checking duplicates.
349    *
350    * @param elem Element to set
351    * @throws MalformedURIException If an invalid URI is found
352    */
353   private void addFaultTo(SOAPHeaderElement elem) throws MalformedURIException {
354     if (this.faultTo == null) {
355       this.faultTo = new FaultTo(elem);
356     } else {
357       // If this header is duplicated, we cannot assume the previous value is valid
358       this.faultTo = null;
359       this.addrHeaderFault = new AddressingHeaderFault(
360         AddressingHeaderFault.INVALID_CARDINALITY,
361         Constants.FAULT_TO);
362     }
363   }
364 
365   /**
366    * Sets the From header element, checking duplicates.
367    *
368    * @param elem Element to set
369    * @throws MalformedURIException If an invalid URI is found
370    */
371   private void addFrom(SOAPHeaderElement elem) throws MalformedURIException {
372     if (this.from == null) {
373       this.from = new From(elem);
374     } else {
375       this.addrHeaderFault = new AddressingHeaderFault(
376         AddressingHeaderFault.INVALID_CARDINALITY,
377         Constants.FROM);
378     }
379   }
380 
381   /**
382    * Sets the MessageID header element, checking duplicates.
383    *
384    * @param elem Element to set
385    * @throws MalformedURIException If an invalid URI is found
386    */
387   private void addMessageID(SOAPHeaderElement elem) throws MalformedURIException {
388     if (this.messageID == null) {
389       this.messageID = new MessageID(elem);
390     } else {
391       this.addrHeaderFault = new AddressingHeaderFault(
392         AddressingHeaderFault.INVALID_CARDINALITY,
393         Constants.MESSAGE_ID);
394     }
395   }
396 
397   /**
398    * Adds a reference parameter.
399    *
400    * @param param Parameter to add
401    */
402   public void addReferenceParameter(Element param) {
403     if (this.referenceParameters == null) {
404       this.referenceParameters = new ReferenceParametersType();
405     }
406     this.referenceParameters.add(param);
407   }
408 
409   /**
410    * Adds a reference parameter.
411    *
412    * @param param Parameter to add
413    */
414   public void addReferenceParameter(MessageElement param) {
415     if (this.referenceParameters == null) {
416       this.referenceParameters = new ReferenceParametersType();
417     }
418     this.referenceParameters.add(param);
419   }
420 
421   /**
422    * Adds an XML element to the referencePropeties collection.
423    *
424    * @param prop Element to add
425    */
426   public void addReferenceProperty(Element prop) {
427     if (this.referenceProperties == null) {
428       this.referenceProperties = new ReferencePropertiesType();
429     }
430     this.referenceProperties.add(prop);
431   }
432 
433   /**
434    * Adds a message element to the referencePropeties collection.
435    *
436    * @param prop Element to add
437    */
438   public void addReferenceProperty(MessageElement prop) {
439     if (this.referenceProperties == null) {
440       this.referenceProperties = new ReferencePropertiesType();
441     }
442     this.referenceProperties.add(prop);
443   }
444 
445   /**
446    * Method addRelatesTo.
447    *
448    * @param uri  Address URI
449    * @param type an IRI indicating the relationship type
450    * @throws URI.MalformedURIException If the URI is not valid
451    */
452   public void addRelatesTo(String uri, QName type) throws URI.MalformedURIException {
453     this.relatesTo.add(new RelatesTo(uri, type));
454   }
455 
456   /**
457    * Method addRelatesTo.
458    *
459    * @param uri  Address URI
460    * @param type an IRI indicating the relationship type
461    * @throws URI.MalformedURIException If the URI is not valid
462    */
463   public void addRelatesTo(String uri, String type) throws URI.MalformedURIException {
464     this.relatesTo.add(new RelatesTo(uri, type));
465   }
466 
467   /**
468    * Sets the ReplyTo header element, checking duplicates.
469    *
470    * @param elem Element to set
471    * @throws MalformedURIException If an invalid URI is found
472    */
473   private void addReplyTo(SOAPHeaderElement elem) throws MalformedURIException {
474     if (this.replyTo == null) {
475       this.replyTo = new ReplyTo(elem);
476     } else {
477       this.addrHeaderFault = new AddressingHeaderFault(
478         AddressingHeaderFault.INVALID_CARDINALITY,
479         Constants.REPLY_TO);
480     }
481   }
482 
483   /**
484    * Sets the To header element, checking duplicates.
485    *
486    * @param elem Element to set
487    * @throws MalformedURIException If an invalid URI is found
488    */
489   private void addTo(SOAPHeaderElement elem) throws MalformedURIException {
490     if (this.to == null) {
491       this.to = new To(elem);
492     } else {
493       this.addrHeaderFault = new AddressingHeaderFault(
494         AddressingHeaderFault.INVALID_CARDINALITY,
495         Constants.TO);
496     }
497   }
498 
499   /**
500    * Take a SOAP header, check if it matches one of our reference
501    * properties/parameters, if so add it to the appropriate collection.
502    *
503    * @param headerElement the header to check
504    * @param refPropQNames List of property names to match to
505    * @return true if it matched, false otherwise
506    */
507   private boolean checkReferenceP(SOAPHeaderElement headerElement,
508     List<QName> refPropQNames) {
509     Name name = headerElement.getElementName();
510     QName elementName = new QName(name.getURI(), name.getLocalName());
511 
512     // if we got to this point, the user wants deserialization of ref props.
513     // if refPropQNames was a null, it is treated as a '*' or process all
514     // headers
515     // otherwise we check to see if the element name was specified by the user
516     if (refPropQNames == null || refPropQNames.contains(elementName)) {
517       this.referenceProperties.add(headerElement);
518       return true;
519     } else {
520       return false;
521     }
522   }
523 
524   /**
525    * Method getAction.
526    *
527    * @return The action field
528    */
529   public Action getAction() {
530     return this.action;
531   }
532 
533   /**
534    * Gets the fault contained in the headers.
535    *
536    * @return A fault
537    */
538   public AxisFault getAddrHeaderFault() {
539     return this.addrHeaderFault;
540   }
541 
542   /**
543    * Method getFaultTo.
544    *
545    * @return The FaultTo end-point reference
546    */
547   public EndpointReference getFaultTo() {
548     return this.faultTo;
549   }
550 
551   /**
552    * Method getFrom.
553    *
554    * @return The from field
555    */
556   public EndpointReference getFrom() {
557     return this.from;
558   }
559 
560   /**
561    * Method getMessageID.
562    *
563    * @return The message ID
564    */
565   public MessageID getMessageID() {
566     return this.messageID;
567   }
568 
569   /**
570    * Get the reference parameters.
571    *
572    * @return a List of reference parameters (MessageElements)
573    */
574   public ReferenceParametersType getReferenceParameters() {
575     return this.referenceParameters;
576   }
577 
578   /**
579    * Method getReferenceProperties.
580    *
581    * @return referenceProperties
582    */
583   public ReferencePropertiesType getReferenceProperties() {
584     return this.referenceProperties;
585   }
586 
587   /**
588    * Method getRelatesTo.
589    *
590    * @return The list of RelatesTo fields
591    */
592   public List<RelatesTo> getRelatesTo() {
593     return this.relatesTo;
594   }
595 
596   /**
597    * Method getReplyTo.
598    *
599    * @return The ReplyTo end-point reference
600    */
601   public EndpointReference getReplyTo() {
602     return this.replyTo;
603   }
604 
605   /**
606    * Method getTo.
607    *
608    * @return The To field
609    */
610   public To getTo() {
611     return this.to;
612   }
613 
614   /**
615    * Gets the value of the "setMustUnderstand" flag.
616    *
617    * @return The flag value
618    */
619   public boolean isSetMustUnderstand() {
620     return this.setMustUnderstand;
621   }
622 
623   /**
624    * Converts the specified object into a SOAPHeaderElement instance.
625    *
626    * @param refP Instance to convert
627    * @return Resulting header element
628    * @throws SOAPException If an error occurs
629    */
630   private SOAPHeaderElement makeSOAPHeader(Object refP) throws SOAPException {
631     SOAPHeaderElement element;
632     if (refP instanceof SOAPHeaderElement) {
633       // already a SOAPHeaderElement
634       element = (SOAPHeaderElement) refP;
635     } else if (refP instanceof MessageElement) {
636       // conversion from MessageElement to SOAPHeaderElement
637       MessageElement msgElement = (MessageElement) refP;
638       try {
639         element = new org.apache.axis.message.SOAPHeaderElement(msgElement.getAsDOM());
640       } catch (SOAPException e) {
641         throw e;
642       } catch (Exception e) {
643         throw new SOAPException(e);
644       }
645     } else if (refP instanceof Element) {
646       Element refPropElement = (Element) refP;
647       // conversion from DOM Element
648       element = new org.apache.axis.message.SOAPHeaderElement(refPropElement);
649     } else {
650       throw new SOAPException(refP.getClass().getName());
651     }
652     return element;
653   }
654 
655   /**
656    * Serialize the reference properties/parameters in the SOAP Header.
657    *
658    * @param env       Envelope to modify
659    * @param refPs     List of reference properties
660    * @param actorURI  Actor URI
661    * @param addAttribute Whether to mark elements as reference properties (W3C version)
662    */
663   private void serializeReferencePs(SOAPEnvelope env, List<MessageElement> refPs,
664     String actorURI, boolean addAttribute) throws SOAPException {
665     // If no referenceProps are available, we are done
666     if (refPs == null || refPs.size() == 0) {
667       return;
668     }
669 
670     SOAPHeaderElement element;
671     SOAPHeader header = env.getHeader();
672     if (header == null) {
673       header = env.addHeader();
674     }
675 
676     // Add each ref property to SOAP Header
677     for (MessageElement refProp : refPs) {
678       element = this.makeSOAPHeader(refProp);
679       element.setActor(actorURI);
680 
681       // If we're supposed to mark this as a refP, do so (W3C version)
682       if (addAttribute) {
683         element.addAttribute(Constants.ATTR_REFP, "true");
684       }
685       header.addChildElement(element);
686     }
687   }
688 
689   /**
690    * Method setAction.
691    *
692    * @param action Action field
693    */
694   public void setAction(Action action) {
695     this.action = action;
696   }
697 
698   /**
699    * Sets the action URI.
700    *
701    * @param uri Action URI
702    * @throws Exception If an error occurs
703    */
704   public void setAction(String uri) throws Exception {
705     this.action = new Action(new URI(uri));
706   }
707 
708   /**
709    * Sets the action URI.
710    *
711    * @param uri Action URI
712    */
713   public void setAction(URI uri) {
714     this.action = (uri == null) ? null : new Action(uri);
715   }
716 
717   /**
718    * Method setFaultTo.
719    *
720    * @param epr The FaultTo end-point reference
721    */
722   public void setFaultTo(EndpointReference epr) {
723     this.faultTo = new FaultTo(epr);
724   }
725 
726   /**
727    * Method setFrom.
728    *
729    * @param ref From end-point reference
730    */
731   public void setFrom(EndpointReference ref) {
732     this.from = new From(ref);
733   }
734 
735   /**
736    * Method setMessageID.
737    *
738    * @param messageID The message ID to set
739    */
740   public void setMessageID(MessageID messageID) {
741     this.messageID = messageID;
742   }
743 
744   /**
745    * Sets the reference parameters.
746    *
747    * @param params Reference parameters bean
748    */
749   public void setReferenceParameters(ReferenceParametersType params) {
750     this.referenceParameters = params;
751   }
752 
753   /**
754    * Method setReferenceProperties.
755    *
756    * @param props The properties to set
757    */
758   public void setReferenceProperties(ReferencePropertiesType props) {
759     this.referenceProperties = props;
760   }
761 
762   /**
763    * Set the collection of RelatesToProperties. Not additive, this replaces the
764    * current collection.
765    *
766    * @param v List of RelatesToProperties
767    */
768   public void setRelatesTo(List<RelatesTo> v) {
769     this.relatesTo.clear();
770     this.relatesTo.addAll(v);
771   }
772 
773   /**
774    * Method setReplyTo.
775    *
776    * @param ref The ReplyTo end-point reference
777    */
778   public void setReplyTo(EndpointReference ref) {
779     this.replyTo = new ReplyTo(ref);
780   }
781 
782   /**
783    * Sets the "SetMustUnderstand" flag.
784    *
785    * @param setMustUnderstand Flag value
786    */
787   public void setSetMustUnderstand(boolean setMustUnderstand) {
788     this.setMustUnderstand = setMustUnderstand;
789   }
790 
791   /**
792    * Method setTo.
793    *
794    * @param uri To URI
795    */
796   public void setTo(AttributedURI uri) {
797     this.to = new To(uri);
798   }
799 
800   /**
801    * Method setTo.
802    *
803    * @param to The To field
804    */
805   public void setTo(To to) {
806     this.to = to;
807   }
808 
809   /**
810    * Adds these addressing headers to the specified SOAP envelope.
811    *
812    * @param env Envelope to add to
813    * @throws Exception If an error occurs
814    */
815   public void toEnvelope(SOAPEnvelope env) throws Exception {
816     this.toEnvelope(env, null);
817   }
818 
819   /**
820    * Adds these addressing headers to the specified SOAP envelope.
821    *
822    * @param env Envelope to add to
823    * @param actorURI Actor URI
824    * @throws javax.xml.soap.SOAPException
825    */
826   public void toEnvelope(SOAPEnvelope env, String actorURI) throws SOAPException {
827 
828     AddressingVersion version = AddressingUtils.getAddressingVersion();
829 
830     if (env.getNamespaceURI(Constants.NS_PREFIX_ADDRESSING) == null) {
831       env.addNamespaceDeclaration(Constants.NS_PREFIX_ADDRESSING,
832                                   version.getNamespace());
833     }
834 
835     AddressingUtils.removeHeaders(env.getHeader(), actorURI);
836 
837     addItem(version, env, actorURI, this.messageID);
838     addItem(version, env, actorURI, this.to);
839     addItem(version, env, actorURI, this.action);
840     addItem(version, env, actorURI, this.from);
841     addItem(version, env, actorURI, this.replyTo);
842     addItem(version, env, actorURI, this.faultTo);
843     addItem(version, env, actorURI, this.recipient);
844 
845     if (this.relatesTo != null) {
846       for (int i = 0; i < this.relatesTo.size(); i++) {
847         AddressingHeaderItem item = this.relatesTo.get(i);
848         addItem(version, env, actorURI, item);
849       }
850     }
851 
852     if (this.referenceProperties != null && this.referenceProperties.size() > 0) {
853       this.serializeReferencePs(env, this.referenceProperties, actorURI, false);
854     }
855 
856     if (this.referenceParameters != null && this.referenceParameters.size() > 0) {
857       this.serializeReferencePs(env, this.referenceParameters, actorURI,
858         this.isW3CVersion);
859     }
860   }
861 
862   /**
863    * Adds a SOAPHeaderElement to the headers of the current envelope.
864    *
865    * @param version   WS-Addressing version to use
866    * @param env       Envelope to modify
867    * @param actorURI  Actor URI
868    * @param item      Element to add
869    * @throws SOAPException If an error occurs
870    */
871   private void addItem(AddressingVersion version, SOAPEnvelope env, String actorURI,
872     AddressingHeaderItem item) throws SOAPException {
873     if (item != null) {
874       SOAPHeaderElement elem = item.toSOAPHeaderElement(version, env, actorURI);
875       elem.setMustUnderstand(this.setMustUnderstand);
876     }
877   }
878 }