Dearl all,

 

I've been struggling with a problem while trying to access a .Net web
service from apache axis client generated classes (version 1.4). Since I've
been able to overcome the problems (mainly due to scattered information that
I've collected from the web) I decided to share the knowledge with the
community.

 

The first problem was that although the service seemed to be well generated
and I was able to connect to the server, I was always receiving an axis
fault with the following reason: "The message with To '' cannot be processed
at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher.
Check that the sender and receiver's EndpointAddresses agree."

 

It turns out that I had two problems: the first was that the .Net service
was expecting the message to have two specific soap headers from the
<http://www.w3.org/2005/08/addressing> http://www.w3.org/2005/08/addressing
namespace: the "To" and the "Action" headers. The first is supposed to
contain the actual URL of the service being called while the latter should
replicate the same information that goes into the SoapAction HTTP header,
i.e. the action to be executed (ex  http://some-namespace/MethodName).

 

So, in order to add both these headers, I've included the following piece of
code just before the method call in my generated class:

 

((org.apache.axis.client.Stub)
servicestub).setHeader("http://www.w3.org/2005/08/addressing";, "To",
"http://server/MyService.svc";);

((org.apache.axis.client.Stub)
servicestub).setHeader("http://www.w3.org/2005/08/addressing";, "Action",
"http://some-namespace/MethodName";);

SOAPHeaderElement[] headers = ((org.apache.axis.client.Stub)
servicestub).getHeaders();

for (SOAPHeaderElement h : headers) {

      h.setRole(null);

}

 

Where "servicestub" is the axis generated stub that implements the service
interface (i.e. the object that is used to perform the actual service
calls). Please notice the "h.setRole(null);" piece of code. That snippet is
ESSENTIAL for getting the service called, since without that the axis
runtime will add a "role" attribute to both headers which is not well
understood by the .Net runtime.

 

After doing that I was able to successfully perform the service call, but
unable to process the reply, since axis was firing the infamous "Could not
understand MustUnderstand Header(s)" fault. That happened because the reply
was carrying a similar Action header with the "mustUnderstand" flag set to
"1". Consequently, as there was no registered handler, on the client side,
for processing that mandatory header element, the client was crashing just
before being able to process the reply message.

 

To overcome that problem, I've created a specialized Handler that simply set
the "processed" flag of the SOAPHeaderElement to true, so axis wouldn't
complain about it.

 

The code of the handler is very straightforward and  goes like this:

 

public class ActionHandler implements Handler{

 

      HandlerInfo hi;

 

 

      @Override

      public void init(HandlerInfo hi) {

            this.hi = hi;     

      }

 

 

      @Override

      public QName[] getHeaders() {

            // TODO Auto-generated method stub

            return hi.getHeaders();

      }

 

      @Override

      public void destroy() {

            // TODO Auto-generated method stub       

      }

 

 

      @Override

      public boolean handleFault(javax.xml.rpc.handler.MessageContext arg0)
{

            // TODO Auto-generated method stub

            return true;

      }

 

      @Override

      public boolean handleRequest(javax.xml.rpc.handler.MessageContext
context) {

            return true;

      }

 

      @Override

      public boolean handleResponse(javax.xml.rpc.handler.MessageContext
context) {

            org.apache.axis.MessageContext mc =
(org.apache.axis.MessageContext)context;

            try {

                  Iterator<SOAPHeaderElement> itr =
mc.getCurrentMessage().getSOAPHeader().getChildElements();

                  while (itr.hasNext()) {

                        SOAPHeaderElement el = itr.next();

                        System.out.println("SETTING HEADER: " + el.getName()
+ " PROCESSED...");

                        el.setProcessed(true);

                  }

            } catch (SOAPException e) {

                  // TODO Auto-generated catch block

                  e.printStackTrace();

            }

            return true;

      }

}

 

 

Finally, I've only needed to register the new created handler against axis,
which was accomplished by the following piece of code, in the proxy's
initialization method (which, by the way, was not generated by axis as usual
- don't know why):

 

MyServiceLocator service = new MyServiceLocator();

servicestub = service.getMyServiceStub();

HandlerRegistry registry = service.getHandlerRegistry();

List<HandlerInfo> handlerList = new ArrayList<HandlerInfo>();

handlerList.add(new HandlerInfo(ActionHandler.class, null, null));

QName port = (QName) service.getPorts().next();

registry.setHandlerChain(port, handlerList);

 

And that's it.

 

Hope this helps.

 

Regards,

Ricardo Fernandes

Reply via email to