You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Sebastian Zarzycki <se...@cognifide.com> on 2007/09/25 18:59:37 UTC

SOAP Headers empty - no data.

I am struggling with extracting headers from soap message, using CXF.

I just have simplest webservice, taking one String, and returning it 
back, divided on interface and implementation. Using annotations, and 
then web.xml and beans.xml, I am able to deploy it in Tomcat and have it 
working. In fact, I have Adobe Flex application client, who sends WS 
request, and receive valid response. Everything is fine.

What I don't understand is how to handle headers. I'm adding headers to 
the envelope of soap message. I remember extracting them just fine using 
XFire. In CXF (using 2.0.1, but also tried lastest nightly), first I'm 
very confused as to which Interceptor phase to use. I am plugging my 
Interceptor (AbstractSoapInterceptor) using beans.xml. While this 
document - http://cwiki.apache.org/CXF20DOC/interceptors.html - advises 
to use READ phase to extract headers, whenever I call msg.hasHeaders(), 
I have null. I've been able to access headers, when setting phase to one 
that is after UNMARSHAL - is that expected behaviour? However, even when 
I'm able to access List of Headers, the only data they hold, is their 
local name, and namespace - and no data that are passed within. Can 
someone please explain what I'm doing wrong and provide with solution? 
My WSDL is generated from pojo class, so it's not contract-first 
approach. AFAIK I need to add SOAP header to the message, not to have 
headers within operation request. That was possible in XFire. Something 
drastically changed? I am really willing to upgrade to CXF.

Oh and btw, that document describes a way for setting phase using 
setPhase() in constructor. This is no longer valid (compilation error), 
and the only way I know of, is to super() in Interceptor constructor 
with wanted phase. Or not?

Seb


Re: SOAP Headers empty - no data.

Posted by Sebastian Zarzycki <se...@cognifide.com>.
Yay! Thanks a lot, Daniel - this is much appreciated!

It was some internal implementation but still castable to 
w3c.dom.Element. It was the actual datapull from here that caused me 
headache, but those helper classes are indeed very helpful.

Final solution (extracting headers, and for each header, printing out 
first-level children) :
------------------------------------------------------------------------------------
import java.util.List;
import org.w3c.dom.Node;
import org.apache.cxf.binding.soap.SoapFault;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.helpers.XMLUtils;


public class MySoapInterceptor extends AbstractSoapInterceptor {

      public MySoapInterceptor() {
           super(Phase.UNMARSHAL);
      }

   
  public void handleMessage(SoapMessage msg) throws SoapFault {
    System.out.println("Interceptor " + this.getPhase());
    List<Header> lista = msg.getHeaders();
   
    for (Header h : lista) {
        Element el = (Element) h.getObject();
       
        System.out.println("Header XML :");
        XMLUtils.printDOM(el);      
       
        Node node = DOMUtils.getChild(el, null);
        printNode(node);

        while ( ((node = DOMUtils.getNext(node, null, 
node.getNodeType()) ) != null) ) {
            printNode(node);
        }
    }
  }
 
  public void printNode(Node node) {
      System.out.println("Node : ");       
    System.out.println(node.getNodeName());
    System.out.println("Node value : ");
    System.out.println(DOMUtils.getContent(node));
  }
}
----------------------------------------------------------------------


Seb


>> The object returned from Header is virtually null - it holds no data,
>> at least I couldn't find in it (browsing properties in debug) the data
>> I put in Header. 
>>     
>
> Hmmm.....    It should be castable to a org.w3c.dom.Element object which 
> should have all the data that was on the wire.   Can you check if it's 
> castable?   At the very least, can you do something like:
> System.out.println(obj.getClass());
> to figure out the class.   If it is an Element, try:
> org.apache.cxf.common.helpers.XMLUtils.printDOM((Element)obj);
>
> The standard DOM "toString" method sucks.   It would look fairly empty.  
> If you actually traverse it though, the data is there.
>
> A straight cast to an Element should work.



Re: SOAP Headers empty - no data.

Posted by Daniel Kulp <dk...@apache.org>.
On Tuesday 25 September 2007, Sebastian Zarzycki wrote:
> Thanks for the answer, Dan!
> Which approach would you recommend?

Well, it kind of depends.   If the headers really are specific to that 
application and re-usability is irrelevant, doing it right in the POJO 
web service is usually the easiest.  (nothing to configure, no extra 
classes, etc...)   

For WS-Security "type" stuff, where you need to see the ENTIRE message at 
once, the JAX-WS Handler may make some sense.   There is a performance 
penalty for this though as the entire message does need to get read into 
the SAAJ model and then re-walked later.

In general though, the interceptor model is the most flexible.   It can 
be re-used with other services, it can process via DOM or other if need 
be, has full access to the exchange to modify the handler chains, etc...


> I was not aware of other ways than 
> Interceptor. I personally like the idea of processing headers in
> Interceptor - it is something my actual service should not know about.
> I'm going to pass credentials in headers. If user is not authorized,
> there is no point to invoke service. Other way I would need to ask for
> authorization at the beginning of processing every webservice, which
> is inconvenient.

Yep.   Sounds like Interceptor is definitely the way to go.


> > 1) Interceptor approach:  the page is a bit unclear.   The headers
> > are read during the READ phase, but if your interceptor occurred
> > before the interceptor that does the reading
> > (ReadHeadersInterceptor) in that phase, you wouldn't see them.
>
> That is what I thought.
>
> > From the List<Header>, each header should have a getObject().
> > The "normal" behavior for the getObject() return is to return the
> > DOM for the header.   There are ways to configure things so JAXB
> > data objects are returned, but that's a bit more complex.
>
> The object returned from Header is virtually null - it holds no data,
> at least I couldn't find in it (browsing properties in debug) the data
> I put in Header. 

Hmmm.....    It should be castable to a org.w3c.dom.Element object which 
should have all the data that was on the wire.   Can you check if it's 
castable?   At the very least, can you do something like:
System.out.println(obj.getClass());
to figure out the class.   If it is an Element, try:
org.apache.cxf.common.helpers.XMLUtils.printDOM((Element)obj);

The standard DOM "toString" method sucks.   It would look fairly empty.  
If you actually traverse it though, the data is there.


> there is no way I could access the <foo> and its value. Could this be
> done automatically? 

A straight cast to an Element should work.

> If not, how should I configure JAXB to return 
> simple FooObject with populated value? Any example or tutorial for
> that?

Not right now...   My quick 30 second tutorial would be:

In your setup code, you would need to register an instance of 
HeaderProcessor with the HeaderManager extension found on the Bus:
bus.getExtension(HeaderManager.class).registerHeaderProcessor(processor);

Your header processor would hold an instance of JAXBDataBinding 
configured with the classes your namespace will processes.   

Thus, when the ReadHeadersInterceptor encounters headers in your 
namespace, it will grab the DataBinding and deserialize it to the 
correct object.   That said, it deserializes the entire header element.  
You would need a JAXB class for the qo:header type which has a "foo" 
field of the foo type.


> > 2) JAX-WS SOAPHandler - with the JAX-WS frontend, you can use JAX-WS
> > SOAP Handlers and get the entire message as an SAAJ object.    Do
> > whatever processing you want.
>
> At which point should I do that? My webservice? Could you provide some
> details (links, tutorials, documentation, examples) on how to do that?

That would be in the jaxws spec.   We have a simple sample in the 
samples/jaxws_handlers stuff included with 2.0.2 (about to be released 
very shortly).   It was included in 2.0.1 but I think it was in a 
different directory name.     There is a LoggingHandler in there that 
takes the message and just prints it.


> > 3) Directly in Pojo - with JAX-WS, you can put:
> > @Resource
> > WebServiceContext ctx
> > and then in your method call
> > ctx.getMessageContext().get(Header.HEADER_LIST); to get the
> > List<Header> objects out of the context.   You can process them
> > there if needed.
>
> You mean - pojo of my webservice implementation?

Yep.   As I mentioned about, this is usually the easiest to do as no 
config or anything is involved, but it does tie it to the implementation 
which is probably not desirable.


-- 
J. Daniel Kulp
Principal Engineer
IONA
P: 781-902-8727    C: 508-380-7194
daniel.kulp@iona.com
http://www.dankulp.com/blog

Re: SOAP Headers empty - no data.

Posted by Sebastian Zarzycki <se...@cognifide.com>.
Thanks for the answer, Dan!
Which approach would you recommend? I was not aware of other ways than 
Interceptor. I personally like the idea of processing headers in 
Interceptor - it is something my actual service should not know about. 
I'm going to pass credentials in headers. If user is not authorized, 
there is no point to invoke service. Other way I would need to ask for 
authorization at the beginning of processing every webservice, which is 
inconvenient.

> 1) Interceptor approach:  the page is a bit unclear.   The headers are 
> read during the READ phase, but if your interceptor occurred before the 
> interceptor that does the reading (ReadHeadersInterceptor) in that 
> phase, you wouldn't see them.  
>   
That is what I thought.

> From the List<Header>, each header should have a getObject().   
> The "normal" behavior for the getObject() return is to return the DOM 
> for the header.   There are ways to configure things so JAXB data 
> objects are returned, but that's a bit more complex.
>   
The object returned from Header is virtually null - it holds no data, at 
least I couldn't find in it (browsing properties in debug) the data I 
put in Header. In XFire I could extract the headers without specifying 
any DOM :

public class AuthorizationHandler extends AbstractHandler {

    public void invoke(MessageContext arg0) throws Exception {
        Element header = null;
        if ((header = arg0.getInMessage().getHeader()) != null) {
            Element el = header.getChild("myHeader", 
Namespace.getNamespace("http://mynamespace"));
             String value = el.getChild("node", 
Namespace.getNamespace("http://mynamespace")).getValue();
        }

In CXF Interceptor, I receive only Object and if I send this in soap 
header :

<q0:header ... somenamespacehere>
    <foo>bar</foo>
</q0:header>

there is no way I could access the <foo> and its value. Could this be 
done automatically? If not, how should I configure JAXB to return simple 
FooObject with populated value? Any example or tutorial for that?


> 2) JAX-WS SOAPHandler - with the JAX-WS frontend, you can use JAX-WS SOAP 
> Handlers and get the entire message as an SAAJ object.    Do whatever 
> processing you want.
>   
At which point should I do that? My webservice? Could you provide some 
details (links, tutorials, documentation, examples) on how to do that?

> 3) Directly in Pojo - with JAX-WS, you can put:
> @Resource
> WebServiceContext ctx
> and then in your method call 
> ctx.getMessageContext().get(Header.HEADER_LIST); to get the List<Header> 
> objects out of the context.   You can process them there if needed.
>   
You mean - pojo of my webservice implementation?




Re: SOAP Headers empty - no data.

Posted by Daniel Kulp <dk...@apache.org>.
Seb,

There are several ways of dealing with the headers in CXF.   Some ways 
work better than others for various situations.   

1) Interceptor approach:  the page is a bit unclear.   The headers are 
read during the READ phase, but if your interceptor occurred before the 
interceptor that does the reading (ReadHeadersInterceptor) in that 
phase, you wouldn't see them.   You could do a "addAfter(....)" type 
thing to force your interceptor after that one or move to a later phase.    
From the List<Header>, each header should have a getObject().   
The "normal" behavior for the getObject() return is to return the DOM 
for the header.   There are ways to configure things so JAXB data 
objects are returned, but that's a bit more complex.

2) JAX-WS SOAPHandler - with the JAX-WS frontend, you can use JAX-WS SOAP 
Handlers and get the entire message as an SAAJ object.    Do whatever 
processing you want.

3) Directly in Pojo - with JAX-WS, you can put:
@Resource
WebServiceContext ctx
and then in your method call 
ctx.getMessageContext().get(Header.HEADER_LIST); to get the List<Header> 
objects out of the context.   You can process them there if needed.


Dan




On Tuesday 25 September 2007, Sebastian Zarzycki wrote:
> I am struggling with extracting headers from soap message, using CXF.
>
> I just have simplest webservice, taking one String, and returning it
> back, divided on interface and implementation. Using annotations, and
> then web.xml and beans.xml, I am able to deploy it in Tomcat and have
> it working. In fact, I have Adobe Flex application client, who sends
> WS request, and receive valid response. Everything is fine.
>
> What I don't understand is how to handle headers. I'm adding headers
> to the envelope of soap message. I remember extracting them just fine
> using XFire. In CXF (using 2.0.1, but also tried lastest nightly),
> first I'm very confused as to which Interceptor phase to use. I am
> plugging my Interceptor (AbstractSoapInterceptor) using beans.xml.
> While this document -
> http://cwiki.apache.org/CXF20DOC/interceptors.html - advises to use
> READ phase to extract headers, whenever I call msg.hasHeaders(), I
> have null. I've been able to access headers, when setting phase to one
> that is after UNMARSHAL - is that expected behaviour? However, even
> when I'm able to access List of Headers, the only data they hold, is
> their local name, and namespace - and no data that are passed within.
> Can someone please explain what I'm doing wrong and provide with
> solution? My WSDL is generated from pojo class, so it's not
> contract-first approach. AFAIK I need to add SOAP header to the
> message, not to have headers within operation request. That was
> possible in XFire. Something drastically changed? I am really willing
> to upgrade to CXF.
>
> Oh and btw, that document describes a way for setting phase using
> setPhase() in constructor. This is no longer valid (compilation
> error), and the only way I know of, is to super() in Interceptor
> constructor with wanted phase. Or not?
>
> Seb



-- 
J. Daniel Kulp
Principal Engineer
IONA
P: 781-902-8727    C: 508-380-7194
daniel.kulp@iona.com
http://www.dankulp.com/blog