In the handleMessage method inside FaultHeaderInterceptor,
import javax.xml.namespace.QName;
import org.apache.cxf.headers.Header;
import org.w3c.dom.Element;
import com.sun.xml.messaging.saaj.soap.SOAPDocumentImpl;
import com.sun.xml.messaging.saaj.soap.impl.ElementImpl;
import com.sun.xml.messaging.saaj.soap.name.NameImpl;
import com.sun.xml.messaging.saaj.soap.ver1_1.SOAPPart1_1Impl;
import net.clockstudio.cxf.HeaderTransferObject;
public void handleMessage(SoapMessage message) throws Fault
{
// previous code
Header header = this.createHeader(headerTO);
if (header != null)
{
message.getHeaders.add(header);
}
}
private Header createHeader(HeaderTransferObject headerTO)
{
if (headerTO != null)
{
QName qname = new QName("/some/qname");
SOAPDocumentImpl doc = new SOAPDocmentImpl(new SOAPPart1_1Impl());
doc.setErrorChecking(false);
Element element = new ElementImpl(doc, NameImpl.createFromQualifiedName("MyHeader", "http://clockstudio.net/cxf/myheader"));
Element subElement = new ElementImpl(doc, NameImpl.createFromQualifiedName("subHeader", "http://clockstudio.net/cxf/subheader"));
subElement.setTextContent(headerTO.getInfo());
// more headers can be added
element.appendChild(subElement);
return new Header(qname, element);
}
return null;
}
In the above code, HeaderTransferObject attributes hold the information for creating a header. To create a header, it takes a QName (Qualified Name) and Element objects. In this example, the Element objects are created using SOAPDocumentImpl as well as its qualified name.
As you can see, it's still fairly simple to create a header when a fault is returned. However, what if you want to capture the incoming platform specific header and return those information back? In an asynchronized environment, the client request comes along with it's session id, transaction info and those has to be returned when a fault is occured. So the client can then be able to trace back which thread made the request, what can you do with this case?
In this case, another Interceptor has to be created to capture the incoming header information. You may wonder that there is an Exchange object which hold all incoming, outgoing message in the whole process, however, from my experience, when a fault is occured, the incoming header information in the Exchange object will be erased, it is probably because of a fault routine is started. Or it maybe just a bug in CXF. A further investigation is needed. But now, the new SoapHeaderInterceptor will do the job which explicitly save the header information into the message.
Here is the code,
public SoapHeaderInterceptor()
{
super(Phase.READ);
addAfter(ReadHeadersInterceptor.class.getName());
}
public void handleMessage(SoapMessage message) throws Fault
{
// retrieve the incoming header and saved it explicitly, if it's not saved, it will be lost when a fault is returned
List list = (List) message.get("org.apache.cxf.headers.Header.list");
if (list != null && !list.isEmpty() && list.get(0) instanceof SoapHeader)
{
SoapHeader header = (SoapHeader) list.get(0);
message.put(SoapHeader.class, header);
}
}
The above code capture the incoming SoapHeader and explicitly put into the message. So once a fault is occured, the FaultHeaderInterceptor can still find the SoapHeader message from the incoming request.
To retrieve the saved SoapHeader in FaultHeaderInterceptor,
public void handleMessage(SoapMessage message) throws Fault
{
// code that create PlatFormException
// retrieve the soapHeader saved in the inMessage in SoapHeaderInterceptor
SoapHeader header = message.getExchange().getInMessage().get(SoapHeader.class);
// code that manipulate the header with headerTO above, headerTO can now be replaced to this new header
}
In the configuration, this interceptor will be put under inInterceptors bucket,
<bean id="soapHeaderInterceptor"
class="com.telstra.sdfcore.csc.uup.interceptor.SoapHeaderInterceptor" />
<cxf:bus>
<cxf:inInterceptors>
<ref bean="soapHeaderInterceptor" />
</cxf:inInterceptors>
<cxf:outFaultInterceptors>
<ref bean="faultHeaderInterceptor" />
</cxf:outFaultInterceptors>
</cxf:bus>
Now, when a request comes in, it will save the header into the message by using SoapHeaderInterceptor. When a fault is occured, it will return a platform specific exception, as well as the platform specific header which comes from the request.
No comments:
Post a Comment