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.