/* * Copyright 2010, 2013, 2014 Chris Pheby * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jadira.jms.mdp; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import javax.jms.BytesMessage; import javax.jms.JMSException; import javax.jms.MapMessage; import javax.jms.Message; import javax.jms.MessageFormatException; import javax.jms.ObjectMessage; import javax.jms.Session; import javax.jms.StreamMessage; import javax.jms.TextMessage; import org.springframework.jms.core.MessageCreator; /** * A MessageCreator that takes a given Message and related Exeption. This class copies the source message and enriches the copy with information about the original headers and properties as well as * the causing exception Priority and CorrelationID are preserved on the error message. */ public class FatalJmsExceptionMessageCreator implements MessageCreator { private static final String EXCEPTION_MESSAGE_PROPERTY = "cause_exceptionMessage"; private static final String EXCEPTION_STACKTRACE_PROPERTY = "cause_exceptionStackTrace"; private static final String ORIGINAL_DELIVERY_MODE = "original_JMSDeliveryMode"; private static final String ORIGINAL_EXPIRATION = "original_JMSExpiration"; private static final String ORIGINAL_MESSAGE_ID = "original_JMSMessageID"; private static final String ORIGINAL_REPLY_TO = "original_JMSReplyTo"; private static final String ORIGINAL_REDELIVERED = "original_JMSRedelivered"; private static final String ORIGINAL_CORRELATIONID = "original_JMSCorrelationID"; private static final String ORIGINAL_PRIORITY = "original_JMSPriority"; private static final int BUFFER_CAPACITY_BYTES = 4096; private final Message message; private final Exception e; public FatalJmsExceptionMessageCreator(Message message, Exception e) { this.message = message; this.e = e; } @Override public Message createMessage(Session session) throws JMSException { final Message copyMessage = copyMessage(session, message); enrichMessage(copyMessage, message); return copyMessage; } protected void enrichMessage(Message copyMessage, Message originalMessage) throws JMSException { Map<String, Object> messageProps = buildErrorMessageProperties(originalMessage); applyMessageProperties(copyMessage, messageProps); applyMessageHeaders(copyMessage, originalMessage); applyErrorDetails(copyMessage, e); } protected Map<String, Object> buildErrorMessageProperties(Message msg) throws JMSException { Map<String, Object> properties = new HashMap<String, Object>(); @SuppressWarnings("unchecked") Enumeration<String> srcProperties = msg.getPropertyNames(); while (srcProperties.hasMoreElements()) { String propertyName = srcProperties.nextElement(); properties.put("original_" + propertyName, msg.getObjectProperty(propertyName)); } properties.put(ORIGINAL_DELIVERY_MODE, msg.getJMSDeliveryMode()); properties.put(ORIGINAL_EXPIRATION, msg.getJMSExpiration()); properties.put(ORIGINAL_MESSAGE_ID, msg.getJMSMessageID()); properties.put(ORIGINAL_REPLY_TO, msg.getJMSReplyTo()); properties.put(ORIGINAL_REDELIVERED, msg.getJMSRedelivered()); properties.put(ORIGINAL_CORRELATIONID, msg.getJMSCorrelationID()); properties.put(ORIGINAL_PRIORITY, msg.getJMSPriority()); return properties; } private void applyMessageProperties(Message destinationMessage, Map<String, Object> properties) throws JMSException { if (properties == null) { return; } for (Map.Entry<String, Object> entry : properties.entrySet()) { destinationMessage.setObjectProperty(entry.getKey(), entry.getValue()); } } protected void applyMessageHeaders(Message destinationMessage, Message sourceMessage) { try { destinationMessage.setJMSCorrelationIDAsBytes(sourceMessage.getJMSCorrelationIDAsBytes()); } catch (JMSException e) { } try { destinationMessage.setJMSPriority(sourceMessage.getJMSPriority()); } catch (JMSException e) { } } protected void applyErrorDetails(final Message destinationMessage, final Exception exception) throws JMSException { destinationMessage.setStringProperty(EXCEPTION_MESSAGE_PROPERTY, exception.getMessage()); StringWriter stackTraceWriter = new StringWriter(); exception.printStackTrace(new PrintWriter(stackTraceWriter)); destinationMessage.setStringProperty(EXCEPTION_STACKTRACE_PROPERTY, stackTraceWriter.toString()); } private static Message copyMessage(Session session, Message originalMessage) throws JMSException { Message copyMessage; if (originalMessage instanceof BytesMessage) { final BytesMessage theMessage = session.createBytesMessage(); final byte[] bytes = extractByteArrayFromMessage((BytesMessage) originalMessage); theMessage.writeBytes(bytes); copyMessage = theMessage; } else if (originalMessage instanceof StreamMessage) { final StreamMessage theMessage = session.createStreamMessage(); final byte[] bytes = extractByteArrayFromMessage((StreamMessage) originalMessage); theMessage.writeBytes(bytes); copyMessage = theMessage; } else if (originalMessage instanceof ObjectMessage) { copyMessage = session.createObjectMessage(((ObjectMessage) originalMessage).getObject()); } else if (originalMessage instanceof TextMessage) { copyMessage = session.createTextMessage(((TextMessage) originalMessage).getText()); } else if (originalMessage instanceof MapMessage) { MapMessage theMessage = session.createMapMessage(); @SuppressWarnings("unchecked") Enumeration<String> keys = ((MapMessage) originalMessage).getMapNames(); while (keys.hasMoreElements()) { String next = keys.nextElement(); theMessage.setObject(next, ((MapMessage) originalMessage).getObject(next)); } copyMessage = theMessage; } else { throw new MessageFormatException("Unexpected Message Type received, was: " + originalMessage.getClass()); } return copyMessage; } private static byte[] extractByteArrayFromMessage(BytesMessage message) throws JMSException { ByteArrayOutputStream oStream = new ByteArrayOutputStream(BUFFER_CAPACITY_BYTES); byte[] buffer = new byte[BUFFER_CAPACITY_BYTES]; int bufferCount = -1; while ((bufferCount = message.readBytes(buffer)) >= 0) { oStream.write(buffer, 0, bufferCount); if (bufferCount < BUFFER_CAPACITY_BYTES) { break; } } return oStream.toByteArray(); } private static byte[] extractByteArrayFromMessage(StreamMessage message) throws JMSException { ByteArrayOutputStream oStream = new ByteArrayOutputStream(BUFFER_CAPACITY_BYTES); byte[] buffer = new byte[BUFFER_CAPACITY_BYTES]; int bufferCount = -1; while ((bufferCount = message.readBytes(buffer)) >= 0) { oStream.write(buffer, 0, bufferCount); if (bufferCount < BUFFER_CAPACITY_BYTES) { break; } } return oStream.toByteArray(); } }