Reputation: 415
I have to customize the error handling for my project . In case of error, depending on the error type, I want to send it to different queues.
However, before sending it to the queues depending on the type we do some transformations in the exception message along with the conversion of object to String (For which I am using the transformer
) so that the queue can have the object value as the message text, so that we can track easily.
Now the problem is, during the conversion of object to String or any other error (code specific) occurs , service starts to throw an exception with no error channel has been registered.
This Error handling code is generalized for several components, hence in case of any failure even in transformation. I want to pass the exception to the Error Transformer
, to pass it to Error Queue
.
XML configuration for Error is:
<int:transformer id = "errorTransformer" input-channel="errorsDest"
ref="exceptionTransformer" output-channel="errors" />
<bean id="exceptionTransformer"
class="com.commons.spring.integration.error.ErrorTransformer">
</bean>
<int-jms:outbound-channel-adapter id ="errorQueueAdapter"
explicit-qos-enabled="${jms.qos.enabled}"
auto-startup="${jms.connect}" channel="errors" pub-sub-domain="false"
connection-factory="connectionFactory" destination-name="${error}" />
@Transformer
public Message<String> handleError(MessagingException message) {
headers.put("stacktrace", ExceptionUtils.getStackTrace(message));
headers.put("serviceCausedTheException", EnvironmentResolver.getService());
Message<?> failedMessage = message.getFailedMessage();
Object msgPayload = failedMessage.getPayload();
String payload = "";
try {
if (msgPayload instanceof String)
payload = (String) failedMessage.getPayload();
else if (msgPayload instanceof MyObject)
payload = XMLMarshallingUtil.objectToXml((MyObject) msgPayload);
} catch (Exception e) {
payload = msgPayload.toString();
headers.put("Object Conversion Exception Occurred in Error Transformer",
e.getMessage());
}
Message<String> parsed = MessageBuilder.withPayload(payload).copyHeaders(headers).
copyHeaders(message.getFailedMessage().getHeaders()).build();
return parsed;
}
Now, as this Transformer
expects Messaging Exception Object
, hence in order to forward the message to Error Transformer
from other transformers , I need to pass the Messaging Exception Object
. Using MessageChannel.send
method, I could only pass on the message object.Please suggest
Below is my Another transformer code , from where I would like to forward the message to error queue
public Message<MyObject> handleError(MessagingException message) {
Message<MyObject> messageMyObject = null;
try {
Object obj = message.getFailedMessage().getPayload();
MyObject styleML = null;
if (obj instanceof String) {
String temp = (String) obj;
if (temp != null && temp.contains("MyObject"))
styleML = XMLMarshallingUtil.xmlToObject(temp, MyObject.class);
} else if (obj instanceof MyObject) {
styleML = (MyObject) obj;
}
String serviceName = EnvironmentResolver.getService();
Throwable t = ExceptionUtils.getRootCause(message.getCause());
if (t == null)
t = message.getCause();
String userComment = "Exception Occurred";
String sysComment = t.getMessage();
MyObject= MyObjectUtils.addMessageEventToMyObject(sysComment, userComment, styleML, serviceName, ProcessState.IN_ERROR);
messageMyObject = MessageBuilder.withPayload(styleML).copyHeaders(message.getFailedMessage().getHeaders()).build();
} catch (Exception e) {
errorsDest.send(MessageBuilder.withPayload(message).build());
}
return messageStyleML;
}
Upvotes: 0
Views: 3024
Reputation: 121337
Right. Channels have Message
contract for sending and receiving methods. However each message has payload
. And in your case handleError
accepts messages with MessagingException
payload
. In case of error-handling to the errorChannel
, when any your endpoint throws exception, it will be wrapped to the MessagingException
with failedMessage
and further to the ErrorMessage
.
So, if you want to send something directly to the channel, even if it is Exception
, you need to wrap it with Message
. And it can be a result of MessageBuilder
.
From other side Method Invocation principle of Spring Integration allows you to have any desired flexibility over method arguments. In your case the handleError
method accepts MessagingException
, and it is a default strategy to map message's payload to the method's argument.
Hope I understood you correctly...
UPDATE
Regarding the second question about how to avoid sending message to both channels.
I suggest the simplest way:
<transformer>
to the <service-activator>
. (Fom method invocation perspective they are similar.)errorsDest.send
add just return null;
. Transformer
doesn't allow to return null
. ServiceActivator
allows it by default. In this case your main flow will be stopped.Upvotes: 2