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