View Javadoc

1   /*
2    * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
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.opensaml.ws.soap.util;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Set;
24  import java.util.Map.Entry;
25  
26  import javax.xml.namespace.QName;
27  
28  import org.opensaml.ws.message.MessageContext;
29  import org.opensaml.ws.soap.soap11.ActorBearing;
30  import org.opensaml.ws.soap.soap11.Detail;
31  import org.opensaml.ws.soap.soap11.EncodingStyleBearing;
32  import org.opensaml.ws.soap.soap11.Envelope;
33  import org.opensaml.ws.soap.soap11.Fault;
34  import org.opensaml.ws.soap.soap11.FaultActor;
35  import org.opensaml.ws.soap.soap11.FaultCode;
36  import org.opensaml.ws.soap.soap11.FaultString;
37  import org.opensaml.ws.soap.soap11.Header;
38  import org.opensaml.ws.soap.soap11.MustUnderstandBearing;
39  import org.opensaml.xml.AttributeExtensibleXMLObject;
40  import org.opensaml.xml.Configuration;
41  import org.opensaml.xml.XMLObject;
42  import org.opensaml.xml.XMLObjectBuilderFactory;
43  import org.opensaml.xml.schema.XSBooleanValue;
44  import org.opensaml.xml.util.AttributeMap;
45  import org.opensaml.xml.util.DatatypeHelper;
46  import org.opensaml.xml.util.LazyList;
47  import org.opensaml.xml.util.XMLHelper;
48  
49  /**
50   * Helper methods for working with SOAP.
51   */
52  public final class SOAPHelper {
53  
54      /**
55       * Private constructor.
56       */
57      private SOAPHelper() {
58      }
59  
60      /**
61       * Adds a <code>soap11:mustUnderstand</code> attribute to the given SOAP object.
62       * 
63       * @param soapObject the SOAP object to add the attribute to
64       * @param mustUnderstand whether mustUnderstand is true or false
65       */
66      public static void addSOAP11MustUnderstandAttribute(XMLObject soapObject, boolean mustUnderstand) {
67          if (soapObject instanceof MustUnderstandBearing) {
68              ((MustUnderstandBearing) soapObject).setSOAP11MustUnderstand(new XSBooleanValue(mustUnderstand, true));
69          } else if (soapObject instanceof AttributeExtensibleXMLObject) {
70              ((AttributeExtensibleXMLObject) soapObject).getUnknownAttributes().put(
71                      MustUnderstandBearing.SOAP11_MUST_UNDERSTAND_ATTR_NAME,
72                      new XSBooleanValue(mustUnderstand, true).toString());
73          } else {
74              throw new IllegalArgumentException("Specified object was neither MustUnderBearing nor AttributeExtensible");
75          }
76      }
77  
78      /**
79       * Get the <code>soap11:mustUnderstand</code> attribute from a given SOAP object.
80       * 
81       * @param soapObject the SOAP object to add the attribute to
82       * 
83       * @return value of the mustUnderstand attribute, or false if not present
84       */
85      public static boolean getSOAP11MustUnderstandAttribute(XMLObject soapObject) {
86          if (soapObject instanceof MustUnderstandBearing) {
87              XSBooleanValue value = ((MustUnderstandBearing) soapObject).isSOAP11MustUnderstandXSBoolean();
88              if (value != null) {
89                  return value.getValue();
90              }
91          }
92          if (soapObject instanceof AttributeExtensibleXMLObject) {
93              String value = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject) soapObject)
94                      .getUnknownAttributes().get(MustUnderstandBearing.SOAP11_MUST_UNDERSTAND_ATTR_NAME));
95              return DatatypeHelper.safeEquals("1", value);
96          }
97          return false;
98      }
99  
100     /**
101      * Adds a <code>soap11:actor</code> attribute to the given SOAP object.
102      * 
103      * @param soapObject the SOAP object to add the attribute to
104      * @param actorURI the URI of the actor
105      */
106     public static void addSOAP11ActorAttribute(XMLObject soapObject, String actorURI) {
107         if (soapObject instanceof ActorBearing) {
108             ((ActorBearing) soapObject).setSOAP11Actor(actorURI);
109         } else if (soapObject instanceof AttributeExtensibleXMLObject) {
110             ((AttributeExtensibleXMLObject) soapObject).getUnknownAttributes().put(ActorBearing.SOAP11_ACTOR_ATTR_NAME,
111                     actorURI);
112         } else {
113             throw new IllegalArgumentException("Specified object was neither ActorBearing nor AttributeExtensible");
114         }
115     }
116 
117     /**
118      * Gets the <code>soap11:actor</code> attribute from a given SOAP object.
119      * 
120      * @param soapObject the SOAP object to add the attribute to
121      * 
122      * @return the value of the actor attribute, or null if not present
123      */
124     public static String getSOAP11ActorAttribute(XMLObject soapObject) {
125         String value = null;
126         if (soapObject instanceof ActorBearing) {
127             value = DatatypeHelper.safeTrimOrNullString(((ActorBearing) soapObject).getSOAP11Actor());
128             if (value != null) {
129                 return value;
130             }
131         }
132         if (soapObject instanceof AttributeExtensibleXMLObject) {
133             value = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject) soapObject)
134                     .getUnknownAttributes().get(ActorBearing.SOAP11_ACTOR_ATTR_NAME));
135             return value;
136         }
137         return null;
138     }
139 
140     /**
141      * Adds a single encoding style to the given SOAP object. If an existing <code>soap11:encodingStyle</code> attribute
142      * is present, the given style will be added to the existing list.
143      * 
144      * @param soapObject the SOAP object to add the attribute to
145      * @param encodingStyle the encoding style to add
146      */
147     public static void addSOAP11EncodingStyle(XMLObject soapObject, String encodingStyle) {
148         if (soapObject instanceof EncodingStyleBearing) {
149             EncodingStyleBearing esb = (EncodingStyleBearing) soapObject;
150             List<String> list = esb.getSOAP11EncodingStyles();
151             if (list == null) {
152                 list = new LazyList<String>();
153                 esb.setSOAP11EncodingStyles(list);
154             }
155             list.add(encodingStyle);
156         } else if (soapObject instanceof AttributeExtensibleXMLObject) {
157             AttributeMap am = ((AttributeExtensibleXMLObject) soapObject).getUnknownAttributes();
158             String list = am.get(EncodingStyleBearing.SOAP11_ENCODING_STYLE_ATTR_NAME);
159             if (list == null) {
160                 list = encodingStyle;
161             } else {
162                 list = list + " " + encodingStyle;
163             }
164             am.put(EncodingStyleBearing.SOAP11_ENCODING_STYLE_ATTR_NAME, list);
165         } else {
166             throw new IllegalArgumentException(
167                     "Specified object was neither EncodingStyleBearing nor AttributeExtensible");
168         }
169     }
170 
171     /**
172      * Adds a <code>soap11:encodingStyle</code> attribute to the given SOAP object.
173      * 
174      * @param soapObject the SOAP object to add the attribute to
175      * @param encodingStyles the list of encoding styles to add
176      */
177     public static void addSOAP11EncodingStyles(XMLObject soapObject, List<String> encodingStyles) {
178         if (soapObject instanceof EncodingStyleBearing) {
179             ((EncodingStyleBearing) soapObject).setSOAP11EncodingStyles(encodingStyles);
180         } else if (soapObject instanceof AttributeExtensibleXMLObject) {
181             ((AttributeExtensibleXMLObject) soapObject).getUnknownAttributes().put(
182                     EncodingStyleBearing.SOAP11_ENCODING_STYLE_ATTR_NAME,
183                     DatatypeHelper.listToStringValue(encodingStyles, " "));
184         } else {
185             throw new IllegalArgumentException(
186                     "Specified object was neither EncodingStyleBearing nor AttributeExtensible");
187         }
188     }
189 
190     /**
191      * Gets the list value of the <code>soap11:encodingStyle</code> attribute from the given SOAP object.
192      * 
193      * @param soapObject the SOAP object to add the attribute to
194      * 
195      * @return the list of encoding styles, or null if not present
196      */
197     public static List<String> getSOAP11EncodingStyles(XMLObject soapObject) {
198         if (soapObject instanceof EncodingStyleBearing) {
199             List<String> value = ((EncodingStyleBearing) soapObject).getSOAP11EncodingStyles();
200             if (value != null) {
201                 return value;
202             }
203         }
204         if (soapObject instanceof AttributeExtensibleXMLObject) {
205             String value = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject) soapObject)
206                     .getUnknownAttributes().get(EncodingStyleBearing.SOAP11_ENCODING_STYLE_ATTR_NAME));
207             if (value != null) {
208                 DatatypeHelper.stringToList(value, XMLHelper.LIST_DELIMITERS);
209             }
210         }
211         return null;
212     }
213 
214     /**
215      * Adds the <code>soap12:encodingStyle</code> attribute to the given soap object.
216      * 
217      * @param soapObject object to which the encoding style attribute should be added
218      * @param style the encoding style
219      */
220     public static void addSOAP12EncodingStyleAttribute(XMLObject soapObject, String style) {
221         if (soapObject instanceof org.opensaml.ws.soap.soap12.EncodingStyleBearing) {
222             ((org.opensaml.ws.soap.soap12.EncodingStyleBearing) soapObject).setSOAP12EncodingStyle(style);
223         } else if (soapObject instanceof AttributeExtensibleXMLObject) {
224             ((AttributeExtensibleXMLObject) soapObject).getUnknownAttributes().put(
225                     org.opensaml.ws.soap.soap12.EncodingStyleBearing.SOAP12_ENCODING_STYLE_ATTR_NAME, style);
226         } else {
227             throw new IllegalArgumentException(
228                     "Specified object was neither EncodingStyleBearing nor AttribtueExtensible");
229         }
230     }
231 
232     /**
233      * Gets the <code>soap12:encodingStyle</code>.
234      * 
235      * @param soapObject the SOAP object which may contain the encoding style
236      * 
237      * @return the encoding style or null if it is not set on the object
238      */
239     public static String getSOAP12EncodingStyleAttribute(XMLObject soapObject) {
240         String style = null;
241         if (soapObject instanceof org.opensaml.ws.soap.soap12.EncodingStyleBearing) {
242             style = ((org.opensaml.ws.soap.soap12.EncodingStyleBearing) soapObject).getSOAP12EncodingStyle();
243         }
244 
245         if (style == null && soapObject instanceof AttributeExtensibleXMLObject) {
246             style = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject) soapObject)
247                     .getUnknownAttributes().get(
248                             org.opensaml.ws.soap.soap12.EncodingStyleBearing.SOAP12_ENCODING_STYLE_ATTR_NAME));
249         }
250 
251         return style;
252     }
253 
254     /**
255      * Adds a <code>soap12:mustUnderstand</code> attribute to the given SOAP object.
256      * 
257      * @param soapObject the SOAP object to add the attribute to
258      * @param mustUnderstand whether mustUnderstand is true or false
259      */
260     public static void addSOAP12MustUnderstandAttribute(XMLObject soapObject, boolean mustUnderstand) {
261         if (soapObject instanceof org.opensaml.ws.soap.soap12.MustUnderstandBearing) {
262             ((org.opensaml.ws.soap.soap12.MustUnderstandBearing) soapObject)
263                     .setSOAP12MustUnderstand(new XSBooleanValue(mustUnderstand, false));
264         } else if (soapObject instanceof AttributeExtensibleXMLObject) {
265             ((AttributeExtensibleXMLObject) soapObject).getUnknownAttributes().put(
266                     org.opensaml.ws.soap.soap12.MustUnderstandBearing.SOAP12_MUST_UNDERSTAND_ATTR_NAME,
267                     new XSBooleanValue(mustUnderstand, false).toString());
268         } else {
269             throw new IllegalArgumentException("Specified object was neither MustUnderstandBearing nor AttributeExtensible");
270         }
271     }
272 
273     /**
274      * Get the <code>soap12:mustUnderstand</code> attribute from a given SOAP object.
275      * 
276      * @param soapObject the SOAP object to add the attribute to
277      * 
278      * @return value of the mustUnderstand attribute, or false if not present
279      */
280     public static boolean getSOAP12MustUnderstandAttribute(XMLObject soapObject) {
281         if (soapObject instanceof org.opensaml.ws.soap.soap12.MustUnderstandBearing) {
282             XSBooleanValue value = ((org.opensaml.ws.soap.soap12.MustUnderstandBearing) soapObject)
283                     .isSOAP12MustUnderstandXSBoolean();
284             if (value != null) {
285                 return value.getValue();
286             }
287         }
288         if (soapObject instanceof AttributeExtensibleXMLObject) {
289             String value = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject) soapObject)
290                     .getUnknownAttributes().get(
291                             org.opensaml.ws.soap.soap12.MustUnderstandBearing.SOAP12_MUST_UNDERSTAND_ATTR_NAME));
292             return DatatypeHelper.safeEquals("1", value) || DatatypeHelper.safeEquals("true", value);
293         }
294         return false;
295     }
296 
297     /**
298      * Adds a <code>soap12:relay</code> attribute to the given SOAP object.
299      * 
300      * @param soapObject the SOAP object to add the attribute to
301      * @param relay whether relay is true or false
302      */
303     public static void addSOAP12RelayAttribute(XMLObject soapObject, boolean relay) {
304         if (soapObject instanceof org.opensaml.ws.soap.soap12.RelayBearing) {
305             ((org.opensaml.ws.soap.soap12.RelayBearing) soapObject).setSOAP12Relay(new XSBooleanValue(relay, false));
306         } else if (soapObject instanceof AttributeExtensibleXMLObject) {
307             ((AttributeExtensibleXMLObject) soapObject).getUnknownAttributes().put(
308                     org.opensaml.ws.soap.soap12.RelayBearing.SOAP12_RELAY_ATTR_NAME,
309                     new XSBooleanValue(relay, false).toString());
310         } else {
311             throw new IllegalArgumentException("Specified object was neither RelyBearing nor AttributeExtensible");
312         }
313     }
314 
315     /**
316      * Get the <code>soap12:relay</code> attribute from a given SOAP object.
317      * 
318      * @param soapObject the SOAP object to add the attribute to
319      * 
320      * @return value of the relay attribute, or false if not present
321      */
322     public static boolean getSOAP12RelayAttribute(XMLObject soapObject) {
323         if (soapObject instanceof org.opensaml.ws.soap.soap12.RelayBearing) {
324             XSBooleanValue value = ((org.opensaml.ws.soap.soap12.RelayBearing) soapObject).isSOAP12RelayXSBoolean();
325             if (value != null) {
326                 return value.getValue();
327             }
328         }
329         if (soapObject instanceof AttributeExtensibleXMLObject) {
330             String value = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject) soapObject)
331                     .getUnknownAttributes().get(org.opensaml.ws.soap.soap12.RelayBearing.SOAP12_RELAY_ATTR_LOCAL_NAME));
332             return DatatypeHelper.safeEquals("1", value) || DatatypeHelper.safeEquals("true", value);
333         }
334         return false;
335     }
336     
337     /**
338      * Adds the <code>soap12:role</code> attribute to the given soap object.
339      * 
340      * @param soapObject object to which the rol attribute should be added
341      * @param role the role
342      */
343     public static void addSOAP12RoleAttribute(XMLObject soapObject, String role) {
344         if (soapObject instanceof org.opensaml.ws.soap.soap12.RoleBearing) {
345             ((org.opensaml.ws.soap.soap12.RoleBearing) soapObject).setSOAP12Role(role);
346         } else if (soapObject instanceof AttributeExtensibleXMLObject) {
347             ((AttributeExtensibleXMLObject) soapObject).getUnknownAttributes().put(
348                     org.opensaml.ws.soap.soap12.RoleBearing.SOAP12_ROLE_ATTR_NAME, role);
349         } else {
350             throw new IllegalArgumentException(
351                     "Specified object was neither RoleBearing nor AttribtueExtensible");
352         }
353     }
354 
355     /**
356      * Gets the <code>soap12:role</code>.
357      * 
358      * @param soapObject the SOAP object which may contain the role
359      * 
360      * @return the role or null if it is not set on the object
361      */
362     public static String getSOAP12RoleAttribute(XMLObject soapObject) {
363         String role = null;
364         if (soapObject instanceof org.opensaml.ws.soap.soap12.RoleBearing) {
365             role = ((org.opensaml.ws.soap.soap12.RoleBearing) soapObject).getSOAP12Role();
366         }
367 
368         if (role == null && soapObject instanceof AttributeExtensibleXMLObject) {
369             role = DatatypeHelper.safeTrimOrNullString(((AttributeExtensibleXMLObject) soapObject)
370                     .getUnknownAttributes().get(
371                             org.opensaml.ws.soap.soap12.RoleBearing.SOAP12_ROLE_ATTR_LOCAL_NAME));
372         }
373 
374         return role;
375     }
376 
377     /**
378      * Adds a <code>soap11:actor</code> attribute to the given SOAP object.
379      * 
380      * @param soapObject the SOAP object to add the attribute to
381      * @param actorURI the URI of the actor
382      * 
383      * @deprecated use instead {@link #addSOAP11ActorAttribute(XMLObject, String)}.
384      */
385     public static void addActorAttribute(XMLObject soapObject, String actorURI) {
386         addSOAP11ActorAttribute(soapObject, actorURI);
387     }
388 
389     /**
390      * Adds a single encoding style to the given SOAP object. If an existing <code>soap11:encodingStyle</code> attribute
391      * is present, the given style will be added to the existing list.
392      * 
393      * @param soapObject the SOAP object to add the attribute to
394      * @param encodingStyle the encoding style to add
395      * 
396      * @deprecated use instead {@link #addSOAP11EncodingStyle(XMLObject, String)}.
397      */
398     public static void addEncodingStyle(XMLObject soapObject, String encodingStyle) {
399         addSOAP11EncodingStyle(soapObject, encodingStyle);
400     }
401 
402     /**
403      * Adds a <code>soap11:encodingStyle</code> attribute to the given SOAP object.
404      * 
405      * @param soapObject the SOAP object to add the attribute to
406      * @param encodingStyles the list of encoding styles to add
407      * 
408      * @deprecated use instead {@link #addSOAP11EncodingStyles(XMLObject, List)}.
409      */
410     public static void addEncodingStyles(XMLObject soapObject, List<String> encodingStyles) {
411         addSOAP11EncodingStyles(soapObject, encodingStyles);
412     }
413 
414     /**
415      * Adds a <code>soap11:mustUnderstand</code> attribute to the given SOAP object.
416      * 
417      * @param soapObject the SOAP object to add the attribute to
418      * @param mustUnderstand whether mustUnderstand is true or false
419      * 
420      * @deprecated use instead {@link #addSOAP11MustUnderstandAttribute(XMLObject, boolean)}.
421      */
422     public static void addMustUnderstandAttribute(XMLObject soapObject, boolean mustUnderstand) {
423         addSOAP11MustUnderstandAttribute(soapObject, mustUnderstand);
424     }
425     
426     /**
427      * Add a header block to the SOAP envelope contained within the specified message context's
428      * {@link MessageContext#getOutboundMessage()}.
429      * 
430      * @param messageContext the message context being processed
431      * @param headerBlock the header block to add
432      */
433     public static void addHeaderBlock(MessageContext messageContext, XMLObject headerBlock) {
434         XMLObject outboundEnvelope = messageContext.getOutboundMessage();
435         if (outboundEnvelope == null) {
436             throw new IllegalArgumentException("Message context does not contain a SOAP envelope");
437         }
438         
439         // SOAP 1.1 Envelope
440         if (outboundEnvelope instanceof Envelope) {
441             addSOAP11HeaderBlock((Envelope) outboundEnvelope, headerBlock);
442         }
443         
444         //TODO SOAP 1.2 support when object providers are implemented
445         
446     }
447 
448     /**
449      * Add a header to the SOAP 1.1 Envelope.
450      * 
451      * @param envelope the SOAP 1.1 envelope to process
452      * @param headerBlock the header to add
453      */
454     public static void addSOAP11HeaderBlock(Envelope envelope, XMLObject headerBlock) {
455         Header envelopeHeader = envelope.getHeader();
456         if (envelopeHeader == null) {
457             envelopeHeader = (Header) Configuration.getBuilderFactory().getBuilder(Header.DEFAULT_ELEMENT_NAME)
458                 .buildObject(Header.DEFAULT_ELEMENT_NAME);
459             envelope.setHeader(envelopeHeader);
460         }
461         
462         envelopeHeader.getUnknownXMLObjects().add(headerBlock);
463     }
464 
465     /**
466      * Get a header block from the SOAP envelope contained within the specified message context's
467      * {@link MessageContext#getInboundMessage()}.
468      * 
469      * @param msgContext the message context being processed
470      * @param headerName the name of the header block to return 
471      * @param targetNodes the explicitly specified SOAP node actors (1.1) or roles (1.2) for which the header is desired
472      * @param isFinalDestination true specifies that headers targeted for message final destination should be returned,
473      *          false means they should not be returned
474      * @return the list of matching header blocks
475      */
476     public static List<XMLObject> getInboundHeaderBlock(MessageContext msgContext, QName headerName,
477             Set<String> targetNodes, boolean isFinalDestination) {
478         XMLObject inboundEnvelope = msgContext.getInboundMessage();
479         if (inboundEnvelope == null) {
480             throw new IllegalArgumentException("Message context does not contain an inbound SOAP envelope");
481         }
482         
483         // SOAP 1.1 Envelope
484         if (inboundEnvelope instanceof Envelope) {
485             return getSOAP11HeaderBlock((Envelope) inboundEnvelope, headerName, targetNodes, isFinalDestination);
486         }
487         
488         //TODO SOAP 1.2 support when object providers are implemented
489         return Collections.emptyList();
490     }
491 
492     /**
493      * Get a header block from the SOAP envelope contained within the specified message context's
494      * {@link MessageContext#getOutboundMessage()}.
495      * 
496      * @param msgContext the message context being processed
497      * @param headerName the name of the header block to return 
498      * @param targetNodes the explicitly specified SOAP node actors (1.1) or roles (1.2) for which the header is desired
499      * @param isFinalDestination true specifies that headers targeted for message final destination should be returned,
500      *          false specifies they should not be returned
501      * @return the list of matching header blocks
502      */
503     public static List<XMLObject> getOutboundHeaderBlock(MessageContext msgContext, QName headerName,
504             Set<String> targetNodes, boolean isFinalDestination) {
505         XMLObject outboundEnvelope = msgContext.getOutboundMessage();
506         if (outboundEnvelope == null) {
507             throw new IllegalArgumentException("Message context does not contain an outbound SOAP envelope");
508         }
509         
510         // SOAP 1.1 Envelope
511         if (outboundEnvelope instanceof Envelope) {
512             return getSOAP11HeaderBlock((Envelope) outboundEnvelope, headerName, targetNodes, isFinalDestination);
513         }
514         
515         //TODO SOAP 1.2 support when object providers are implemented
516         return Collections.emptyList();
517     }
518 
519     /**
520      * Get a header block from the SOAP 1.1 envelope.
521      * 
522      * @param envelope the SOAP 1.1 envelope to process 
523      * @param headerName the name of the header block to return 
524      * @param targetNodes the explicitly specified SOAP node actors for which the header is desired
525      * @param isFinalDestination true specifies that headers targeted for message final destination should be returned,
526      *          false specifies they should not be returned
527      * @return the list of matching header blocks
528      */
529     public static List<XMLObject> getSOAP11HeaderBlock(Envelope envelope, QName headerName, Set<String> targetNodes,
530             boolean isFinalDestination) {
531         Header envelopeHeader = envelope.getHeader();
532         if (envelopeHeader == null) {
533             return Collections.emptyList();
534         }
535         ArrayList<XMLObject> headers = new ArrayList<XMLObject>();
536         for (XMLObject header : envelopeHeader.getUnknownXMLObjects(headerName)) {
537             if (isSOAP11HeaderTargetedToNode(header, targetNodes, isFinalDestination)) {
538                 headers.add(header);
539             }
540         }
541         
542         return headers;
543     }
544     
545     /**
546      * Evaluate whether the specified header block is targeted to a SOAP 1.1 node given the specified 
547      * parameters.
548      * 
549      * @param header the header to evaluate
550      * @param nodeActors the explicitly specified node actors for which the header is desired
551      * @param isFinalDestination true specifies that headers targeted for message final destination should be returned,
552      *          false specifies they should not be returned
553      * @return the list of matching header blocks
554      */
555     public static boolean isSOAP11HeaderTargetedToNode(XMLObject header, Set<String> nodeActors,
556             boolean isFinalDestination) {
557         String headerActor = getSOAP11ActorAttribute(header);
558         if (headerActor == null) {
559             if (isFinalDestination) {
560                 return true;
561             }
562         } else if (ActorBearing.SOAP11_ACTOR_NEXT.equals(headerActor)) {
563             return true;
564         } else if (nodeActors != null && nodeActors.contains(headerActor)) {
565             return true;
566         }
567         return false;
568     }
569 
570     /**
571      * Determine whether the inbound message represented by the message context 
572      * contains a SOAP Envelope.
573      * 
574      * @param messageContext the current message context
575      * @return true if the inbound message contains a SOAP Envelope, false otherwise
576      */
577     public static boolean isInboundSOAPMessage(MessageContext messageContext) {
578         XMLObject inboundMessage = messageContext.getInboundMessage();
579         if (inboundMessage == null) {
580             return false;
581         }
582         // SOAP 1.1 Envelope
583         if (inboundMessage instanceof Envelope) {
584             return true;
585         }
586         //TODO SOAP 1.2 support when object providers are implemented
587         return false;
588     }
589     
590     /**
591      * Build a SOAP 1.1. Fault element.
592      * 
593      * @param faultCode the 'faultcode' QName (required)
594      * @param faultString the 'faultstring' value (required)
595      * @param faultActor the 'faultactor' value (may be null)
596      * @param detailChildren the 'detail' child elements
597      * @param detailAttributes the 'detail' element attributes
598      * @return the new Fault element object
599      */
600     public static Fault buildSOAP11Fault(QName faultCode, String faultString, String faultActor,
601             List<XMLObject> detailChildren, Map<QName, String> detailAttributes) {
602         if (faultCode == null) {
603             throw new IllegalArgumentException("Argument for 'faultcode' may not be null");
604         }
605         if (faultString == null) {
606             throw new IllegalArgumentException("Argument for 'faultstring' may not be null");
607         }
608         
609         XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); 
610         
611         Fault faultObj =  (Fault) builderFactory.getBuilder(Fault.DEFAULT_ELEMENT_NAME)
612             .buildObject(Fault.DEFAULT_ELEMENT_NAME);
613         FaultCode faultCodeObj =  (FaultCode) builderFactory.getBuilder(FaultCode.DEFAULT_ELEMENT_NAME)
614             .buildObject(FaultCode.DEFAULT_ELEMENT_NAME);
615         FaultString faultStringObj =  (FaultString) builderFactory.getBuilder(FaultString.DEFAULT_ELEMENT_NAME)
616             .buildObject(FaultString.DEFAULT_ELEMENT_NAME);
617         
618         faultCodeObj.setValue(faultCode);
619         faultObj.setCode(faultCodeObj);
620         
621         faultStringObj.setValue(faultString);
622         faultObj.setMessage(faultStringObj);
623         
624         if (faultActor != null) {
625             FaultActor faultActorObj =  (FaultActor) builderFactory.getBuilder(FaultActor.DEFAULT_ELEMENT_NAME)
626                 .buildObject(FaultActor.DEFAULT_ELEMENT_NAME);
627             faultActorObj.setValue(faultActor);
628             faultObj.setActor(faultActorObj);
629         }
630             
631         Detail detailObj = null;
632         if (detailChildren != null && !detailChildren.isEmpty()) {
633             detailObj = (Detail) builderFactory.getBuilder(Detail.DEFAULT_ELEMENT_NAME)
634                 .buildObject(Detail.DEFAULT_ELEMENT_NAME);
635             for (XMLObject xo : detailChildren) {
636                 if (xo != null) {
637                     detailObj.getUnknownXMLObjects().add(xo);
638                 }
639             }
640         }
641         if (detailAttributes != null && !detailAttributes.isEmpty()) {
642             if (detailObj == null) {
643                 detailObj = (Detail) builderFactory.getBuilder(Detail.DEFAULT_ELEMENT_NAME)
644                     .buildObject(Detail.DEFAULT_ELEMENT_NAME);
645             }
646             for (Entry<QName,String> entry : detailAttributes.entrySet()) {
647                 if (entry.getKey() != null && entry.getValue() != null) {
648                     detailObj.getUnknownAttributes().put(entry.getKey(), entry.getValue());
649                 }
650             }
651         }
652         if (detailObj != null && 
653                 (!detailObj.getUnknownXMLObjects().isEmpty() || !detailObj.getUnknownAttributes().isEmpty())) {
654             faultObj.setDetail(detailObj);
655         }
656         
657         return faultObj;
658     }
659 }