I figured I owe to the community an example how I did it, so here it is:
if you plug it in, it will add FooWSSHeader type with SessionID to the WSDL
on the fly.
package spring.demo.cxf.handler;
import javax.xml.namespace.QName;
import javax.xml.xpath.XPathFactory;
import java.util.List;
import java.util.Map;
import javax.wsdl.Definition;
import javax.wsdl.extensions.schema.SchemaReference;
import org.apache.cxf.Bus;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.transport.http.WSDLQueryHandler;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class MyWSDLQueryHandler extends WSDLQueryHandler
{
public static final String foo_WSS_HEADER_TAG = "FooWSSHeader";
public static final String foo_WSS_HEADER_SESSIONID_TAG = "SessionID";
/**
* Creates a new instance of demo.spring.handler.MyWSDLQueryHandler.java
and Performs Initialization
*
*/
public MyWSDLQueryHandler()
{
}
/**
* Creates a new instance of demo.spring.handler.MyWSDLQueryHandler.java
and Performs Initialization
*
* @param b
*/
public MyWSDLQueryHandler(Bus b)
{
super(b);
}
protected void updateDoc(Document doc, String base,
Map<String, Definition> mp,
Map<String, SchemaReference> smp,
EndpointInfo ei) {
super.updateDoc(doc, base, mp, smp, ei);
Element definitions = null;
List<Element> defList =
DOMUtils.findAllElementsByTagNameNS(doc.getDocumentElement(),
"http://schemas.xmlsoap.org/wsdl/",
"definitions");
for (Element def: defList)
{
definitions = def;
break;
}
//sneak the header in
List<Element> schemaList =
DOMUtils.findAllElementsByTagNameNS(definitions,
"http://www.w3.org/2001/XMLSchema",
"schema");
for (Element elSchema : schemaList) {
//insert fooWSSHeader schema element
insertWSSSchemaElement(doc, elSchema);
//append fooWSSHeader complex type
appendWSSComplexType(doc, elSchema);
break;
}
insertWSSMessage(doc, definitions);
//insert headers into binding inputs
insertWSSHeaders(doc, definitions);
}
private void insertWSSHeaders(Document doc, Element definitions)
{
List<Element> bindingList =
DOMUtils.findAllElementsByTagNameNS(definitions,
"http://schemas.xmlsoap.org/wsdl/",
"binding");
for (Element elBinding: bindingList)
{
List<Element> inputList =
DOMUtils.findAllElementsByTagNameNS(elBinding,
"http://schemas.xmlsoap.org/wsdl/",
"input");
for (Element elInput: inputList)
{
Element elHeader = doc.createElement("soap:header");
elHeader.setAttribute("message", "tns:" + foo_WSS_HEADER_TAG);
elHeader.setAttribute("part", foo_WSS_HEADER_TAG);
elHeader.setAttribute("use", "literal");
elInput.appendChild(elHeader);
}
}
}
private void insertWSSMessage(Document doc, Element definitions)
{
List<Element> wsdlMessages =
DOMUtils.findAllElementsByTagNameNS(definitions,
"http://schemas.xmlsoap.org/wsdl/",
"message");
for (Element elMessage : wsdlMessages) {
Element elMsg = doc.createElement("wsdl:message");
elMsg.setAttribute("name", foo_WSS_HEADER_TAG);
Element elPart = doc.createElement("wsdl:part");
elPart.setAttribute("name", foo_WSS_HEADER_TAG);
elPart.setAttribute("element", "tns:" + foo_WSS_HEADER_TAG);
elMsg.appendChild(elPart);
definitions.insertBefore(elMsg, elMessage);
break;
}
}
private void appendWSSComplexType(Document doc, Element elSchema)
{
Element elCT = doc.createElement("xs:complexType");
elCT.setAttribute("name", foo_WSS_HEADER_TAG);
Element elSeq = doc.createElement("xs:sequence");
elSeq.appendChild(getHeaderElement(doc, foo_WSS_HEADER_SESSIONID_TAG));
elCT.appendChild(elSeq);
elSchema.appendChild(elCT);
}
private Element getHeaderElement(Document doc, String tagname)
{
Element elEl = doc.createElement("xs:element");
elEl.setAttribute("minOccurs", "0");
elEl.setAttribute("name", tagname);
elEl.setAttribute("type", "xs:string");
return elEl;
}
private void insertWSSSchemaElement(Document doc, Element elSchema)
{
Element el = doc.createElement("xs:element");
el.setAttribute("name", foo_WSS_HEADER_TAG);
el.setAttribute("type", "tns:" + foo_WSS_HEADER_TAG);
NodeList nl = elSchema.getChildNodes();
Node n0 = nl.item(0);
elSchema.insertBefore(el, n0);
}
}
dkulp wrote:
>
>
> Basically, what I was trying to get at is that you just implement a single
> class, your MyWSDLQueryHandler class, that is the QueryHandler. It has a
> method like:
>
> @Resource
> public void setQueryHandlerRegistry(QueryHandlerRegistry qhr) {
> qhr.registerHandler(this, 0);
> }
>
> That SHOULD work fine with 2.2.4.
>
> Dan
>
>
>
>
> On Mon October 26 2009 11:08:37 am vickatvuuch wrote:
>> Dan,
>>
>> Thanks for the reply.
>>
>> I had trouble building my project with SNAPSHOT not sure why that is, but
>> I
>> didn't have time to track it down, so I'm using 2.2.4 for now.
>> It turns out that my solution is slightly different than what I copied in
>> my earlier post.
>> MyQueryHandlerRegistry.setBus injects MyWSDLQueryHandler into the bus,
>> but
>> the actual substitution is done by MyQueryHandlerRegistry.getHandlers
>> which
>> returns
>> MyWSDLQueryHandler instead of the default one.
>> Then I insert Xml elements to build my header things inside the
>> MyWSDLQueryHandler.updateDoc
>>
>> >>Instead of injecting the Bus, you could inject the QueryHandlerRegistry
>>
>> directly.
>> Not sure what did you mean by: "inject the QueryHandlerRegistry directly"
>> could you elaborate a bit more?
>>
>> PS
>> I can build CXF trunk, but need a bit more time before I would be ready
>> to
>> commit.. watching for now..
>>
>> Thanks,
>> -Vitaly
>>
>> dkulp wrote:
>> > Some of this is already changed pretty significantly on trunk/2.3. On
>> > trunk,
>> > when the QueryHandlerRegistryImpl starts up (which is lazy init on
>> trunk,
>> > btw,
>> > thus, the first time it's needed), it queries the context for all the
>> > beans
>> > that implement QueryHandler and auto registers them.
>> >
>> > I think the ordering might be a problem with this though. I THINK
>> it's
>> > currently ordering them in the order they appear in the configs (taking
>> > into
>> > account depends-on attributes). However, thinking about it, I think
>> it
>> > should be reverse. With the last being put in slot 0.
>> >
>> > Basically, I'd love it if you could take your test case and see how it
>> > would
>> > work with 2.3 snapshots. Possibly submit a patch to
>> > QueryHandlerRegistryImpl
>> > to get the ordering "correct".
>> >
>> > One other note:
>> > Instead of injecting the Bus, you could inject the QueryHandlerRegistry
>> > directly.
>> >
>> > Dan
>> >
>> > On Sat October 24 2009 12:11:08 pm vickatvuuch wrote:
>> >> Thanks a bunch for the ideas!
>> >>
>> >> Here is what worked for me:
>> >>
>> >> 1. I defined my version of MyWSDLQueryHandler extends WSDLQueryHandler
>> >> (will override updateDoc and sneak in my header elements there later)
>> >>
>> >> 2. Defined my version of MyQueryHandlerRegistry implement
>> >> QueryHandlerRegistry
>> >> and did this little hack:
>> >>
>> >> @Override
>> >> public void setBus(Bus b)
>> >> {
>> >> super.setBus(b);
>> >>
>> >> QueryHandlerRegistry reg =
>> >> b.getExtension(QueryHandlerRegistry.class);
>> >>
>> >> for (Iterator<QueryHandler> it = reg.getHandlers().iterator();
>> >> it.hasNext(); it.next())
>> >> {
>> >> if (it.next() instanceof WSDLQueryHandler) {
>> >> MyWSDLQueryHandler myHandler = new MyWSDLQueryHandler(b);
>> >>
>> >> reg.registerHandler(myHandler,0);
>> >> break;
>> >> }
>> >> }
>> >>
>> >> }
>> >>
>> >> note: remove from iterator failed with spring exception, so
>> >> registerHandler
>> >> at position 0 seem to have
>> >> put mine in front of an existing one.
>> >>
>> >> 3. finally to kick start all that I added my registry bean inside
>> >> beans.xml
>> >>
>> >> <bean id="myQueryHandlerRegistry"
>> >> class="demo.spring.handler.MyQueryHandlerRegistry"/>
>> >>
>> >> PS
>> >> Is this something, the core team may be want to put in as an
>> >> extensibility
>> >> feature?
>> >> May be let the handler registry be a spring configurable child of the
>> >> bus that would take handlers by name or something of that sort? First
>> >> default once would be loaded and if additional ones are given they
>> would
>> >> override default once? just a suggestion..
>> >>
>> >> Thanks again,
>> >> -Vitaly
>> >>
>> >> bimargulies wrote:
>> >> > We are a little outside my expertise, but I'd advise:
>> >> >
>> >> > Define a bean class that gets the CXF bug injected.
>> >> >
>> >> >
>> >> > @Resource
>> >> > public void setBus(Bus bus) {
>> >> > if (this.bus != bus) {
>> >> > this.bus = bus;
>> >> > registerWithBindingManager();
>> >> > }
>> >> >
>> >> >
>> >> > And put the code in there. What I don't know is how to make sure
>> that
>> >>
>> >> you
>> >>
>> >> > get called at the right time: after the handler registry is set up.
>> >>
>> >> There
>> >>
>> >> > are other people who, with any luck, will chime in.
>> >> >
>> >> > On Sat, Oct 24, 2009 at 10:52 AM, vickatvuuch <[email protected]>
>> >>
>> >> wrote:
>> >> >> can it be done from the config file?
>> >> >>
>> >> >> so far I was using beans.xml to configure everything - bus and
>> >> >> endpoints, interceptors, etc.
>> >> >>
>> >> >> bimargulies wrote:
>> >> >> > org.apache.cxf.transport.http.QueryHandlerRegistryImpl
>> >> >> >
>> >> >> > Walk the bus:
>> >> >> >
>> >> >> > for (QueryHandler qh :
>> >> >> > bus.getExtension(QueryHandlerRegistry.class).getHandlers()) {
>> >> >> > }
>> >> >> >
>> >> >> > and when you find the regular handler, replace it with yours.
>> >> >> >
>> >> >> > And perhaps open a JIRA suggesting that QueryHandlerRegistryImpl
>> be
>> >> >> > friendlier to customization here.
>> >> >> >
>> >> >> >
>> >> >> > On Sat, Oct 24, 2009 at 10:17 AM, vickatvuuch
>> <[email protected]>
>> >> >>
>> >> >> wrote:
>> >> >> >> Thanks!
>> >> >> >>
>> >> >> >> it sounds promising; do you mind sharing how to tell the bus
>> that
>> >>
>> >> it
>> >>
>> >> >> >> should
>> >> >> >> run my handler?
>> >> >> >>
>> >> >> >> Thanks,
>> >> >> >> -Vitaly
>> >> >> >>
>> >> >> >> bimargulies wrote:
>> >> >> >> > The handler is registered as an object on the bus. You can
>> >>
>> >> register
>> >>
>> >> >> >> yours
>> >> >> >>
>> >> >> >> > instead.
>> >> >> >> >
>> >> >> >> > On Fri, Oct 23, 2009 at 6:19 PM, vickatvuuch
>> >>
>> >> <[email protected]>
>> >>
>> >> >> >> wrote:
>> >> >> >> >> Some digging led me to the WSDLQueryHandler.updateDoc method.
>> >> >> >> >> I could add my header elements as a sibling of each input
>> >>
>> >> element
>> >>
>> >> >> in
>> >> >>
>> >> >> >> >> there;
>> >> >> >> >> now the question is how can I override WSDLQueryHandler with
>> my
>> >> >> >> >> implementation? is it possible to give CXF my derived class
>> >> >> >> >> that
>> >> >> >>
>> >> >> >> extends
>> >> >> >>
>> >> >> >> >> WSDLQueryHandler?
>> >> >> >> >>
>> >> >> >> >> vickatvuuch wrote:
>> >> >> >> >> > Hi CXF gurus!
>> >> >> >> >> >
>> >> >> >> >> > I need to add a custom header element to all my endpoints
>> as
>> >> >> >> >> > a
>> >> >>
>> >> >> place
>> >> >>
>> >> >> >> >> for
>> >> >> >> >>
>> >> >> >> >> > client to stick a session token.
>> >> >> >> >> >
>> >> >> >> >> > For example I need to add this message xml element once:
>> >> >> >> >> >
>> >> >> >> >> > <wsdl:message name="Authentication">
>> >> >> >> >> > <wsdl:part name="Authentication"
>> >> >> >> >> > type="tns1:SessionInfo"/> </wsdl:message><br/>
>> >> >> >> >> >
>> >> >> >> >> > and a chunk of xml in bold below, to every port and every
>> >> >> >> >>
>> >> >> >> >> operation:<br/>
>> >> >> >> >>
>> >> >> >> >> > <wsdl:operation name="getFoo">
>> >> >> >> >> > <wsdlsoap:operation soapAction="getFoo"/>
>> >> >> >> >> > <wsdl:input name="getFoo">
>> >> >> >> >> > <wsdlsoap:body
>> >> >> >> >> > encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
>> >> >> >> >>
>> >> >> >> >> use="encoded"/>
>> >> >> >> >>
>> >> >> >> >> > <wsdlsoap:header message="impl:Authentication"
>> >> >> >> >> > part="Authentication"
>> >> >> >> >> > encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
>> >> >> >> >>
>> >> >> >> >> use="encoded"/>
>> >> >> >> >>
>> >> >> >> >> > </wsdl:input>
>> >> >> >> >> >
>> >> >> >> >> > I'm debugging it at the WSDLManager level and wonder if
>> there
>> >>
>> >> is
>> >>
>> >> >> a
>> >> >>
>> >> >> >> >> better
>> >> >> >> >>
>> >> >> >> >> > way to do it?
>> >> >> >> >> > May be a plug in or through an interceptor?
>> >> >> >> >> >
>> >> >> >> >> > Any help is very much appreciated.
>> >> >> >> >> >
>> >> >> >> >> > Thanks,
>> >> >> >> >> > -Vitaly
>> >> >> >> >>
>> >> >> >> >> --
>> >> >> >> >> View this message in context:
>> >>
>> >> http://www.nabble.com/Custom-WSDL-header-tp26030841p26034038.html
>> >>
>> >> >> >> >> Sent from the cxf-user mailing list archive at Nabble.com.
>> >> >> >>
>> >> >> >> --
>> >> >> >> View this message in context:
>> >> >> >>
>> http://www.nabble.com/Custom-WSDL-header-tp26030841p26039401.html
>> >> >> >> Sent from the cxf-user mailing list archive at Nabble.com.
>> >> >>
>> >> >> --
>> >> >> View this message in context:
>> >>
>> >>
>> http://www.nabble.com/CXF-custom-WSDL-header-or-customizing-WSDLQueryHan
>> >>
>> >> >>dler-document-tp26030841p26039721.html Sent from the cxf-user
>> mailing
>> >> >> list archive at Nabble.com.
>>
>
> --
> Daniel Kulp
> [email protected]
> http://www.dankulp.com/blog
>
>
--
View this message in context:
http://www.nabble.com/CXF-custom-WSDL-header-or-customizing-WSDLQueryHandler-document-tp26030841p26118572.html
Sent from the cxf-user mailing list archive at Nabble.com.