axis-java-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Greg Truty <gtr...@us.ibm.com>
Subject JAX-RPC Handler Support in Axis
Date Wed, 28 Aug 2002 02:30:13 GMT




Folks,

I apologize for the long note... so... if you are not interested in the
JAX-RPC handler support in Axis... you can stop right here.  I was taking a
look at our current JAX-RPC handler support in Axis.  To (a) document the
work and (b) define issues with it. I defined what I believe Axis does,
defined the issues, and then suggest a solution.

Dims has added a good portion of the Axis support for Handlers (thanks
Dims).  However, the support needed for containers (as defined in JSR 109)
and that required for non-managed environments (as defined in 101) is a bit
different.  In addition, how this *could* or *should* be reflected in the
*config.wsdd documents should be addressed as pieces are currently missing.
One of the reasons I want to suggest this is that if users of Axis wanted
to stick with spec compliant APIs, this would be a good model to start
with.

Axis

There are 2 ways to configure JAX-RPC Handlers within Axis.

   1) use the WSDD model, create an instance of a JAX-RPC handler and
   define the className parameter of the Client Handler to be invoked.

      <service name="HelloPort" provider="java:RPC">
            :
        <requestFlow>
         <handler type="java:org.apache.axis.handlers.JAXRPCHandler">
          <parameter name="className" value="samples.jaxrpc.hello.
      ClientHandler"/>
          <parameter name="scope" value="session"/>
         </handler>
        </requestFlow>
            :

   2) use the APIs defined in JAX-RPC to add the handler to the Service
   object.

           java.util.List list = helloService.getHandlerRegistry().
   getHandlerChain(new QName(nameSpaceUri, portName));
           list.add(new javax.xml.rpc.handler.HandlerInfo(ClientHandler.
   class,null,null));

Although 2) is the official API way, it intertwines the programming model
w/the QOS possibly added by the handlers at a later date.  Therefore, 1) is
actually a cleaner way (from an application developer standpoint) in that
out-of-band QOSes can be added w/o affecting the client programming model.

However, w/the current implementation, there is a caveat w/the current Axis
design.  In 1) above, the JAX-RPC handlers are added in an slightly bizarre
fashion, in that the actual JAX-RPC Handler used itself isn't a first class
WSDD handler, but instead a parameter to an Axis Handler (org.apache.axis.
handlers.JAXRPCHandler).  Although this allows the JAX-RPC handlers to be
called in a container-based manner, via something similar to the item
below...

    <service name="http://hello.jaxrpc.samples/" provider="java:RPC">
      :
     <requestFlow>
      <handler type="java:org.apache.axis.handlers.JAXRPCHandler">
       <parameter name="className" value="samples.jaxrpc.hello.
   ClientHandler"/>
       <parameter name="scope" value="session"/>
      </handler>
     </requestFlow>
     <responseFlow>
      <handler type="java:org.apache.axis.handlers.JAXRPCHandler">
       <parameter name="className" value="samples.jaxrpc.hello.
   ClientHandler"/>
       <parameter name="scope" value="session"/>
      </handler>
     </responseFlow>
      :

...the creation of the HandlerInfo object defaults to no HandlerConfig
objects (i.e., the init params) or Headers (the soap-header qname items).
In looking at the code, it does something like this...

   public class JAXRPCHandler extends BasicHandler {
       protected static Log log =
               LogFactory.getLog(JAXRPCHandler.class.getName());

       HandlerChainImpl impl = null;

       public void invoke(MessageContext msgContext) throws AxisFault {
           log.debug("Enter: JAXRPCHandler::enter invoke");
           if (impl == null) {
               String className = (String) getOption("className");
               impl = new HandlerChainImpl();
               impl.addNewHandler(className);
           }
      :

Which would create the HandlerChainImpl below...

   public class HandlerChainImpl extends ArrayList {
       protected List handlerInfos = new ArrayList();
       String[] roles = null;

       public HandlerChainImpl() {
       }

       public HandlerChainImpl(List handlerInfos) {
           this.handlerInfos = handlerInfos;
           for (int i = 0; i < handlerInfos.size(); i++)
               add(newHandler(getHandlerInfo(i)));
       }

       public void addNewHandler(String className) {
           try {
               HandlerInfo handlerInfo = new HandlerInfo(ClassUtils.
   forName(className), null, null);
               handlerInfos.add(handlerInfo);
               add(newHandler(handlerInfo));
      :
       }
   :

As you can see... the 2 null's passed in don't allow a map to be easily
created or the list of QNames.  In addition, there are another set of
Issues I found in trying to figure out out to resolve this.

Issues:

1) HandlerChainImpl doesn't implement JAX-RPC HandlerChain

   I talked to Rich about this and saw the note from Rich and Dims about
   this...  My version does implement this.

2) JAX-RPC handlers can only configured for the client side

   Since JAX-RPC is a programming model issue on the client side... Dims
   only addressed the client side.  It's also only specifiable via
   configuring the JAX-RPC service.  I added support to allow this and
   works off the configuration files as well as on the server side.
   However... there is a problem addressed in item 6 below.

3) The AxisEngine implementation is tuned for the client side (it's based
on a Call object being available).

    Calls are only available on the client side.  Therefore, I moved the
   logic for the invoke to AxisClient vs. AxisEngine.

4) getPort is required

   This is more a comment but since getPort is required, we now take
   advantage of Russell's new code in ServiceLocator is now there to set
   the WSDDService name (which is the Port).  We have to be aware of what
   this means in the WAS integration piece.

5) invokeJAXRPCHandlers is in the wrong spot on the client.

   It should be prior to the global handlers but right now it's after.  I
   suggest actually even prior to the service-specific Axis Handlers.  As
   such, I think it should also be in the same spot on the server side.
   For now, I left it where it is (it's called in AxisClient) and recommend
   we probably move it to the Call object itself.  On the server side, I
   placed in in JavaProvider (on the invoke).  Again... thinking it should
   be as close to the target dispatch as possible.  Note, I call these
   prior to the demarshalling (in case they want to screw w/ the XML
   message).

6) On the client side... we need to discuss the behaviour of JAX-RPC
handlers configured programmatically and those via the client-config.
There are merge issues between programmatic and config based items now.

   Currently, I am using the container config version even if they do so
   programmatically.  We need to disallow the programmatic version in 109.
   We should probably ask how we want to deal with this in the Axis non-
   container managed version.. and keep an eye on the 109 implementation of
   these items.

7) JAX-RPC spec discusses an init(Map) method on the HandlerChain.  I can't
quite figure out how this should be used.

   I think we need to go back to the JAX-RPC folks.  Since HandlerInfos
   (which ARE part of the programming model), take maps, I can't tell how
   it should be called.  Also, users can't really create the HandlerChain.
   Only Chains of HandlerInfo objects.  Therefore, I can't quite figure it
   out.

Prototype Details

   1) Created a set of WSDD artifacts to extend to support HandlerInfo and
   Chains for these HandlerInfo objects.

   WSDDJAXRPCHandlerInfo.java
   WSDDJAXRPCHandlerInfoChain.java
   WSDDConstants - added additional constants

   2) Created a HandlerInfoChainFactory to produce these HandlerInfoChains
   which will eventually create HandlerChainImpl objects.

   3) Moved invokeJAXRPCHandlers from AxisEngine to AxisClient (as per
   above)

   4) Added Constants for HandlerInfoChain in Constants

   5) Extended the moved invokeJAXRPCHandlers to allow config to be passed
   from the serviceHandler (set from client-config.wsdd).   Also changed it
   to use the HandlerInfoChainFactory to create my HandlerChains...

   6) Extended WSDDService to look for the configured JAX-RPC HandlerInfo
   chains and invoke downstream elements

   7) Added roles to HandlerChainImpl

   8) Added to Java Provider server-side invocations of these Handler
   chains

Configuration Changes

My config I was testing with looks something like the following:

      :
   <service name="Service1Soap" provider="java:RPC" style="document"
   sstreaming="on">
     <handlerInfoChain>
        <handlerInfo classname = "client.MyJAXRPCHandler"/>
        <handlerInfo classname = "client.MyJAXRPCHandler">
          <parameter name="param1" value="value1"/>
          <parameter name="param2" value="value2"/>
          <parameter name="param3" value="value3"/>
          <header qname="ns12:Fred"/>
          <header qname="ns12:Bob"/>
          <header qname="ns12:Marv"/>
         /handlerInfo>
        <role soapActorName="Mary"/>
        <role soapActorName="Jane"/>
      </handlerInfoChain>
      :

CVS Diff

My CVS diff from my 8/22 codebase is as follows:

   ? axis/deployment/wsdd/WSDDJAXRPCHandlerInfo.java
   ? axis/deployment/wsdd/WSDDJAXRPCHandlerInfoChain.java
   ? axis/handlers/HandlerInfoChainFactory.java
   Index: axis/AxisEngine.java
   ===================================================================
   RCS file: /home/cvspublic/xml-axis/java/src/org/apache/axis/AxisEngine.
   java,v
   retrieving revision 1.94
   diff -r1.94 AxisEngine.java
   77a78,79
   > import org.apache.axis.handlers.HandlerInfoChainFactory;
   >
   421,449c423
   <
   <     protected void invokeJAXRPCHandlers(MessageContext context){
   <         Service service
   <             = (Service)context.getProperty(Call.WSDL_SERVICE);
   <         if(service == null)
   <             return;
   <
   <         QName portName = (QName) context.getProperty(Call.
   WSDL_PORT_NAME);
   <         if(portName == null)
   <             return;
   <
   <         javax.xml.rpc.handler.HandlerRegistry registry = service.
   getHandlerRegistry();
   <         if(registry == null)
   <             return;
   <
   <         java.util.List chain = registry.getHandlerChain(portName);
   <
   <         if(chain == null || chain.isEmpty())
   <             return;
   <
   <         HandlerChainImpl impl
   <             = new HandlerChainImpl(chain);
   <
   <         if(!context.getPastPivot())
   <             impl.handleRequest(context);
   <         else
   <             impl.handleResponse(context);
   <         impl.destroy();
   <     }
   ---
   >
   Index: axis/Constants.java
   ===================================================================
   RCS file: /home/cvspublic/xml-axis/java/src/org/apache/axis/Constants.
   java,v
   retrieving revision 1.83
   diff -r1.83 Constants.java
   410a411
   >     public static final String ATTR_HANDLERINFOCHAIN =
   "handlerInfoChain";
   Index: axis/client/AxisClient.java
   ===================================================================
   RCS file: /home/cvspublic/xml-
   axis/java/src/org/apache/axis/client/AxisClient.java,v
   retrieving revision 1.51
   diff -r1.51 AxisClient.java
   69a70,74
   > import javax.xml.namespace.QName;
   > import org.apache.axis.handlers.HandlerInfoChainFactory;
   > import org.apache.axis.handlers.HandlerChainImpl;
   >
   > import org.apache.axis.Constants;
   211a217,255
   >     }
   >
   >     protected void invokeJAXRPCHandlers(MessageContext context){
   >         Service service
   >             = (Service)context.getProperty(Call.WSDL_SERVICE);
   >         if(service == null)
   >             return;
   >
   >         QName portName = (QName) context.getProperty(Call.
   WSDL_PORT_NAME);
   >         if(portName == null)
   >             return;
   >
   >         javax.xml.rpc.handler.HandlerRegistry registry = service.
   getHandlerRegistry();
   >         if(registry == null)
   >             return;
   >
   >         java.util.List chain = registry.getHandlerChain(portName);
   >
   >         if(chain == null || chain.isEmpty())
   >             return;
   >
   >         SOAPService    soapService = context.getService();
   >         if (soapService != null) {
   >              // A client configuration exists for this service.  Check
   to see
   >              //  if there is a HandlerInfoChain configured upon it.
   >              java.util.List cfgChain = (java.util.List) soapService.
   getOption(Constants.ATTR_HANDLERINFOCHAIN);
   >              // GLT - merge this w/an existing chain
   >              //  for now... use the container version
   >              chain = cfgChain;
   >         }
   >
   >        HandlerInfoChainFactory _handlerChainFactory = new
   HandlerInfoChainFactory(chain);
   >         HandlerChainImpl impl =  (HandlerChainImpl)
   _handlerChainFactory.createHandlerChain();
   >
   >         if(!context.getPastPivot())
   >             impl.handleRequest(context);
   >         else
   >             impl.handleResponse(context);
   >         impl.destroy();
   Index: axis/deployment/wsdd/WSDDConstants.java
   ===================================================================
   RCS file: /home/cvspublic/xml-
   axis/java/src/org/apache/axis/deployment/wsdd/WSDDConstants.java,v
   retrieving revision 1.20
   diff -r1.20 WSDDConstants.java
   130a131,134
   >     public static final String ELEM_WSDD_JAXRPC_HANDLERINFO =
   "handlerInfo";
   >     public static final String ELEM_WSDD_JAXRPC_CHAIN =
   "handlerInfoChain";
   >     public static final String ELEM_WSDD_JAXRPC_ROLE = "role";
   >     public static final String ELEM_WSDD_JAXRPC_HEADER = "header";
   150a155,157
   >     public static final QName QNAME_JAXRPC_HANDLERINFO = new
   QName(URI_WSDD, ELEM_WSDD_JAXRPC_HANDLERINFO);
   >     public static final QName QNAME_JAXRPC_HANDLERINFOCHAIN = new
   QName(URI_WSDD, ELEM_WSDD_JAXRPC_CHAIN);
   >     public static final QName QNAME_JAXRPC_HEADER = new
   QName(URI_WSDD, ELEM_WSDD_JAXRPC_HEADER);
   167a175,177
   >     public static final String ATTR_SOAPACTORNAME = "soapActorName";
   >     public static final String ATTR_CLASSNAME = "classname";
   >
   Index: axis/deployment/wsdd/WSDDService.java
   ===================================================================
   RCS file: /home/cvspublic/xml-
   axis/java/src/org/apache/axis/deployment/wsdd/WSDDService.java,v
   retrieving revision 1.80
   diff -r1.80 WSDDService.java
   86a87,89
   > import org.apache.axis.handlers.HandlerInfoChainFactory;
   > import org.apache.axis.Constants;
   >
   101a105,107
   >  private HandlerInfoChainFactory _hiChainFactory;
   >
   >
   207a214,220
   >        // Add in JAX-RPC support for HandlerInfo chains
   >         Element hcEl = getChildElement(e, ELEM_WSDD_JAXRPC_CHAIN);
   >         if (hcEl != null) {
   >              WSDDJAXRPCHandlerInfoChain wsddHIChain = new
   WSDDJAXRPCHandlerInfoChain(hcEl);
   >             _hiChainFactory = wsddHIChain.getHandlerChainFactory();
   >         }
   >
   401a415,420
   >        // GLT - set handler chain... do we want to subclass?
   >        if (_hiChainFactory != null) {
   >              service.setOption(Constants.ATTR_HANDLERINFOCHAIN,
   _hiChainFactory);
   >
   >        }
   >
   593a613
   >
   Index: axis/handlers/HandlerChainImpl.java
   ===================================================================
   RCS file: /home/cvspublic/xml-
   axis/java/src/org/apache/axis/handlers/HandlerChainImpl.java,v
   retrieving revision 1.2
   diff -r1.2 HandlerChainImpl.java
   71c71,86
   < public class HandlerChainImpl extends ArrayList {
   ---
   > public class HandlerChainImpl extends ArrayList implements javax.xml.
   rpc.handler.HandlerChain {
   >
   >  private String[] _roles;
   >
   >  public String[] getRoles() {
   >        return _roles;
   >  }
   >
   >  public void setRoles(String[] roles) {
   >        _roles = roles;
   >  }
   >
   >  public void init(Map map) {
   >        // DO SOMETHING WITH THIS
   >  }
   >
   Index: axis/providers/java/JavaProvider.java
   ===================================================================
   RCS file: /home/cvspublic/xml-
   axis/java/src/org/apache/axis/providers/java/JavaProvider.java,v
   retrieving revision 1.72
   diff -r1.72 JavaProvider.java
   86a87,89
   > import org.apache.axis.handlers.HandlerChainImpl;
   > import org.apache.axis.handlers.HandlerInfoChainFactory;
   > import javax.xml.rpc.handler.*;
   267a271,275
   >              HandlerInfoChainFactory handlerFactory =
   (HandlerInfoChainFactory) service.getOption(Constants.
   ATTR_HANDLERINFOCHAIN);
   >              HandlerChainImpl handlerImpl = null;
   >              if (handlerFactory != null) handlerImpl =
   (HandlerChainImpl) handlerFactory.createHandlerChain();
   >             if (handlerImpl != null) handlerImpl.
   handleRequest(msgContext);
   >
   280a289,294
   >
   >             if ( handlerImpl != null) {
   >                    handlerImpl.handleResponse(msgContext);
   >                handlerImpl.destroy();
   >             }


Changed files (and new files) themselves...
(See attached file: handler.zip)

Whew!... that's it... What do folks think?

Regards... Greg

Mime
View raw message