IMO, the wire format controls how business data and/or fault are represented
in the JMSMessage. The following is quoted from the OSOA JMS binding spec
1.0:
217 1.5.2 Default Data Binding
218 The default data binding behavior maps between a JMSMessage and the
object(s) expected by
219 the component implementation. We encourage component implementers to
avoid exposure of
220 JMS APIs to component implementations, however in the case of an
existing implementation that
221 expects a JMSMessage, this provides for simple reuse of that as an SCA
component.
222 The message body is mapped to the parameters or return value of the
target operation as
223 follows:
224 . If there is a single parameter or return value that is a JMSMessage,
then the JMSMessage is
225 passed as is.
226 . Otherwise, the JMSMessage must be a JMS text message containing XML.
227 . If there is a single parameter, or for the return value, the JMS text
XML payload is the XML
228 serialization of that parameter according to the WSDL schema for the
message.
229 . If there are multiple parameters, then they are encoded in XML using
the document wrapped
230 style, according to the WSDL schema for the message.
And the SCA java spec says:
1715 1.9. WSDL to Java and Java to WSDL
1716 The SCA Client and Implementation Model for Java applies the WSDL to
Java and Java to WSDL mapping
1717 rules as defined by the JAX-WS specification [4] for generating
remotable Java interfaces from WSDL
1718 portTypes and vice versa.
Based on this, my assumption is for text/xml wire format, we follow the Java
to WSDL mapping rules defined by JAXWS. It should also apply to fault data.
Passing exceptions as Objects in JMSMessage seems to be a backdoor and it is
not consistent with the wire format. It requires both client and service
side have the same CheckedException class.
Thanks,
Raymond
From: ant elder
Sent: Wednesday, January 07, 2009 12:02 PM
To: [email protected]
Subject: Re: [1.4] Change in Exception handling behaviour for binding.jms
Ok, looks like we are getting to the bottom of this, those two points are
exactly what and why it worked in previous releases ;)
The JMS spec doesn't define how to handle exceptions so there's nothing that
says the exception needs to follow the JAXWS pattern and ideally it
shouldn't need to. The TransportServiceInterceptor creates a
JMSObjectMessage to return the exception as in the previous releases thats
how this was able to work - it didn't delegate everything to the databinding
framework so the on the client side the invoke spotted the response was an
exception and didn't use the databinding framework to do any transformations
but just returned the received exception.
As we know the exception response wont be XML so wont need a databinding
framework transformation could we prevent the transformation happening by
changing the WireFormatJMSTextXMLReferenceProvider constructor around line
82 to not reset the datatype of the fault types to OMElement?
...ant
On Wed, Jan 7, 2009 at 7:37 PM, Raymond Feng <[email protected]> wrote:
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