/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.camel.component.sjms; import java.io.File; import java.util.Map; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.Queue; import javax.jms.Session; import javax.jms.Topic; import org.apache.camel.RuntimeExchangeException; import org.apache.camel.component.sjms.jms.JmsBinding; import org.apache.camel.component.sjms.jms.JmsMessageHelper; import org.apache.camel.impl.DefaultMessage; import org.apache.camel.util.ExchangeHelper; import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represents a {@link org.apache.camel.Message} for working with JMS * * @version */ public class SjmsMessage extends DefaultMessage { private static final Logger LOG = LoggerFactory.getLogger(SjmsMessage.class); private Message jmsMessage; private Session jmsSession; private JmsBinding binding; public SjmsMessage(Message jmsMessage, Session jmsSession, JmsBinding binding) { setJmsMessage(jmsMessage); setJmsSession(jmsSession); setBinding(binding); } @Override public String toString() { // do not print jmsMessage as there could be sensitive details if (jmsMessage != null) { try { return "SjmsMessage[JmsMessageID: " + jmsMessage.getJMSMessageID() + "]"; } catch (Throwable e) { // ignore } } return "SjmsMessage@" + ObjectHelper.getIdentityHashCode(this); } @Override public void copyFrom(org.apache.camel.Message that) { if (that == this) { // the same instance so do not need to copy return; } // must initialize headers before we set the JmsMessage to avoid Camel // populating it before we do the copy getHeaders().clear(); boolean copyMessageId = true; if (that instanceof SjmsMessage) { SjmsMessage thatMessage = (SjmsMessage) that; this.jmsMessage = thatMessage.jmsMessage; if (this.jmsMessage != null) { // for performance lets not copy the messageID if we are a JMS message copyMessageId = false; } } if (copyMessageId) { setMessageId(that.getMessageId()); } // copy body and fault flag setBody(that.getBody()); setFault(that.isFault()); // we have already cleared the headers if (that.hasHeaders()) { getHeaders().putAll(that.getHeaders()); } getAttachments().clear(); if (that.hasAttachments()) { getAttachmentObjects().putAll(that.getAttachmentObjects()); } } public JmsBinding getBinding() { if (binding == null) { binding = ExchangeHelper.getBinding(getExchange(), JmsBinding.class); } return binding; } public void setBinding(JmsBinding binding) { this.binding = binding; } /** * Returns the underlying JMS message */ public Message getJmsMessage() { return jmsMessage; } public void setJmsMessage(Message jmsMessage) { if (jmsMessage != null) { try { setMessageId(jmsMessage.getJMSMessageID()); } catch (JMSException e) { LOG.warn("Unable to retrieve JMSMessageID from JMS Message", e); } } this.jmsMessage = jmsMessage; } /** * Returns the underlying JMS session. * <p/> * This may be <tt>null</tt>. */ public Session getJmsSession() { return jmsSession; } public void setJmsSession(Session jmsSession) { this.jmsSession = jmsSession; } @Override public void setBody(Object body) { super.setBody(body); if (body == null) { // preserver headers even if we set body to null ensureInitialHeaders(); // remove underlying jmsMessage since we mutated body to null jmsMessage = null; } } public Object getHeader(String name) { Object answer = null; // we will exclude using JMS-prefixed headers here to avoid strangeness with some JMS providers // e.g. ActiveMQ returns the String not the Destination type for "JMSReplyTo"! // only look in jms message directly if we have not populated headers if (jmsMessage != null && !hasPopulatedHeaders() && !name.startsWith("JMS")) { try { // use binding to do the lookup as it has to consider using encoded keys answer = getBinding().getObjectProperty(jmsMessage, name); } catch (JMSException e) { throw new RuntimeExchangeException("Unable to retrieve header from JMS Message: " + name, getExchange(), e); } } // only look if we have populated headers otherwise there are no headers at all // if we do lookup a header starting with JMS then force a lookup if (answer == null && (hasPopulatedHeaders() || name.startsWith("JMS"))) { answer = super.getHeader(name); } return answer; } @Override public Map<String, Object> getHeaders() { ensureInitialHeaders(); return super.getHeaders(); } @Override public Object removeHeader(String name) { ensureInitialHeaders(); return super.removeHeader(name); } @Override public void setHeaders(Map<String, Object> headers) { ensureInitialHeaders(); super.setHeaders(headers); } @Override public void setHeader(String name, Object value) { ensureInitialHeaders(); super.setHeader(name, value); } @Override public SjmsMessage newInstance() { return new SjmsMessage(null, null, binding); } /** * Returns true if a new JMS message instance should be created to send to the next component */ public boolean shouldCreateNewMessage() { return super.hasPopulatedHeaders(); } /** * Ensure that the headers have been populated from the underlying JMS message * before we start mutating the headers */ protected void ensureInitialHeaders() { if (jmsMessage != null && !hasPopulatedHeaders()) { // we have not populated headers so force this by creating // new headers and set it on super super.setHeaders(createHeaders()); } } @Override protected Object createBody() { if (jmsMessage != null) { return getBinding().extractBodyFromJms(getExchange(), jmsMessage); } return null; } @Override protected void populateInitialHeaders(Map<String, Object> map) { if (jmsMessage != null && map != null) { map.putAll(getBinding().extractHeadersFromJms(jmsMessage, getExchange())); } } @Override protected String createMessageId() { if (jmsMessage == null) { LOG.trace("No javax.jms.Message set so generating a new message id"); return super.createMessageId(); } try { String id = getDestinationAsString(jmsMessage.getJMSDestination()) + jmsMessage.getJMSMessageID(); return getSanitizedString(id); } catch (JMSException e) { throw new RuntimeExchangeException("Unable to retrieve JMSMessageID from JMS Message", getExchange(), e); } } @Override protected Boolean isTransactedRedelivered() { if (jmsMessage != null) { return JmsMessageHelper.getJMSRedelivered(jmsMessage); } else { return null; } } private String getDestinationAsString(Destination destination) throws JMSException { String result; if (destination == null) { result = "null destination!" + File.separator; } else if (destination instanceof Topic) { result = "topic" + File.separator + ((Topic) destination).getTopicName() + File.separator; } else { result = "queue" + File.separator + ((Queue) destination).getQueueName() + File.separator; } return result; } private String getSanitizedString(Object value) { return value != null ? value.toString().replaceAll("[^a-zA-Z0-9\\.\\_\\-]", "_") : ""; } }