jax rpc client side handler

Fri, Jun 17, 2005

Well, this one caused quite a few cakes to be consumed, no doubt from jumping in at the deep end and foundering for a few days until I figured out what was wrong.

The scenario is this. The Guanxi Service Provider (SP) is a distributed SP, with the various components communicating via JAX-RPC web services, under the control of Apache Axis. I’m using Axis 1.2 at the moment. Protecting a web application using the Guanxi SP involves dropping a pre-configured Servlet Filter in front of your application and the filter uses web services technology to communicate with the attribute engine which fetches user attributes from an AA on it’s behalf. As this is asynchronous, the filter has to have some way to tell the engine where to send a signal saying that the attributes are ready for collection. Enter WS-CallBack. To use this means adding the callback information to the SOAP header as it leaves the client and before it gets to the engine’s web service.

Adding info to the SOAP header using the Axis specific org.apache.axis.client.Call object is easy. Just use addHeader() but I wanted to keep it JAX-RPC and not use Axis specific stuff. So that meant using a client side handler to intercept the SOAP message on it’s way to the remote service.

The web service client is actually a Servlet Filter that blocks requests to a web application until it has gathered user attributes from the engine and made a decision using whatever policy engine is installed. So here’s how to implement the handler:

First off, we’ll need to access the engine’s WSDL. This will let Axis configure everything from the wsdl, rather thus us setting the target endpoint address and adding parameters to the Call object. configNode is just the result of getDocumentElement() on the filter’s xml config file. I’ve also shown the XPath query to get the namespace qualified node “location”. This foxed me for ages too!

// The namespace of the engine’s web service - from the config file String nameSpace = xUtils.getNodeValue(configNode, “//*[local-name()=‘namespace’ and namespace-uri()=‘urn:guanxi:sp:guard’]");

// This is from the WSDL node <wsdl:service name=“EngineService”> String serviceName = “EngineService”; // This is from the WSDL node <wsdl:port binding=“impl:GuanxiEngineServiceSoapBinding” name=“GuanxiEngineService”> String portName = “GuanxiEngineService”;

// Create a new instance of the ServiceFactory ServiceFactory serviceFactory = ServiceFactory.newInstance();

// The nameSpace comes from the WSDL node <wsdl:definitions targetNamespace=“http://sgarbh.smo.uhi.ac.uk/guanxi_sp/services/GuanxiEngineService"> Service service = serviceFactory.createService(wsdlURL, new QName(nameSpace, serviceName));

// Now create a new List of HandlerInfo objects - only one really. Our client handler List handlerList = new ArrayList(); handlerList.add(new HandlerInfo(GuardHandler.class, null, null)); HandlerRegistry registry = service.getHandlerRegistry(); registry.setHandlerChain(new QName(nameSpace, portName), handlerList);

// Setup the call Call call = service.createCall(new QName(nameSpace, portName), new QName(“initAttributeRequest”));

// Call the engine’s web service. String wayfLocation = (String)call.invoke(new Object[] {Utils.getUniqueID()});

You can see from the above that the following methods are not required if we’re using WSDL configuraton of the client: Call.setTargetEndpointAddress() Call.setOperationName() Call.addParameter() Call.setReturnType()

If you invoke the first two methods above, the handler won’t be called. That took a long time to figure out! If you invoke the last two you’ll just get an error about parameters already being added via the WSDL configuration.

To finish off, I’ll leave you with the handler itself. It’s a JAX-RPC handler and not the Axis specific kind.

  public GuardHandler() {     System.out.println(“GuardHandler: In constructor”);   }

  public boolean handleRequest(MessageContext context) {     System.out.println(“GuardHandler: In handleRequest”);     return true;   }

  public boolean handleResponse(MessageContext context) {     System.out.println(“GuardHandler: In handleResponse”);     return true;   }

  public boolean handleFault(MessageContext context) {     System.out.println(“GuardHandler: In handleFault”);     return true;   }

  public void init(HandlerInfo config) {     System.out.println(“GuardHandler: In init”);   }

  public void destroy() {     System.out.println(“GuardHandler: In destroy”);   }

  public QName[] getHeaders() {     System.out.println(“GuardHandler: In getHeaders”);     return null;   } }

The handler flow is thus: GuardHandler: In constructor GuardHandler: In init GuardHandler: In handleRequest GuardHandler: In handleResponse GuardHandler: In destroy

comments powered by Disqus