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.

Reply via email to