Hi, 1) The org.apache.tuscany.sca.binding.jms.ExceptionService interface is remotable but the CheckedException is a plain java exception and it doesn't follow the JAXWS pattern to represent a fault. In this case, the construction of the ChjeckedException is heuristic.
2) I further debugged the root cause of the null faultInfo. On the following stack, it seems that WireFormatJMSTextXMLServiceInterceptor is not doing its job to correctly marshal the fault data into the response JMS message. Even though the wireFormat is textXML, the TransportServiceInterceptor catches the exception, creates a JMSObjectMessage, sets the exception as an Object and sends it back as a response. The WireFormatJMSTextXMLServiceInterceptor doesn't have a chance to format the fault JMSMessage as textXML. Thanks, Raymond Thread [ActiveMQ Session Task] (Suspended (breakpoint at line 25 in ExceptionServiceImpl)) ExceptionServiceImpl.throwChecked() line: 25 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] NativeMethodAccessorImpl.invoke(Object, Object[]) line: 79 DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 Method.invoke(Object, Object...) line: 618 JavaImplementationInvoker.invoke(Message) line: 132 DataTransformationInterceptor.invoke(Message) line: 78 RuntimeWireInvoker.invoke(InvocationChain, Message, RuntimeWire) line: 129 RuntimeWireInvoker.invoke(RuntimeWire, Operation, Message) line: 104 RuntimeWireInvoker.invoke(Operation, Message) line: 98 RuntimeWireInvoker.invoke(Message) line: 86 WireFormatJMSTextXMLServiceInterceptor.invoke(Message) line: 68 OperationSelectorJMSDefaultServiceInterceptor.invoke(Message) line: 78 TransportServiceInterceptor.invoke(Message) line: 77 RuntimeWireImpl.invoke(Message) line: 149 RRBJMSBindingListener.invokeService(Message) line: 100 RRBJMSBindingListener.onMessage(Message) line: 76 ActiveMQMessageConsumer.dispatch(MessageDispatch) line: 1021 ActiveMQSessionExecutor.dispatch(MessageDispatch) line: 122 ActiveMQSessionExecutor.iterate() line: 192 PooledTaskRunner.runTask() line: 122 PooledTaskRunner$1.run() line: 43 ThreadPoolExecutor$Worker.runTask(Runnable) line: 665 ThreadPoolExecutor$Worker.run() line: 690 Thread.run() line: 810 From: ant elder Sent: Wednesday, January 07, 2009 10:30 AM To: [email protected] Subject: Re: [1.4] Change in Exception handling behaviour for binding.jms To show what I mean i've committed some fixes in r732415 and r732416 which get the testcase working, this isn't a finished fix it just to show where the code is going wrong. I haven't looked at the JAXWSFaultExceptionMapper code in any detail, should it be dealing with a null faultInfo is is the bug that faultInfo isn't getting setup correctly? ...ant On Wed, Jan 7, 2009 at 6:16 PM, ant elder <[email protected]> wrote: It turns out its a bit more complicated that that, i think it is the FaultException that needs to be returned up the chain so that the databinding can transform that back into the user exception, and there is a bug in AbstractMessageProcessor either the createFaultMessage or extractPayloadMessage needs to pull the FaultException out of the InvocationTargetException, but then fixing that the JAXWSFaultExceptionMapper gets an NPE on line 129 as faultInfo is null. Does that all sound plausible? ...ant On Wed, Jan 7, 2009 at 5:39 PM, Raymond Feng <[email protected]> wrote: IIRC, we intentionally return a FaultException to wrap the user exception from the transformation to indicate there is a user fault. The extractPayloadMessage should extract the user exception from the FaultException. Thanks, Raymond From: ant elder Sent: Wednesday, January 07, 2009 9:33 AM To: Raymond Feng Cc: [email protected] Subject: Re: [1.4] Change in Exception handling behaviour for binding.jms OK that helps, but also debugging there you see its too late at that point as the service response message sent back from the service already contains the wrong exception. Debugging on the service side this is the stack from where it goes wrong: Thread [ActiveMQ Session Task] (Suspended) DataTransformationInterceptor.invoke(Message) line: 159 RuntimeWireInvoker.invoke(InvocationChain, Message, RuntimeWire) line: 129 RuntimeWireInvoker.invoke(RuntimeWire, Operation, Message) line: 104 RuntimeWireInvoker.invoke(Operation, Message) line: 98 RuntimeWireInvoker.invoke(Message) line: 86 WireFormatJMSTextXMLServiceInterceptor.invoke(Message) line: 68 OperationSelectorJMSDefaultServiceInterceptor.invoke(Message) line: 78 TransportServiceInterceptor.invoke(Message) line: 77 RuntimeWireImpl.invoke(Message) line: 149 RRBJMSBindingListener.invokeService(Message) line: 100 RRBJMSBindingListener.onMessage(Message) line: 76 ActiveMQMessageConsumer.dispatch(MessageDispatch) line: 1021 ActiveMQSessionExecutor.dispatch(MessageDispatch) line: 122 ActiveMQSessionExecutor.iterate() line: 192 PooledTaskRunner.runTask() line: 122 PooledTaskRunner$1.run() line: 43 ThreadPoolExecutor$Worker.runTask(Runnable) line: not available ThreadPoolExecutor$Worker.run() line: not available Thread.run() line: not available Before DataTransformationInterceptor.invoke(Message) line: 159 is run the "result" variable contains the correct original application exception and thats what we'd like gets sent back to the clinet, but after transformException is called at line 160 "newResult" is a org.apache.tuscany.sca.interfacedef.util.FaultException instance and that is whats returned to the client. Is this related to the value of sourceFaultType which is: sourceFaultType DataTypeImpl<L> (id=265) dataBinding "org.apache.axiom.om.OMElement" (id=282) genericType Class<T> (java.lang.Object) (id=9) logical XMLType (id=298) metaDataMap null physical Class<T> (java.lang.Object) (id=9) perhaps thats not correct with the way all the wireformats and databindings are working now for JMS where really is just wanting to send back the application exception in the response message? ...ant On Wed, Jan 7, 2009 at 4:40 PM, Raymond Feng <[email protected]> wrote: Hi, I debugged the test case and found the code on the following stack is problematic: org.osoa.sca.ServiceRuntimeException: remote service exception, see nested exception at org.apache.tuscany.sca.binding.jms.provider.AbstractMessageProcessor.extractPayloadFromJMSMessage(AbstractMessageProcessor.java:92) at org.apache.tuscany.sca.binding.jms.wireformat.jmstextxml.runtime.WireFormatJMSTextXMLReferenceInterceptor.invokeResponse(WireFormatJMSTextXMLReferenceInterceptor.java:107) at org.apache.tuscany.sca.binding.jms.wireformat.jmstextxml.runtime.WireFormatJMSTextXMLReferenceInterceptor.invoke(WireFormatJMSTextXMLReferenceInterceptor.java:82) at org.apache.tuscany.sca.binding.jms.provider.RRBJMSBindingInvoker.invoke(RRBJMSBindingInvoker.java:201) at org.apache.tuscany.sca.core.databinding.wire.DataTransformationInterceptor.invoke(DataTransformationInterceptor.java:78) at org.apache.tuscany.sca.core.invocation.JDKInvocationHandler.invoke(JDKInvocationHandler.java:287) at org.apache.tuscany.sca.core.invocation.JDKInvocationHandler.invoke(JDKInvocationHandler.java:154) at $Proxy21.throwChecked(Unknown Source) at org.apache.tuscany.sca.binding.jms.ExceptionServiceClient.throwChecked(ExceptionServiceClient.java:38) When the JMSMessage contains a fault (user exception), the AbstractMessageProcessor.extractPayloadFromJMSMessage() method should not throw a ServiceRuntimeException, instead it should call Message.setFaultBody with the user exception extracted from the FaultException. public Object extractPayloadFromJMSMessage(Message msg) { try { if (msg.getBooleanProperty(JMSBindingConstants.FAULT_PROPERTY)) { // ----------------- [rfeng] This is wrong ---------------------- throw new ServiceRuntimeException("remote service exception, see nested exception", (Throwable)((ObjectMessage)msg).getObject()); } } catch (JMSException e) { throw new JMSBindingException(e); } return extractPayload(msg); } Thanks, Raymond From: ant elder Sent: Wednesday, January 07, 2009 4:24 AM To: [email protected] Subject: Re: [1.4] Change in Exception handling behaviour for binding.jms On Wed, Jan 7, 2009 at 11:12 AM, Dave Sowerby <[email protected]> wrote: Hey guys, I'm trying to upgrade an application from Tuscany 1.3.2 to 1.4 RC4, the application uses binding.jms and I've noticed a marked change in behaviour for Exception handling - could someone tell me if this is expected and if there is any means of getting a handle on the original Exception? Basically, the service throws a UserException with a message, but on the client side I get the following Exception hierarchy: org.osoa.sca.ServiceRuntimeException -> org.osoa.sca.ServiceRuntimeException -> java.lang.reflect.InvocationTargetException -> org.apache.tuscany.sca.interfacedef.util.FaultException Where the FaultException contains the original message from the UserException. Back in 1.3.2, for Exceptions the client would have a reconsituted equivilant of the original Exception thrown. Any guidance would be greatly appreciated, Cheers, Dave. That sounds like http://issues.apache.org/jira/browse/TUSCANY-2593 which sadly although marked as a blocker didn't get fixed in the 1.4 RC. The problem is due to the way the DataTransformationInterceptor handles the exception is different now so the way the JMS binding returns the service exception doesn't get returned to the client as before. Tracing through the code i can get it to DataTransformationInterceptor line 147 where the sourceDataType gets set to org.apache.tuscany.sca.interfacedef.util.FaultException which is what the transform on line 159 produces so the original exception from the remote service is lost. There's quite a few FIXME comments around here in the DataTransformationInterceptor so i'm not sure how this is supposed to work, you'd think it must be common across all bindings - does any one know is there a fixed way a binding can return an application checked exception object and have the data binding framework just return that to the client? ...ant
