001/* 002 * Copyright 2002-2017 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.core; 018 019import java.util.Map; 020 021import javax.jms.ConnectionFactory; 022import javax.jms.Destination; 023import javax.jms.JMSException; 024import javax.jms.Session; 025 026import org.springframework.beans.factory.InitializingBean; 027import org.springframework.jms.InvalidDestinationException; 028import org.springframework.jms.JmsException; 029import org.springframework.jms.support.converter.MessageConverter; 030import org.springframework.jms.support.converter.MessagingMessageConverter; 031import org.springframework.jms.support.converter.SimpleMessageConverter; 032import org.springframework.lang.Nullable; 033import org.springframework.messaging.Message; 034import org.springframework.messaging.MessagingException; 035import org.springframework.messaging.converter.MessageConversionException; 036import org.springframework.messaging.core.AbstractMessagingTemplate; 037import org.springframework.messaging.core.DestinationResolutionException; 038import org.springframework.messaging.core.MessagePostProcessor; 039import org.springframework.util.Assert; 040 041/** 042 * An implementation of {@link JmsMessageOperations}. 043 * 044 * @author Stephane Nicoll 045 * @author Juergen Hoeller 046 * @since 4.1 047 */ 048public class JmsMessagingTemplate extends AbstractMessagingTemplate<Destination> 049 implements JmsMessageOperations, InitializingBean { 050 051 @Nullable 052 private JmsTemplate jmsTemplate; 053 054 private MessageConverter jmsMessageConverter = new MessagingMessageConverter(); 055 056 private boolean converterSet; 057 058 @Nullable 059 private String defaultDestinationName; 060 061 062 /** 063 * Constructor for use with bean properties. 064 * Requires {@link #setConnectionFactory} or {@link #setJmsTemplate} to be called. 065 */ 066 public JmsMessagingTemplate() { 067 } 068 069 /** 070 * Create a {@code JmsMessagingTemplate} instance with the JMS {@link ConnectionFactory} 071 * to use, implicitly building a {@link JmsTemplate} based on it. 072 * @since 4.1.2 073 */ 074 public JmsMessagingTemplate(ConnectionFactory connectionFactory) { 075 this.jmsTemplate = new JmsTemplate(connectionFactory); 076 } 077 078 /** 079 * Create a {@code JmsMessagingTemplate} instance with the {@link JmsTemplate} to use. 080 */ 081 public JmsMessagingTemplate(JmsTemplate jmsTemplate) { 082 Assert.notNull(jmsTemplate, "JmsTemplate must not be null"); 083 this.jmsTemplate = jmsTemplate; 084 } 085 086 087 /** 088 * Set the ConnectionFactory to use for the underlying {@link JmsTemplate}. 089 * @since 4.1.2 090 */ 091 public void setConnectionFactory(ConnectionFactory connectionFactory) { 092 if (this.jmsTemplate != null) { 093 this.jmsTemplate.setConnectionFactory(connectionFactory); 094 } 095 else { 096 this.jmsTemplate = new JmsTemplate(connectionFactory); 097 } 098 } 099 100 /** 101 * Return the ConnectionFactory that the underlying {@link JmsTemplate} uses. 102 * @since 4.1.2 103 */ 104 @Nullable 105 public ConnectionFactory getConnectionFactory() { 106 return (this.jmsTemplate != null ? this.jmsTemplate.getConnectionFactory() : null); 107 } 108 109 /** 110 * Set the {@link JmsTemplate} to use. 111 */ 112 public void setJmsTemplate(@Nullable JmsTemplate jmsTemplate) { 113 this.jmsTemplate = jmsTemplate; 114 } 115 116 /** 117 * Return the configured {@link JmsTemplate}. 118 */ 119 @Nullable 120 public JmsTemplate getJmsTemplate() { 121 return this.jmsTemplate; 122 } 123 124 /** 125 * Set the {@link MessageConverter} to use to convert a {@link Message} from 126 * the messaging to and from a {@link javax.jms.Message}. By default, a 127 * {@link MessagingMessageConverter} is defined using a {@link SimpleMessageConverter} 128 * to convert the payload of the message. 129 * <p>Consider configuring a {@link MessagingMessageConverter} with a different 130 * {@link MessagingMessageConverter#setPayloadConverter(MessageConverter) payload converter} 131 * for more advanced scenarios. 132 * @see org.springframework.jms.support.converter.MessagingMessageConverter 133 */ 134 public void setJmsMessageConverter(MessageConverter jmsMessageConverter) { 135 Assert.notNull(jmsMessageConverter, "MessageConverter must not be null"); 136 this.jmsMessageConverter = jmsMessageConverter; 137 this.converterSet = true; 138 } 139 140 /** 141 * Return the {@link MessageConverter} to use to convert a {@link Message} 142 * from the messaging to and from a {@link javax.jms.Message}. 143 */ 144 public MessageConverter getJmsMessageConverter() { 145 return this.jmsMessageConverter; 146 } 147 148 /** 149 * Configure the default destination name to use in send methods that don't have 150 * a destination argument. If a default destination is not configured, send methods 151 * without a destination argument will raise an exception if invoked. 152 * @see #setDefaultDestination(Object) 153 */ 154 public void setDefaultDestinationName(@Nullable String defaultDestinationName) { 155 this.defaultDestinationName = defaultDestinationName; 156 } 157 158 /** 159 * Return the configured default destination name. 160 */ 161 @Nullable 162 public String getDefaultDestinationName() { 163 return this.defaultDestinationName; 164 } 165 166 @Override 167 public void afterPropertiesSet() { 168 Assert.notNull(this.jmsTemplate, "Property 'connectionFactory' or 'jmsTemplate' is required"); 169 if (!this.converterSet && this.jmsTemplate.getMessageConverter() != null) { 170 ((MessagingMessageConverter) this.jmsMessageConverter) 171 .setPayloadConverter(this.jmsTemplate.getMessageConverter()); 172 } 173 } 174 175 private JmsTemplate obtainJmsTemplate() { 176 Assert.state(this.jmsTemplate != null, "No JmsTemplate set"); 177 return this.jmsTemplate; 178 } 179 180 181 @Override 182 public void send(Message<?> message) { 183 Destination defaultDestination = getDefaultDestination(); 184 if (defaultDestination != null) { 185 send(defaultDestination, message); 186 } 187 else { 188 send(getRequiredDefaultDestinationName(), message); 189 } 190 } 191 192 @Override 193 public void convertAndSend(Object payload) throws MessagingException { 194 convertAndSend(payload, null); 195 } 196 197 @Override 198 public void convertAndSend(Object payload, @Nullable MessagePostProcessor postProcessor) throws MessagingException { 199 Destination defaultDestination = getDefaultDestination(); 200 if (defaultDestination != null) { 201 convertAndSend(defaultDestination, payload, postProcessor); 202 } 203 else { 204 convertAndSend(getRequiredDefaultDestinationName(), payload, postProcessor); 205 } 206 } 207 208 @Override 209 public void send(String destinationName, Message<?> message) throws MessagingException { 210 doSend(destinationName, message); 211 } 212 213 @Override 214 public void convertAndSend(String destinationName, Object payload) throws MessagingException { 215 convertAndSend(destinationName, payload, (Map<String, Object>) null); 216 } 217 218 @Override 219 public void convertAndSend(String destinationName, Object payload, @Nullable Map<String, Object> headers) 220 throws MessagingException { 221 222 convertAndSend(destinationName, payload, headers, null); 223 } 224 225 @Override 226 public void convertAndSend(String destinationName, Object payload, @Nullable MessagePostProcessor postProcessor) 227 throws MessagingException { 228 229 convertAndSend(destinationName, payload, null, postProcessor); 230 } 231 232 @Override 233 public void convertAndSend(String destinationName, Object payload, @Nullable Map<String, Object> headers, 234 @Nullable MessagePostProcessor postProcessor) throws MessagingException { 235 236 Message<?> message = doConvert(payload, headers, postProcessor); 237 send(destinationName, message); 238 } 239 240 @Override 241 @Nullable 242 public Message<?> receive() { 243 Destination defaultDestination = getDefaultDestination(); 244 if (defaultDestination != null) { 245 return receive(defaultDestination); 246 } 247 else { 248 return receive(getRequiredDefaultDestinationName()); 249 } 250 } 251 252 @Override 253 @Nullable 254 public <T> T receiveAndConvert(Class<T> targetClass) { 255 Destination defaultDestination = getDefaultDestination(); 256 if (defaultDestination != null) { 257 return receiveAndConvert(defaultDestination, targetClass); 258 } 259 else { 260 return receiveAndConvert(getRequiredDefaultDestinationName(), targetClass); 261 } 262 } 263 264 @Override 265 @Nullable 266 public Message<?> receive(String destinationName) throws MessagingException { 267 return doReceive(destinationName); 268 } 269 270 @Override 271 @Nullable 272 public <T> T receiveAndConvert(String destinationName, Class<T> targetClass) throws MessagingException { 273 Message<?> message = doReceive(destinationName); 274 if (message != null) { 275 return doConvert(message, targetClass); 276 } 277 else { 278 return null; 279 } 280 } 281 282 @Override 283 @Nullable 284 public Message<?> sendAndReceive(Message<?> requestMessage) { 285 Destination defaultDestination = getDefaultDestination(); 286 if (defaultDestination != null) { 287 return sendAndReceive(defaultDestination, requestMessage); 288 } 289 else { 290 return sendAndReceive(getRequiredDefaultDestinationName(), requestMessage); 291 } 292 } 293 294 @Override 295 @Nullable 296 public Message<?> sendAndReceive(String destinationName, Message<?> requestMessage) throws MessagingException { 297 return doSendAndReceive(destinationName, requestMessage); 298 } 299 300 @Override 301 @Nullable 302 public <T> T convertSendAndReceive(String destinationName, Object request, Class<T> targetClass) 303 throws MessagingException { 304 305 return convertSendAndReceive(destinationName, request, null, targetClass); 306 } 307 308 @Override 309 @Nullable 310 public <T> T convertSendAndReceive(Object request, Class<T> targetClass) { 311 return convertSendAndReceive(request, targetClass, null); 312 } 313 314 @Override 315 @Nullable 316 public <T> T convertSendAndReceive(String destinationName, Object request, 317 @Nullable Map<String, Object> headers, Class<T> targetClass) throws MessagingException { 318 319 return convertSendAndReceive(destinationName, request, headers, targetClass, null); 320 } 321 322 @Override 323 @Nullable 324 public <T> T convertSendAndReceive(Object request, Class<T> targetClass, @Nullable MessagePostProcessor postProcessor) { 325 Destination defaultDestination = getDefaultDestination(); 326 if (defaultDestination != null) { 327 return convertSendAndReceive(defaultDestination, request, targetClass, postProcessor); 328 } 329 else { 330 return convertSendAndReceive(getRequiredDefaultDestinationName(), request, targetClass, postProcessor); 331 } 332 } 333 334 @Override 335 @Nullable 336 public <T> T convertSendAndReceive(String destinationName, Object request, Class<T> targetClass, 337 @Nullable MessagePostProcessor requestPostProcessor) throws MessagingException { 338 339 return convertSendAndReceive(destinationName, request, null, targetClass, requestPostProcessor); 340 } 341 342 @SuppressWarnings("unchecked") 343 @Override 344 @Nullable 345 public <T> T convertSendAndReceive(String destinationName, Object request, @Nullable Map<String, Object> headers, 346 Class<T> targetClass, @Nullable MessagePostProcessor postProcessor) { 347 348 Message<?> requestMessage = doConvert(request, headers, postProcessor); 349 Message<?> replyMessage = sendAndReceive(destinationName, requestMessage); 350 return (replyMessage != null ? (T) getMessageConverter().fromMessage(replyMessage, targetClass) : null); 351 } 352 353 @Override 354 protected void doSend(Destination destination, Message<?> message) { 355 try { 356 obtainJmsTemplate().send(destination, createMessageCreator(message)); 357 } 358 catch (JmsException ex) { 359 throw convertJmsException(ex); 360 } 361 } 362 363 protected void doSend(String destinationName, Message<?> message) { 364 try { 365 obtainJmsTemplate().send(destinationName, createMessageCreator(message)); 366 } 367 catch (JmsException ex) { 368 throw convertJmsException(ex); 369 } 370 } 371 372 @Override 373 @Nullable 374 protected Message<?> doReceive(Destination destination) { 375 try { 376 javax.jms.Message jmsMessage = obtainJmsTemplate().receive(destination); 377 return convertJmsMessage(jmsMessage); 378 } 379 catch (JmsException ex) { 380 throw convertJmsException(ex); 381 } 382 } 383 384 @Nullable 385 protected Message<?> doReceive(String destinationName) { 386 try { 387 javax.jms.Message jmsMessage = obtainJmsTemplate().receive(destinationName); 388 return convertJmsMessage(jmsMessage); 389 } 390 catch (JmsException ex) { 391 throw convertJmsException(ex); 392 } 393 } 394 395 @Override 396 @Nullable 397 protected Message<?> doSendAndReceive(Destination destination, Message<?> requestMessage) { 398 try { 399 javax.jms.Message jmsMessage = obtainJmsTemplate().sendAndReceive( 400 destination, createMessageCreator(requestMessage)); 401 return convertJmsMessage(jmsMessage); 402 } 403 catch (JmsException ex) { 404 throw convertJmsException(ex); 405 } 406 } 407 408 @Nullable 409 protected Message<?> doSendAndReceive(String destinationName, Message<?> requestMessage) { 410 try { 411 javax.jms.Message jmsMessage = obtainJmsTemplate().sendAndReceive( 412 destinationName, createMessageCreator(requestMessage)); 413 return convertJmsMessage(jmsMessage); 414 } 415 catch (JmsException ex) { 416 throw convertJmsException(ex); 417 } 418 } 419 420 private MessagingMessageCreator createMessageCreator(Message<?> message) { 421 return new MessagingMessageCreator(message, getJmsMessageConverter()); 422 } 423 424 protected String getRequiredDefaultDestinationName() { 425 String name = getDefaultDestinationName(); 426 if (name == null) { 427 throw new IllegalStateException("No 'defaultDestination' or 'defaultDestinationName' specified. " + 428 "Check configuration of JmsMessagingTemplate."); 429 } 430 return name; 431 } 432 433 @Nullable 434 protected Message<?> convertJmsMessage(@Nullable javax.jms.Message message) { 435 if (message == null) { 436 return null; 437 } 438 try { 439 return (Message<?>) getJmsMessageConverter().fromMessage(message); 440 } 441 catch (Exception ex) { 442 throw new MessageConversionException("Could not convert '" + message + "'", ex); 443 } 444 } 445 446 protected MessagingException convertJmsException(JmsException ex) { 447 if (ex instanceof org.springframework.jms.support.destination.DestinationResolutionException || 448 ex instanceof InvalidDestinationException) { 449 return new DestinationResolutionException(ex.getMessage(), ex); 450 } 451 if (ex instanceof org.springframework.jms.support.converter.MessageConversionException) { 452 return new MessageConversionException(ex.getMessage(), ex); 453 } 454 // Fallback 455 return new MessagingException(ex.getMessage(), ex); 456 } 457 458 459 private static class MessagingMessageCreator implements MessageCreator { 460 461 private final Message<?> message; 462 463 private final MessageConverter messageConverter; 464 465 public MessagingMessageCreator(Message<?> message, MessageConverter messageConverter) { 466 this.message = message; 467 this.messageConverter = messageConverter; 468 } 469 470 @Override 471 public javax.jms.Message createMessage(Session session) throws JMSException { 472 try { 473 return this.messageConverter.toMessage(this.message, session); 474 } 475 catch (Exception ex) { 476 throw new MessageConversionException("Could not convert '" + this.message + "'", ex); 477 } 478 } 479 } 480 481}