I think it's important to establish general principles for these
interoperability cases, and then look at specific cases to see
how the general principles are applied.
The general principle for SCA components communicating over the
Web Service binding is:
1. The service interface is mapped to WSDL (if not already WSDL).
2. The client interface is mapped to WSDL (if not already WSDL).
3. If either interface can't be mapped to WSDL, interoperability
isn't possible and an error should be reported.
4. The SCA compatibility rules are applied to the mapped WSDL
interfaces. If the mapped WSDL interfaces don't pass the
compatibility test, interoperability isn't possible and an
error should be reported.
5. If no errors were reported by steps 3 and 4, the client and
service should interoperate correctly at runtime.
The implication here is that every Java interface and implementation
that passes steps 3 and 4 will also pass step 5. However this isn't
always the case for JAX-WS and JAXB. In some cases it's necessary to
add custom marshalling/unmarshalling code using the @XmlJavaTypeAdapter
annotation to enable the JAXB runtime to successfully marshal and
unmarshal certain object types. In some cases (e.g., interface types)
the need for such customization is detected by the Java-WSDL mapping.
In other cases (e.g., abstract class types), the Java-WSDL mapping
doesn't produce any error message, but it's still necessary to add
custom unmarshalling code to get things to work.
I don't think there's anything special about using an abstract class
as a thrown exception rather than using an abstract class as a passed
or returned parameter. In all these cases the Java-WSDL mapping
works OK without errors, but runtime unmarshalling doesn't work
unless @XmlJavaTypeAdapter is used.
If you want to be able to throw and catch any of a number of concrete
exception classes when using an abstract exception class on the
service interface, you'll need to write a JAXB custom marshalling/
unmarshalling adapter that stores the desired concrete class name
in the XML data passed across the wire for the WSDL fault and uses
this information on the client side to create the correct concrete
subclass. This is effectively what the RMI runtime is doing
automatically for you.
The bottom line is that if using abstract exception classes you need
to write some extra marshalling/unmarshalling adapter code and you
need to design your abstract exception classes to hold the necessary
information to enable custom unmarshalling. If you do this, the same
business exception logic will work over both Web Services and RMI.
Simon
Millies, Sebastian wrote:
Hello there,
in Tuscany SCA 1.6, it seems not to be possible to have a remote method
that declares
an abstract exception class in its interface, and access that method
from a remote node
over a webservice binding.
For example, say CurrencyConverterException is an abstract base class
for my checked
exceptions, and it has UnknownCurrencyException as an immediate concrete
subclass.
Then my service interface and implementation may look like this.
@Remotable
*public* *interface* CurrencyConverter
{
*double* getExchangeRate( String fromCurrencyCode, String
toCurrencyCode ) *throws* CurrencyConverterException;
}
@Service(interfaces =
{ CurrencyConverter.*class* })
*public* *class* CurrencyConverterImpl *implements* CurrencyConverter
{
*public* *double* getExchangeRate( String fromCurrencyCode, String
toCurrencyCode ) *throws* CurrencyConverterException
{
*if*( true )
{
*throw* *new* UnknownCurrencyException( "Unknown source currency:
" + fromCurrencyCode );
}
}
}
The client component has a reference to the CurrencyConverter service:
<sca:component name=/"ClientComponent"/>
<sca:reference name=/"converter"/>
<sca:binding.ws uri=/"http://localhost:8080/CurrencyConverter"//>
</sca:reference>
</sca:component>
When running the client in its own node, calling getExchangeRate on the
injected CurrencyConverter reference,
I will get a _java.lang.InstantiationException _in the class
org.apache.tuscany.sca.interfacedef.java.jaxws.JAXWSFaultExceptionMapper
Of course, the wsdl didn’t change a bit when I changed my service
implementation and made CurrencyConverterException abstract.
A normal JAX-WS Java client can continue to use the JAX-WS artefacts as
it always did and will not encounter this InstantiationException,
because it doesn’t even try to reconstruct a server side exception.
And of course, when using the webservice binding, the client should not
have to rely on technical
implementation details of the server (after all, the whole idea is they
may be implemented in different technologies). So
Tuscany shouldn’t try to give me the original exception, but the
corresponding web fault. Which would force the client
to use different exception handling code for a webservice than say for
an RMI binding. The technologies are just too different
to be handled in a uniform fashion.
We had this point before. I find it interesting that I keep running up
against it in the context of exceptions.
-- Sebastian