In doing some work trying to leverage the Tuscany databinding framework to
transform business exceptions across a binding, I noticed a couple issues
relating to the need to handle both exception and fault DataType(s) .

Basically, I'd like to discuss:

* getting rid of the exception DataType and replacing it with simply a fault
DataType.
* decoupling the fault databinding from the way that the exception maps to a
fault.

Let me explain:

Today, for Java interfaces, we build exception DataTypes during the
introspection phase and we set a databinding upon it.  This DB identifies an
exceptionHandler which can (via getFaultType())  construct a fault DataType
from the exc DataType.

Different exception patterns result in different mappings between exception
and fault data types.   For example, we have the pattern defined by JAX-WS
Sec 2.5 in which the Java exception class wrappers a "fault bean" returned
by the exception's getFaultInfo().   I'm thinking we also want to support
POJO exceptions as well in certain contexts.

Today we would support the JAX-WS Sec. 2.5 pattern by constructing an
DataType wrappering the exception, introspecting the exception to find the
fault and its databinding.   This databinding's exception handler would, at
transform time, be used to construct a fault DataType representing the fault
bean, distinct from the exception DataType.     This more or less works the
same for JAXB and SDO, except that for SDO we have the Tuscany-ism of
looking at FAULT_ELEMENT instead of @WebFault ( which I mention below I'd
like to change).

For the POJO exception pattern, on the other hand, the fault DataType and
exception DataType collapse into one as we see in the logic of
JavaBeansExceptionHandler.

I don't think we need the complexity of the two DataTypes;  I think all we
really need from the exception DataType is its "physical', i.e. the Java
Class of the exception type.   We use this to match the exception we have
in-hand from the Java runtime with the DataType on the operation.   It is
only the fault that gets transformed by the Tuscany databinding framework.

Perhaps what would be better, instead of an exception DataType and fault
DataType, would be to simply have the fault DataType with an additional
"exceptionPhysical" member.    (We still need ExceptionHandler with
getFaultInfo() and createFaultException() as well).

This would let us get the exception handlers out of the introspection
business.

If we look at DataBindingJavaInterfaceProcessor.processInterface() today,
and see how the various databindings' exception handlers' getFaultType()s
are called in order to find the right databinding to set on the exception
DataType, it does seem messy to have to rely on this same getFaultType()
method to work in a certain way and introspection time and transform
time.

The best reason, I think is elegance:  if it is the actual fault DataType
which is interesting at transform time, and if we have an introspect step,
let's have the introspect step set up this interesting fault DataType.
As an example, in  working on some binding impl code in the past, I found
myself calling this same getFaultType() method to get the fault from the
exc...   making for at least three times this same getFaultType() method was
called (Java introspect, my binding construction, and transform time).

Then there is also performance to consider...

---------

In addition, (and to some degree this is a separate point),  I think we
should recognize certain patterns in which a Java exception relates to both
the Java type of the "fault bean" and to a logical type and decouple these
patterns from association with one of the various databinding impls we
support.

So, as an example, if you take the pattern in JAX-WS Sec. 2.5, you can have
an exception with @WebFault(<fault elem>)  with a getFaultInfo() method
returning a fault bean of any of the simple, SDO, or JAXB databindings.
I don't see the rationale for using FAULT_ELEMENT to denote the logical type
when the fault bean is an SDO vs. using the @WebFault for a JAXB;  I think
this pattern should be decoupled from the choice of databinding, and we
don't want the same  algorithm (looking for @WebFault and using reflection
to find the type returned by getFaultInfo(), etc.) to be re-coded for each
databinding.

(Though I don't think Tuscany has it presently, I coded a Simple DB
ExceptionHandler which is largely just a copy of the SDOExceptionHandler,
wihch illustrates my point.   Someone please correct me if Tuscany can
already handle simple-typed fault beans in the JAX-WS Sec 2.5 pattern).


In addition we'd have other patterns like POJO exception and maybe the Axis2
exception which Simon Nash recently did some work regarding.


At this point I'd like to show some sample code, which is part of some
changes I've run with successfully (some of my own tests in my own sandbox -
not Tuscany tests yet).


    public DataType<?> getFaultFromExceptionDataType(DataType<?>
excDataType) {

        //
        // 1. Find the Java type of the fault bean, construct fault DT and
set exc physical
        //
        Object excPhysical = excDataType.getPhysical();
        if (!(excPhysical instanceof Class)) {
            return null;    // Should we be throwing exc instead?
        }
        Class excClass = (Class)excPhysical;
        Class faultBeanClass = null;
        try {
            Method method = excClass.getMethod("getFaultInfo",
EMPTY_CLASS_ARRAY);
            faultBeanClass = method.getReturnType();
        } catch (NoSuchMethodException e) {
            faultBeanClass = null;
        }
        if (faultBeanClass == null) {
            return null;
        }

        // Only the physical is set here.
        DataType faultDataType = new DataTypeImpl(null, faultBeanClass,
null);
        faultDataType.setExceptionPhysical(excClass);

        //
        // 2. Send through already-existing introspection routine
        //

        // Don't try to propagate annotations yet.  Note the DB on the
faultDataType
        // is set by the databinding according to the implied contract we
have going.
        dataBindingRegistry.introspectType(faultDataType, null);

        //
        // 3) instantiate an exception handler for this fault from the
appropriate DB and
        //    set in the fault DT
        //

        DataBinding faultDataBinding = dataBindingRegistry.getDataBinding(
faultDataType.getDataBinding());
        ExceptionHandler excHandler = faultDataBinding.getExceptionHandler
();
        faultDataType.setExceptionHandler(excHandler);

        //
        // 4) set the logical from the @WebFault (FAULT_ELEMENT for now)
        //
        QName faultElement = null;
        try {
            Field field = excClass.getField("FAULT_ELEMENT");
            faultElement = (QName)field.get(null);
        } catch (NoSuchFieldException e) {
            // Ignore
        } catch (Throwable e) {
            // Ignore
        }
        if (faultElement == null) {
            // Should we be responsible for calculating a default fault_elem
            // or leave this to someone else???
            return null;
        }

        // Having set the physical and DB already, we now set the logical of
the fault
        faultDataType.setLogical(new XMLType(faultElement, null));

        return faultDataType;

    }


The above is code that would be called in some form from
DataBindingJavaInterfaceProcessor.processInterface(), passing in the
exception DataType.

In this code, I'm finding the fault bean class through a databinding-neutral
look at the getFaultInfo() return type.  I'm then setting the DB on this
based on the normal DB.introspect() routine (i.e. the same introspection of
input and output types to find the databinding).
Step 4 is to set the logical, again in a databinding-neutral way.

I also have a step 3 where the ExceptionHandler is now stored in the
DataType.   This is a non-trivial change which could probably
really use some improvement (it brings up build and intra-project dependency
issues).     I wanted to have a working prototype before
posting this, however, and this is how I did it.    The ExceptionHandler
still has the job of implementing createException() and getFaultInfo() but
not getFaultType() any more

I also have a simple routine to do something similar for "POJO exceptions"
which do not have a fault bean and which have a Java, not an XML
logical type.

    public DataType<?> getFaultFromExceptionDataType(DataType<?>
excDataType) {

        //
        // 1. Fault physical and Exception physical are one and the same
        //
        Object excPhysical = excDataType.getPhysical();
        if (!(excPhysical instanceof Class)) {
            return null;    // Should we be throwing exc instead?
        }
        Class excClass = (Class)excPhysical;

        // Only the physical is set here.
        DataType faultDataType = new DataTypeImpl(null, excClass, null);
        faultDataType.setExceptionPhysical(excClass);

        //
        // 2. Send through already-existing introspection routine
        //

        // Don't try to propagate annotations yet.  Note the DB on the
faultDataType
        // is set by the databinding according to the implied contract we
have going.
        dataBindingRegistry.introspectType(faultDataType, null);

        //
        // 3) instantiate an exception handler for this fault from the
appropriate DB and
        //    set in the fault DT
        //

        DataBinding faultDataBinding = dataBindingRegistry.getDataBinding(
faultDataType.getDataBinding());
        ExceptionHandler excHandler = faultDataBinding.getExceptionHandler
();
        faultDataType.setExceptionHandler(excHandler);

        //
        // 4) set the logical to be the exc class as well
        //

        // Having set the physical and DB already, we now set the logical of
the fault
        faultDataType.setLogical(excClass);

        return faultDataType;

    }

Assuming it gets that far, I'm not sure whether it would be better to have
these pieces of code in classes which are added to some registry
(like the databinding registry), or whether it would be better to have one,
master, order in which the exception to fault
mapping is assumed to take place in Tuscany.

I coded up a parallel modification in WSDL introspection in the class:
org.apache.tuscany.sca.interfacedef.wsdl.introspect.WSDLOperation.
Basically I just need to set "FaultException" as the exceptionPhysical on
top of what had been done, as the "logical" was being set just fine already.

------------------------------------------------------------------------------

So, this is getting long........

Where I see this going from here is.. if this sounds interesting to people,
it would be interesting to try incorporating
the Axis2 exc->fault mapping pattern with the example from the recent JIRA
Simon worked on into this new view I'm working on.

Another pattern I could imagine would be the one mentioned in JAX-WS Sec.
3.7 in cases in which the exceptions don't conform to the Sec 2.5 pattern.

And it might be that my point about "decoupling" is only partially right.
Maybe the POJO exception case will always be associated with JavaBeans DB
and maybe the JAX-WS Sec 3.7 case will always be associated with JAXB.

However, I wanted to get this posted before thinking through all those
permutations.

Thanks,
Scott

Reply via email to