The Java EE 5 Tutorial

Adding Attributes

An XML element can have one or more attributes that give information about that element. An attribute consists of a name for the attribute followed immediately by an equal sign (=) and its value.

The SOAPElement interface provides methods for adding an attribute, for getting the value of an attribute, and for removing an attribute. For example, in the following code fragment, the attribute named id is added to the SOAPElement object person. Because person is a SOAPElement object rather than a SOAPBodyElement object or SOAPHeaderElement object, it is legal for its QName object to contain only a local name.

QName attributeName = new QName("id");
person.addAttribute(attributeName, "Person7");

These lines of code will generate the first line in the following XML fragment.

<person id="Person7">
  ...
</person>

The following line of code retrieves the value of the attribute whose name is id.

String attributeValue = person.getAttributeValue(attributeName);

If you had added two or more attributes to person, the preceding line of code would have returned only the value for the attribute named id. If you wanted to retrieve the values for all the attributes for person, you would use the method getAllAttributes, which returns an iterator over all the values. The following lines of code retrieve and print each value on a separate line until there are no more attribute values. Note that the Iterator.next method returns a Java Object, which is cast to a QName object so that it can be assigned to the QName object attributeName. (The examples in DOM and DOMSource Examples use code similar to this.)

Iterator iterator = person.getAllAttributesAsQNames();
while (iterator.hasNext()){
    QName attributeName = (QName) iterator.next();
    System.out.println("Attribute name is " + attributeName.toString());
    System.out.println("Attribute value is " + 
        element.getAttributeValue(attributeName));
}

The following line of code removes the attribute named id from person. The variable successful will be true if the attribute was removed successfully.

boolean successful = person.removeAttribute(attributeName);

In this section you have seen how to add, retrieve, and remove attributes. This information is general in that it applies to any element. The next section discusses attributes that can be added only to header elements.

Header Attributes

Attributes that appear in a SOAPHeaderElement object determine how a recipient processes a message. You can think of header attributes as offering a way to extend a message, giving information about such things as authentication, transaction management, payment, and so on. A header attribute refines the meaning of the header, whereas the header refines the meaning of the message contained in the SOAP body.

The SOAP 1.1 specification defines two attributes that can appear only in SOAPHeaderElement objects: actor and mustUnderstand.

The SOAP 1.2 specification defines three such attributes: role (a new name for actor), mustUnderstand, and relay.

The next sections discuss these attributes.

See Header Example for an example that uses the code shown in this section.

The actor Attribute

The actor attribute is optional, but if it is used, it must appear in a SOAPHeaderElement object. Its purpose is to indicate the recipient of a header element. The default actor is the message’s ultimate recipient; that is, if no actor attribute is supplied, the message goes directly to the ultimate recipient.

An actor is an application that can both receive SOAP messages and forward them to the next actor. The ability to specify one or more actors as intermediate recipients makes it possible to route a message to multiple recipients and to supply header information that applies specifically to each of the recipients.

For example, suppose that a message is an incoming purchase order. Its SOAPHeader object might have SOAPHeaderElement objects with actor attributes that route the message to applications that function as the order desk, the shipping desk, the confirmation desk, and the billing department. Each of these applications will take the appropriate action, remove the SOAPHeaderElement objects relevant to it, and send the message on to the next actor.


Note –

Although the SAAJ API provides the API for adding these attributes, it does not supply the API for processing them. For example, the actor attribute requires that there be an implementation such as a messaging provider service to route the message from one actor to the next.


An actor is identified by its URI. For example, the following line of code, in which orderHeader is a SOAPHeaderElement object, sets the actor to the given URI.

orderHeader.setActor("http://gizmos.com/orders");

Additional actors can be set in their own SOAPHeaderElement objects. The following code fragment first uses the SOAPMessage object message to get its SOAPHeader object header. Then header creates four SOAPHeaderElement objects, each of which sets its actor attribute.

SOAPHeader header = message.getSOAPHeader();
SOAPFactory soapFactory = SOAPFactory.newInstance();

String nameSpace = "ns";
String nameSpaceURI = "http://gizmos.com/NSURI";

QName order = new QName(nameSpaceURI, "orderDesk", nameSpace);
SOAPHeaderElement orderHeader = header.addHeaderElement(order);
orderHeader.setActor("http://gizmos.com/orders");

QName shipping = new QName(nameSpaceURI, "shippingDesk", nameSpace);
SOAPHeaderElement shippingHeader = header.addHeaderElement(shipping);
shippingHeader.setActor("http://gizmos.com/shipping");

QName confirmation = new QName(nameSpaceURI, "confirmationDesk", nameSpace);
SOAPHeaderElement confirmationHeader = header.addHeaderElement(confirmation);
confirmationHeader.setActor("http://gizmos.com/confirmations");

QName billing = new QName(nameSpaceURI, "billingDesk", nameSpace);
SOAPHeaderElement billingHeader = header.addHeaderElement(billing);
billingHeader.setActor("http://gizmos.com/billing");

The SOAPHeader interface provides two methods that return a java.util.Iterator object over all the SOAPHeaderElement objects that have an actor that matches the specified actor. The first method, examineHeaderElements, returns an iterator over all the elements that have the specified actor.

java.util.Iterator headerElements =
    header.examineHeaderElements("http://gizmos.com/orders");

The second method, extractHeaderElements, not only returns an iterator over all the SOAPHeaderElement objects that have the specified actor attribute but also detaches them from the SOAPHeader object. So, for example, after the order desk application did its work, it would call extractHeaderElements to remove all the SOAPHeaderElement objects that applied to it.

java.util.Iterator headerElements =
    header.extractHeaderElements("http://gizmos.com/orders");

Each SOAPHeaderElement object can have only one actor attribute, but the same actor can be an attribute for multiple SOAPHeaderElement objects.

Two additional SOAPHeader methods, examineAllHeaderElements and extractAllHeaderElements, allow you to examine or extract all the header elements, whether or not they have an actor attribute. For example, you could use the following code to display the values of all the header elements:

Iterator allHeaders = header.examineAllHeaderElements();
while (allHeaders.hasNext()) {
    SOAPHeaderElement headerElement = (SOAPHeaderElement)allHeaders.next();
    QName headerName = headerElement.getElementQName();
    System.out.println("\nHeader name is " + headerName.toString());
    System.out.println("Actor is " + headerElement.getActor());
}

The role Attribute

The role attribute is the name used by the SOAP 1.2 specification for the SOAP 1.2 actor attribute. The SOAPHeaderElement methods setRole and getRole perform the same functions as the setActor and getActor methods.

The mustUnderstand Attribute

The other attribute that must be added only to a SOAPHeaderElement object is mustUnderstand. This attribute says whether or not the recipient (indicated by the actor attribute) is required to process a header entry. When the value of the mustUnderstand attribute is true, the actor must understand the semantics of the header entry and must process it correctly to those semantics. If the value is false, processing the header entry is optional. A SOAPHeaderElement object with no mustUnderstand attribute is equivalent to one with a mustUnderstand attribute whose value is false.

The mustUnderstand attribute is used to call attention to the fact that the semantics in an element are different from the semantics in its parent or peer elements. This allows for robust evolution, ensuring that a change in semantics will not be silently ignored by those who may not fully understand it.

If the actor for a header that has a mustUnderstand attribute set to true cannot process the header, it must send a SOAP fault back to the sender. (See Using SOAP Faults.) The actor must not change state or cause any side effects, so that, to an outside observer, it appears that the fault was sent before any header processing was done.

For example, you could set the mustUnderstand attribute to true for the confirmationHeader in the code fragment in The actor Attribute:

QName confirmation = new QName(nameSpaceURI, "confirmationDesk", nameSpace);
SOAPHeaderElement confirmationHeader = header.addHeaderElement(confirmation);
confirmationHeader.setActor("http://gizmos.com/confirmations");
confirmationHeader.setMustUnderstand(true);

This fragment produces the following XML:

<ns:confirmationDesk
  xmlns:ns="http://gizmos.com/NSURI"
  SOAP-ENV:actor="http://gizmos.com/confirmations"
  SOAP-ENV:mustUnderstand="1"/>

You can use the getMustUnderstand method to retrieve the value of the mustUnderstand attribute. For example, you could add the following to the code fragment at the end of the preceding section:

System.out.println("mustUnderstand is " + headerElement.getMustUnderstand());

The relay Attribute

The SOAP 1.2 specification adds a third attribute to a SOAPHeaderElement, relay. This attribute, like mustUnderstand, is a boolean value. If it is set to true, it indicates that the SOAP header block must not be processed by any node that is targeted by the header block, but must only be passed on to the next targeted node. This attribute is ignored on header blocks whose mustUnderstand attribute is set to true or that are targeted at the ultimate receiver (which is the default). The default value of this attribute is false.

For example, you could set the relay element to true for the billingHeader in the code fragment in The actor Attribute (also changing setActor to setRole):

QName billing = new QName(nameSpaceURI, "billingDesk", nameSpace);
SOAPHeaderElement billingHeader = header.addHeaderElement(billing);
billingHeader.setRole("http://gizmos.com/billing");
billingHeader.setRelay(true);

This fragment produces the following XML:

<ns:billingDesk
  xmlns:ns="http://gizmos.com/NSURI"
  env:relay="true"
  env:role="http://gizmos.com/billing"/>

To display the value of the attribute, call getRelay:

System.out.println("relay is " + headerElement.getRelay());