001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jms.support.converter;
018
019import java.io.Serializable;
020import java.util.Enumeration;
021import java.util.HashMap;
022import java.util.Map;
023
024import javax.jms.BytesMessage;
025import javax.jms.JMSException;
026import javax.jms.MapMessage;
027import javax.jms.Message;
028import javax.jms.ObjectMessage;
029import javax.jms.Session;
030import javax.jms.TextMessage;
031
032import org.springframework.util.ObjectUtils;
033
034/**
035 * A simple message converter which is able to handle TextMessages, BytesMessages,
036 * MapMessages, and ObjectMessages. Used as default conversion strategy
037 * by {@link org.springframework.jms.core.JmsTemplate}, for
038 * {@code convertAndSend} and {@code receiveAndConvert} operations.
039 *
040 * <p>Converts a String to a {@link javax.jms.TextMessage}, a byte array to a
041 * {@link javax.jms.BytesMessage}, a Map to a {@link javax.jms.MapMessage}, and
042 * a Serializable object to a {@link javax.jms.ObjectMessage} (or vice versa).
043 *
044 * @author Juergen Hoeller
045 * @since 1.1
046 * @see org.springframework.jms.core.JmsTemplate#convertAndSend
047 * @see org.springframework.jms.core.JmsTemplate#receiveAndConvert
048 */
049public class SimpleMessageConverter implements MessageConverter {
050
051        /**
052         * This implementation creates a TextMessage for a String, a
053         * BytesMessage for a byte array, a MapMessage for a Map,
054         * and an ObjectMessage for a Serializable object.
055         * @see #createMessageForString
056         * @see #createMessageForByteArray
057         * @see #createMessageForMap
058         * @see #createMessageForSerializable
059         */
060        @Override
061        public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
062                if (object instanceof Message) {
063                        return (Message) object;
064                }
065                else if (object instanceof String) {
066                        return createMessageForString((String) object, session);
067                }
068                else if (object instanceof byte[]) {
069                        return createMessageForByteArray((byte[]) object, session);
070                }
071                else if (object instanceof Map) {
072                        return createMessageForMap((Map<? ,?>) object, session);
073                }
074                else if (object instanceof Serializable) {
075                        return createMessageForSerializable(((Serializable) object), session);
076                }
077                else {
078                        throw new MessageConversionException("Cannot convert object of type [" +
079                                        ObjectUtils.nullSafeClassName(object) + "] to JMS message. Supported message " +
080                                        "payloads are: String, byte array, Map<String,?>, Serializable object.");
081                }
082        }
083
084        /**
085         * This implementation converts a TextMessage back to a String, a
086         * ByteMessage back to a byte array, a MapMessage back to a Map,
087         * and an ObjectMessage back to a Serializable object. Returns
088         * the plain Message object in case of an unknown message type.
089         * @see #extractStringFromMessage
090         * @see #extractByteArrayFromMessage
091         * @see #extractMapFromMessage
092         * @see #extractSerializableFromMessage
093         */
094        @Override
095        public Object fromMessage(Message message) throws JMSException, MessageConversionException {
096                if (message instanceof TextMessage) {
097                        return extractStringFromMessage((TextMessage) message);
098                }
099                else if (message instanceof BytesMessage) {
100                        return extractByteArrayFromMessage((BytesMessage) message);
101                }
102                else if (message instanceof MapMessage) {
103                        return extractMapFromMessage((MapMessage) message);
104                }
105                else if (message instanceof ObjectMessage) {
106                        return extractSerializableFromMessage((ObjectMessage) message);
107                }
108                else {
109                        return message;
110                }
111        }
112
113
114        /**
115         * Create a JMS TextMessage for the given String.
116         * @param text the String to convert
117         * @param session current JMS session
118         * @return the resulting message
119         * @throws JMSException if thrown by JMS methods
120         * @see javax.jms.Session#createTextMessage
121         */
122        protected TextMessage createMessageForString(String text, Session session) throws JMSException {
123                return session.createTextMessage(text);
124        }
125
126        /**
127         * Create a JMS BytesMessage for the given byte array.
128         * @param bytes the byte array to convert
129         * @param session current JMS session
130         * @return the resulting message
131         * @throws JMSException if thrown by JMS methods
132         * @see javax.jms.Session#createBytesMessage
133         */
134        protected BytesMessage createMessageForByteArray(byte[] bytes, Session session) throws JMSException {
135                BytesMessage message = session.createBytesMessage();
136                message.writeBytes(bytes);
137                return message;
138        }
139
140        /**
141         * Create a JMS MapMessage for the given Map.
142         * @param map the Map to convert
143         * @param session current JMS session
144         * @return the resulting message
145         * @throws JMSException if thrown by JMS methods
146         * @see javax.jms.Session#createMapMessage
147         */
148        protected MapMessage createMessageForMap(Map<?, ?> map, Session session) throws JMSException {
149                MapMessage message = session.createMapMessage();
150                for (Map.Entry<?, ?> entry : map.entrySet()) {
151                        Object key = entry.getKey();
152                        if (!(key instanceof String)) {
153                                throw new MessageConversionException("Cannot convert non-String key of type [" +
154                                                ObjectUtils.nullSafeClassName(key) + "] to JMS MapMessage entry");
155                        }
156                        message.setObject((String) key, entry.getValue());
157                }
158                return message;
159        }
160
161        /**
162         * Create a JMS ObjectMessage for the given Serializable object.
163         * @param object the Serializable object to convert
164         * @param session current JMS session
165         * @return the resulting message
166         * @throws JMSException if thrown by JMS methods
167         * @see javax.jms.Session#createObjectMessage
168         */
169        protected ObjectMessage createMessageForSerializable(Serializable object, Session session) throws JMSException {
170                return session.createObjectMessage(object);
171        }
172
173
174        /**
175         * Extract a String from the given TextMessage.
176         * @param message the message to convert
177         * @return the resulting String
178         * @throws JMSException if thrown by JMS methods
179         */
180        protected String extractStringFromMessage(TextMessage message) throws JMSException {
181                return message.getText();
182        }
183
184        /**
185         * Extract a byte array from the given {@link BytesMessage}.
186         * @param message the message to convert
187         * @return the resulting byte array
188         * @throws JMSException if thrown by JMS methods
189         */
190        protected byte[] extractByteArrayFromMessage(BytesMessage message) throws JMSException {
191                byte[] bytes = new byte[(int) message.getBodyLength()];
192                message.readBytes(bytes);
193                return bytes;
194        }
195
196        /**
197         * Extract a Map from the given {@link MapMessage}.
198         * @param message the message to convert
199         * @return the resulting Map
200         * @throws JMSException if thrown by JMS methods
201         */
202        @SuppressWarnings("unchecked")
203        protected Map<String, Object> extractMapFromMessage(MapMessage message) throws JMSException {
204                Map<String, Object> map = new HashMap<>();
205                Enumeration<String> en = message.getMapNames();
206                while (en.hasMoreElements()) {
207                        String key = en.nextElement();
208                        map.put(key, message.getObject(key));
209                }
210                return map;
211        }
212
213        /**
214         * Extract a Serializable object from the given {@link ObjectMessage}.
215         * @param message the message to convert
216         * @return the resulting Serializable object
217         * @throws JMSException if thrown by JMS methods
218         */
219        protected Serializable extractSerializableFromMessage(ObjectMessage message) throws JMSException {
220                return message.getObject();
221        }
222
223}