axis-java-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Gary L Peskin" <ga...@firstech.com>
Subject RE: Soap Fault Explanation (long)
Date Sat, 06 Sep 2003 03:00:08 GMT
I am developing a product that can run in two modes.  It can run
on-platform, where classes A and B are on the same platform, in which case
Axis is uninvolved.  An object of class A calls an object of class B and
that's all there is to it.  However, it can also run off-platform where
class B sits on an Axis server and class A sits on a client.  In this case,
class A invokes a method on class B via Axis using an RPC service.

Class A uses a small loader that I wrote.  If it is running on-platform, it
loads the service class directly.  When running off platform, it loads the
stub generated by wsdl2java.

Class B throws a service specific exception (MyException) that is not a
RuntimeException and not a RemoteException.  It doesn't extend AxisFault
since Axis is not present when running on-platform.  I don't want Axis to be
required when running on-platform.

MyException is pretty much a regular old java exception.  It is immutable so
all of the parameters needed are contained in the constructors for the
exception.  As I read JAX-RPC section 4.3.6, MyException conforms to the
requirements set forth there.

The problem is that, when I use wsdl2java, Axis wants to deserialize this
exception with a BeanDeserializer and MyException is not an Axis-compatible
bean.  It doesn't have a no-argument constructor.  And it doesn't have any
setXXX methods.  As I said, MyException is used in regular java processing
and I want it to look like a regular java exception.  So BeanDeserializer
won't work for me.

Reading the JAX-RPC spec, section 4.3.6, it seems awfully vague about how
Service Specific Exceptions are supposed to be constructed.  It requires
getXXX methods for each field as well as a constructor that contains all of
the fields.  However, you can't find out from reflection what order the
various parameters are supposed to be fed to the constructor.  So, you need
some sort of metadata for this for each constructor.  Unfortunately, this is
not currently supported by Axis, to my knowledge.  It creates a FieldDesc
for each field but doesn't have create OperationDescs for the constructors.

I have found that, by making certain assumptions and a few modifications, I
can get Axis to generate MyException just as I'd like it.  It works for me
but it is not entirely satisfactory for the general case.  I realize that
this is boring for most people who never want to throw MyException and are
content to subclass AxisFault and make their exception classes bean-like.
However, if anyone is really interested in bouncing ideas back and forth,
I'd be happy to work up the patches to Axis to implement a view of Service
Specific Exceptions more in keeping with the JAX-RPC ideas.  What follows is
what works for me and is a starting point for discussion, if anyone but me
is interested.

To keep my exception classes as vanilla as possible, I used the -H option of
wsdl2java to generate Helper classes.  This means that wsdl2java generates a
MyException_Helper class to contain all of the metadata and leaves
MyException itself alone.  The metadata is important because it controls the
order in which the fields will be serialized when running in off-platform
mode.  wsdl2java also generates a new MyException class that extends
AxisFault and has a no-argument constructor and setXXX methods for each
field.  I throw that generated class away.  Then, I manually edit the
getDeserializer() method in the _Helper class to return an
ExceptionDeserializer which is a deserializer that I wrote.
ExceptionDeserializer collects the various fields into a List and then uses
that List to find the appropriate constructor and invoke it in
ExceptionDeserializer.onEndElement(...).

This allows me to create MyException provided I follow certain rules.  The
fields in the exception are serialized on the server side in the order that
the FieldDescs appear in the metadata.  So, I need to be sure that I have a
constructor that takes the fields in the same order as the metadata (ie the
same order in which the fields were serialized).  JAX-RPC is pretty weak in
describing how the JAX-RPC implementation is supposed to invoke the
constructor.  I suppose I could add in OperationDescs for each constructor
but that seemed too much like work.  And what if I had two constructors
taking the same parameters in a different order.  How would I choose which
one to invoke?  It seems like someone needs to come up with various use
cases for throwing Service Specific Exceptions and follow those out when
revising the JAX-RPC spec.

If I want to include the message in my constructor, I have to add a
getMessage() method into my exception class since it is not picked up in the
metadata from Throwable.  That is no problem.

The next issue comes with actually throwing MyException.  The big problem
here is that a service may be invoked using the Call.invoke(...) methods.
JAX-RPC specifies in the Call interface that these methods throw
RemoteException.  Therefore, any exception that I throw needs to be wrapped
in a RemoteException if I'm using a conforming JAX-RPC implementation.
Since other classes called from invoke() have a signature indicating that
they throw an AxisFault, my ExceptionDeserializer creates an AxisFault
(which is a RemoteException) specifying my actual MyException instance as
the cause.

Since the stub calls Call.invoke(Object[]), it needs to catch the AxisFault
that gets thrown and determine if this is wrapping a RuntimeException or a
Service Specific Exception.  If so, it is the stub that needs to "unwind"
the AxisFault and throw the original exception back to the caller of the
Stub.  This forces me to add a little bit of code into the generated Stub.
As it is, the Stub is checking for a return value (not a throw) of a
RemoteException which is something that I find very curious.

At the moment, I'm editing the generated stub by hand but this is a pain
because I have to re-edit it every time I regenerate it.  As the number of
generated stubs increases, this will become increasingly annoying so I'm
going to have to modify that part of wsdl2java that generates the stub.

If anyone has thoughts or questions on this, fire away.  At least, I've
gotten pretty familiar with wsdl:fault handling which seems to be an area of
confusion for many.

Can any of the developers comment on whether there are plans to revamp the
Service Specific Exception handling to make it JAX-RPC compliant?  If so, is
someone looking for help?

Gary


> -----Original Message-----
> From: Cory Wilkerson [mailto:cwilkerson@travelnow.com]
> Sent: Wednesday, August 27, 2003 9:52 AM
> To: axis-user@ws.apache.org
> Subject: RE: Soap Fault Explanation
> 
> 
> Gary -- what version of Axis are you running?
> 
> -----Original Message-----
> From: Gary L Peskin [mailto:garyp@firstech.com]
> Sent: Wednesday, August 27, 2003 11:44 AM
> To: axis-user@ws.apache.org
> Subject: RE: Soap Fault Explanation
> 
> 
> The client is java.  However, my Stub is called from a method
> that can either call the Stub class or, in certain 
> situations, call the endpoint service class directly, not via 
> Axis.  I want my service class to just throw the exception, 
> which the client will see.  If the client called the service 
> class directly, it should see the exception via the normal 
> java exception mechanism.  Therefor, I'd like the client to 
> always see the same exception and not have to worry if it's 
> wrapped in an AxisFault or not.
> 
> I'm making good progress in my investigation.  Using tcpmon,
> it looks like the exception is properly thrown and serialized 
> back to the client.  At the moment, I'm zeroing in on 
> SOAPFaultBuilder.createFault() which does not seem to be 
> deserializing this properly.
> 
> Gary
> 
> > -----Original Message-----
> > From: Hansen, Richard [mailto:richard.hansen@thomson.com]
> > Sent: Wednesday, August 27, 2003 9:35 AM
> > To: 'axis-user@ws.apache.org'
> > Subject: RE: Soap Fault Explanation
> > 
> > 
> > I wonder if it depends on the client. Is it java or something else. 
> > If not Java then AxisFault could be useful to get the code and 
> > details the way you want. AxisFault has a
> > writeDetails() method that serializes your service specific fields.
> > 
> > > -----Original Message-----
> > > From: Gary L Peskin [mailto:garyp@firstech.com]
> > > Sent: Wednesday, August 27, 2003 11:22 AM
> > > To: axis-user@ws.apache.org
> > > Subject: RE: Soap Fault Explanation
> > > 
> > > 
> > > Cory et al --
> > > 
> > > I'm looking into this code very carefully at the moment.
> I'm trying
> > > to generate Service Specific Exceptions but having problems on the 
> > > client side where an AxisFault is thrown rather than my actual 
> > > exception.  My Service
> > > Specific Exceptions extend Exception but not AxisFault.
> > > 
> > > Do your Service Specific Exceptions contain a no-argument
> > > constructor?  As I read JAX-RPC, this shouldn't be necessary.
> > > 
> > > I'm currently heavily into investigating this code to see
> > if there's
> > > something wrong I'm doing on my end.
> > > 
> > > Thanks,
> > > Gary
> > > 
> > > > -----Original Message-----
> > > > From: Cory Wilkerson [mailto:cwilkerson@travelnow.com]
> > > > Sent: Wednesday, August 27, 2003 8:02 AM
> > > > To: axis-user@ws.apache.org
> > > > Subject: RE: Soap Fault Explanation
> > > > 
> > > > 
> > > > "I know that this question has been asked again and again but I
> > > > can't find the answer." -- Sorry, didn't mean to sound terse or 
> > > > harsh there, just implying that maybe the Axis folk 
> would like to
> > > > crank out some decent documentation regarding the matter.  I've
> > > > been using Axis for 4 or 5 months and didn't know you could 
> > > > specify all the parameters as you did below -- that's 
> all manner
> > > > of interesting.  Where did you find the documentation
> for *that*?
> > > > 
> > > > Richard -- I'd refute *some* of your points, though I'm
> certainly
> > > > glad someone has some decent knowledge in this realm.  The
> > > > exception I'm successfully serializing does not subclass Axis 
> > > > fault and the only config I did was in the wsdl (which I didn't 
> > > > generate server side ties from) and in server-config my 
> providing
> > > > a beanMapping entry for my service specific exception.  I'm
> > > > successfully catching my specific exception on the client side 
> > > > with both Axis and .NET platforms -- Axis manages to throw my 
> > > > exception type on the client side whereas with the .NET 
> platform,
> > > > I parse it out of the detail element returned in the fault.
> > > > 
> > > > All that said, I am using the nightly builds as opposed
> to the 1.0
> > > > release.
> > > > 
> > > > Cory
> > > > 
> > > > 
> > > > -----Original Message-----
> > > > From: Hansen, Richard [mailto:richard.hansen@thomson.com]
> > > > Sent: Wednesday, August 27, 2003 9:48 AM
> > > > To: 'axis-user@ws.apache.org'
> > > > Subject: RE: Soap Fault Explanation
> > > > 
> > > > 
> > > > If you define the exceptions in your WSDL as "faults" in the
> > > > appropriate pacles. Then wsdl2Java will generate your exception 
> > > > classes and create the
> > > > required config setup in the stubs and skeletons it generates.
> > > > 
> > > > My notes of axis fault handling:
> > > > Faults
> > > > - For all practical purposes a client programmer can
> treat Axis as
> > > > if it only throws
> > > >   org.apache.axis.AxisFault exceptions.
> > > > - Axis does not throw javax.xml.rpc.soap.SOAPFaultException. 
> > > > Axis never
> > > > creates a SOAPFaultException itself.
> > > >   However, since SOAPFaultException is unchecked, one could 
> > > > leak through if
> > > > thrown by a handler or service 
> > > >   implementation. 
> > > > - The invoke methods that are likely to be called by a client 
> > > > programmer
> > > > (the ones inherited from 
> > > >   javax.xml.rpc.Call) return either a service specific 
> > exception or
> > > > org.apache.axis.AxisFault.
> > > > - A service implementation can throw any type of exception.
> > > > - Axis faults thrown by a service implementation are returned
> > > > to the client
> > > > just as thrown. 
> > > > - A non AxisFault thrown by a service implementation but not 
> > > > configured as a
> > > > service specific exception 
> > > >   will be wrapped in an AxisFault on the client. A faultCode of
> > > > Server.userException and a local stack trace 
> > > >   will be included in the Axisfault. This is not the most 
> > > > useful thing that
> > > > could happen as it tends to hide 
> > > >   the source/cuase of the exception. The fault string 
> > > > included represents
> > > > the original exception.
> > > > - Axis must be configured to handle service specific 
> > > > exceptions and recreate
> > > > them on the client. 
> > > > - Service specific exceptions can can be configured using 
> > > > either parameters
> > > > in the wsdd deployment file or 
> > > >   using calls to org.apache.axis.description.OperationDesc in 
> > > > the service
> > > > stubs and skeletons. 
> > > > - Service specific exceptions must subclass 
> > > > org.apache.axis.AxisFault. 
> > > > - The WSDL to Java tools will create service specific 
> > > > exceptions that are
> > > > defined in a wsdl file and
> > > >   create the required configuration code in the stubs and 
> > skeletons
> > > > generated.
> > > > 
> > > > > -----Original Message-----
> > > > > From: Marco Spinetti [mailto:m.spinetti@pisa.iol.it]
> > > > > Sent: Wednesday, August 27, 2003 9:37 AM
> > > > > To: axis-user@ws.apache.org
> > > > > Subject: RE: Soap Fault Explanation
> > > > > 
> > > > > 
> > > > > Thanks Cory: I know that this question has been asked again
> > > > and again
> > > > > but I can't find the answer.
> > > > > 
> > > > > My steps have been:
> > > > > 
> > > > > - create the wsdl
> > > > > - use org.apache.axis.wsdl.WSDL2Java with --server-side
> > > > > - implementing MySearchBindingImpl.java
> > > > > - copy deploy.wsdd (service part) to server-config.wsdd
> > > > > 
> > > > > All is ok except when an axception is generated.
> > > > > 
> > > > > My service element in server-config.wsdd is:
> > > > > 
> > > > > <service name="MySearchPort" provider="java:RPC" style="rpc" 
> > > > > use="encoded">
> > > > >       <parameter name="wsdlTargetNamespace" 
> > > > > value="urn:AriannaSearch"/>
> > > > >       <parameter name="wsdlServiceElement" 
> > > > > value="AriannaSearchService"/>
> > > > >       <parameter name="wsdlServicePort"
> > > value="AriannaSearchPort"/>
> > > > >       <parameter name="className" 
> > > > > value="AriannaSearch.AriannaSearchBindingImpl"/>
> > > > >       <parameter name="wsdlPortType"
> value="AriannaSearchPort"/>
> > > > >       <operation name="doAriannaSearch"
> > > > qname="operNS:doAriannaSearch"
> > > > > xmlns:operNS="urn:AriannaSearch" returnQName="return" 
> > > > > returnType="rtns:AriannaSearchResult"
> > > > > xmlns:rtns="urn:AriannaSearch" >
> > > > >         <parameter name="query" type="tns:string"
> > > > > xmlns:tns="http://www.w3.org/2001/XMLSchema"/>
> > > > >         <parameter name="pagina" type="tns:int" 
> > > > > xmlns:tns="http://www.w3.org/2001/XMLSchema"/>
> > > > >         <parameter name="service" type="tns:string" 
> > > > > xmlns:tns="http://www.w3.org/2001/XMLSchema"/>
> > > > >         <parameter name="nameparam" type="tns:ArrayOfString" 
> > > > > xmlns:tns="urn:AriannaSearch"/>
> > > > >         <parameter name="valueparam" type="tns:ArrayOfString"

> > > > > xmlns:tns="urn:AriannaSearch"/>
> > > > >         <fault name="doAriannaException" qname="fns:fault" 
> > > > > xmlns:fns="urn:AriannaSearch" 
> > class="AriannaSearch.DoAriannaExcep
> > > > > tion" type="tns:doAriannaException"
> > > xmlns:tns="urn:AriannaSearch"/>
> > > > >       </operation>
> > > > >       <parameter name="allowedMethods"
> value="doAriannaSearch"/>
> > > > > 
> > > > >       <typeMapping
> > > > >         xmlns:ns="urn:AriannaSearch"
> > > > >         qname="ns:ResultElementArray"
> > > > >         type="java:AriannaSearch.ResultElement[]"
> > > > >         
> > > > > 
> serializer="org.apache.axis.encoding.ser.ArraySerializerFactory"
> > > > >        
> > > > > 
> > > 
> deserializer="org.apache.axis.encoding.ser.ArrayDeserializerFactory"
> > > > >         
> > encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
> > > > >       />
> > > > >       <typeMapping
> > > > >         xmlns:ns="urn:AriannaSearch"
> > > > >         qname="ns:AriannaSearchResult"
> > > > >         type="java:AriannaSearch.AriannaSearchResult"
> > > > >         
> > > > > 
> serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
> > > > >        
> > > > > 
> > > 
> deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
> > > > >         
> > encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
> > > > > 
> > > > > 
> > > > > 
> > > > > 
> > > > > Il mer, 2003-08-27 alle 16:26, Cory Wilkerson ha scritto:
> > > > > > This question has been asked time and again and I've yet to
> > > > > see a real definitive answer come through.  For starters, you
> > > > > might want to try some of the Axis nightly drops, I've had 
> > > > > better luck with them serializing my exceptions.
> > > > > > 
> > > > > > In the case where I have exceptions working, I've
> > > > > subclassed exception and according to the jax-rpc
> specification
> > > > > (I don't know if Axis pays any attention here at all with
> > > > > exceptions):
> > > > > > 
> > > > > > 1. Provided accessors for each parameter supplied to my
> > > > > constructor (and conversely ensured that each accessor had a
> > > > > parameter in the constructor).
> > > > > > 2. Ensured that the parameter type in constructor was
> > > > > identical to return type of accessor.
> > > > > > 3. Ensured that there was only one accessor with a given
> > > > > return type (I actually cheated here though I would
> expect I'll
> > > > > see some crazy results because of it.)
> > > > > > 
> > > > > > I also am not sure if Axis appropriately generates fault
> > > > > elements in your WSDL based on your exception type.  If you
> > > > > don't see it in the WSDL you're generating stubs 
> against, you'll
> > > > > never see an "exception" in you client code.
> > > > > > 
> > > > > > Good luck!
> > > > > > Cory
> > > > > > 
> > > > > > 
> > > > > > 
> > > > > > -----Original Message-----
> > > > > > From: Marco Spinetti [mailto:m.spinetti@pisa.iol.it]
> > > > > > Sent: Wednesday, August 27, 2003 9:13 AM
> > > > > > To: axis-user@ws.apache.org
> > > > > > Subject: Soap Fault Explanation
> > > > > > 
> > > > > > 
> > > > > > Hi,
> > > > > > 
> > > > > > I'm developing a soap web service with axis (my
> > > > > configuration is apache
> > > > > > + tomcat with axis).
> > > > > > 
> > > > > > In some circumstances my web services has to create a SOAP
> > > > > fault which
> > > > > > has to be sent to the client.
> > > > > > 
> > > > > > I'm a a bit confused with Axis management of SOAP fault
> > > > > (I've tried to
> > > > > > read email in mailing list but without success too).
> > > > > > 
> > > > > > I've declared my Exception:
> > > > > > 
> > > > > > public class DoMyException  extends
> org.apache.axis.AxisFault
> > > > > > implements java.io.Serializable {
> > > > > >     private int codice;
> > > > > >     private java.lang.String stringa;
> > > > > > 
> > > > > >     public DoMyException() {
> > > > > >     }
> > > > > > 
> > > > > >     public DoMyException(
> > > > > >            int codice,
> > > > > >            java.lang.String stringa) {
> > > > > >         this.codice = codice;
> > > > > >         this.stringa = stringa;
> > > > > >     }
> > > > > > .......
> > > > > >  }
> > > > > > 
> > > > > > In my web services method, in some circumstances, I
> throw such
> > > > > > exception:
> > > > > > 
> > > > > > public MySearchResult doMySearch(java.lang.String
> > query) throws
> > > > > > java.rmi.RemoteException, DoMyException {
> > > > > >         
> > > > > > 	......
> > > > > > 
> > > > > > 	try {
> > > > > > 		if (cond) {
> > > > > > 			throw new DoMyException(1,
> > > "Description");
> > > > > > 		}
> > > > > > 	}
> > > > > > 	catch (DoMyException e) {
> > > > > > 		......		
> > > > > > 		throw e;
> > > > > > 	}
> > > > > > .....
> > > > > > }
> > > > > > 
> > > > > > 
> > > > > > When in my test client I try to generate a SOAP fault I
> > > > > don't receive
> > > > > > anything. With SOAPMonitor I see the request SOAP message
> > > > > but not the
> > > > > > response.
> > > > > > 
> > > > > > My client:
> > > > > > 
> > > > > > try {
> > > > > >        MySearchService service = new
> MySearchServiceLocator();
> > > > > >        MySearchPort port = service.getMySearchPort();
> > > > > > 
> > > > > > 	.........
> > > > > >        MySearchResult r = port.doMySearch(query);
> > > > > > 
> > > > > > 	.....
> > > > > > }
> > > > > > catch (DoMyException e) {
> > > > > >      System.err.println("Cod  = " + e.getCodice());
> > > > > >      System.err.println("String = " + e.getStringa());
> > > > > >      System.exit(1);
> > > > > > }
> > > > > > 
> > > > > > 
> > > > > > Probably I'm making some mistakes but I don't see where.
> > > > > > 
> > > > > > Any help would be very useful.
> > > > > > 
> > > > > > Thanks
> > > > > > 
> > > > > > 
> > > > > > Bye
> > > > > > 
> > > > > > --Marco
> > > > > > 
> > > > > > 
> > > > > > 
> > > > > > 
> > > > > 
> > > > 
> > > 
> > 
> 


Mime
View raw message