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