RMIServiceBindingProvider handles InvocationTargetException incorrectly
-----------------------------------------------------------------------
Key: TUSCANY-3665
URL: https://issues.apache.org/jira/browse/TUSCANY-3665
Project: Tuscany
Issue Type: Bug
Affects Versions: Java-SCA-1.6
Environment: JDK 1.6.0_18, Windows XP
Reporter: Sebastian Millies
I have made a service available through the RMI-Binding as follows:
<composite xmlns="http://www.osoa.org/xmlns/sca/1.0"
xmlns:tuscany="http://tuscany.apache.org/xmlns/sca/1.0"
targetNamespace="http://tuscanyscatours.com/"
name="currencyconverter2">
<component name="CurrencyConverter2"
promote="CurrencyConverter2/CurrencyConverter">
<implementation.java
class="com.tuscanyscatours.currencyconverter.impl.CurrencyConverterImpl" />
<service name="CurrencyConverter">
<interface.java
interface="com.tuscanyscatours.currencyconverter.CurrencyConverter" />
<tuscany:binding.rmi host="localhost" port="1099"
serviceName="CurrencyConverterRMI"/>
</service>
</component>
</composite>
The service is allowed to throw a checked Exception. Here are the interface and
implementation:
@Remotable
public interface CurrencyConverter extends java.rmi.Remote
{
// intended to throw a checked exception
double getExchangeRate( String fromCurrencyCode, String toCurrencyCode )
throws RemoteException,
CurrencyConverterFault_Exception;
}
@Service(interfaces = { CurrencyConverter.class })
public class CurrencyConverterImpl extends UnicastRemoteObject implements
CurrencyConverter
{
public CurrencyConverterImpl() throws RemoteException { }
public double getExchangeRate( String fromCurrencyCode, String toCurrencyCode
)
throws CurrencyConverterFault_Exception
{
// note the use of JAX-WS artifacts. The fault bean class has been made
serializable, so this works over RMI as well
CurrencyConverterFault faultBean = new CurrencyConverterFault();
faultBean.setMessage( "Unknown target currency: " + toCurrencyCode);
throw new CurrencyConverterFault_Exception( "Currency conversion fault",
faultBean );
}
}
When I call the service, I expect a CurrencyConverterFault_Exception to be
thrown. This is exactly what happens
when I use a pure Java RMI client (or a webservice client when I also provide
binding.ws):
Registry registry = LocateRegistry.getRegistry( "localhost" );
String name = "CurrencyConverterRMI";
CurrencyConverter converter = (CurrencyConverter) registry.lookup( name );
try
{
System.out.println( "ExchangeRate = " + converter.getExchangeRate( "XYZ",
"GBP" ) ); // (*)
}
catch( CurrencyConverterFault_Exception e )
{
System.out.println( e.getFaultInfo().getMessage() );
}
However, when I deploy the composite in the Tuscany runtime and access it over
the RMI binding, I get a
java.rmi.UnexpectedException instead:
SCADomain scaDomain =
SCADomain.newInstance("currency-converter-rmi.composite");
CurrencyConverter converter = scaDomain.getService(
CurrencyConverter.class, "CurrencyConverter2/CurrencyConverter" );
try
{
System.out.println( "ExchangeRate = " + converter.getExchangeRate( "XYZ",
"GBP" ) ); // (**)
}
catch( CurrencyConverterFault_Exception e ) // <-- not caught
{
System.out.println( e.getMessage() );
}
catch( Exception e )
{
System.out.println( "UnexpectedException: " + e.getMessage() ); // <--
here
}
The reason may be a mistake in
org.apache.tuscany.sca.binding.rmi.provider.RMIServiceBindingProvider#createRmiService.
I believe the MessageInterceptor that is set as a callback does not handle
InvocationTargetExceptions correctly. In particular,
it seems to confuse the "cause" and "targetException" attributes of
InvocationTargetExceptions. I have inserted some code
as follows to test this hypothesis:
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object arg0, Method method, Object[] args,
MethodProxy arg3) throws Throwable {
try {
return invokeTarget(JavaInterfaceUtil.findOperation(method,
serviceInterface.getOperations()), args);
} catch (InvocationTargetException e) {
final Throwable targetException = e.getTargetException();
// <-- insert
for (Class<?> declaredType : method.getExceptionTypes()) {
// <-- insert
if (declaredType.isInstance(targetException)) {
// <-- insert
throw targetException;
// <-- insert
}
// <-- insert
}
// <-- insert
final Throwable cause = e.getCause();
With this change, the two calls in lines (*) and (**) behave identically, as it
should be, because now the
java.rmi.server.RemoteObjectInvocationHandler finds a declared exception type
that is assignable from the thrown
exception type (which it doesn't if it is simply passed an
InvocationTargetException).
Perhaps bug TUSCANY-2406 is related.
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.