001/* 002 * Copyright 2002-2015 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.listener.adapter; 018 019import javax.jms.Destination; 020import javax.jms.JMSException; 021import javax.jms.Session; 022 023import org.springframework.jms.support.destination.DestinationResolver; 024import org.springframework.util.Assert; 025 026/** 027 * Return type of any JMS listener method used to indicate the actual response 028 * destination alongside the response itself. Typically used when said destination 029 * needs to be computed at runtime. 030 * 031 * <p>The example below sends a response with the content of the {@code result} 032 * argument to the {@code queueOut Queue}: 033 * 034 * <pre class="code"> 035 * package com.acme.foo; 036 * 037 * public class MyService { 038 * @JmsListener 039 * public JmsResponse process(String msg) { 040 * // process incoming message 041 * return JmsResponse.forQueue(result, "queueOut"); 042 * } 043 * }</pre> 044 * 045 * If the destination does not need to be computed at runtime, 046 * {@link org.springframework.messaging.handler.annotation.SendTo @SendTo} 047 * is the recommended declarative approach. 048 * 049 * @author Stephane Nicoll 050 * @since 4.2 051 * @see org.springframework.jms.annotation.JmsListener 052 * @see org.springframework.messaging.handler.annotation.SendTo 053 * @param <T> the type of the response 054 */ 055public class JmsResponse<T> { 056 057 private final T response; 058 059 private final Object destination; 060 061 062 /** 063 * Create a new instance 064 * @param response the content of the result 065 * @param destination the destination 066 */ 067 protected JmsResponse(T response, Object destination) { 068 Assert.notNull(response, "Result must not be null"); 069 this.response = response; 070 this.destination = destination; 071 } 072 073 074 /** 075 * Return the content of the response. 076 */ 077 public T getResponse() { 078 return this.response; 079 } 080 081 /** 082 * Resolve the {@link Destination} to use for this instance. The {@link DestinationResolver} 083 * and {@link Session} can be used to resolve a destination at runtime. 084 * @param destinationResolver the destination resolver to use if necessary 085 * @param session the session to use, if necessary 086 * @return the {@link Destination} to use 087 * @throws JMSException if the DestinationResolver failed to resolve the destination 088 */ 089 public Destination resolveDestination(DestinationResolver destinationResolver, Session session) 090 throws JMSException { 091 092 if (this.destination instanceof Destination) { 093 return (Destination) this.destination; 094 } 095 if (this.destination instanceof DestinationNameHolder) { 096 DestinationNameHolder nameHolder = (DestinationNameHolder) this.destination; 097 return destinationResolver.resolveDestinationName(session, 098 nameHolder.destinationName, nameHolder.pubSubDomain); 099 } 100 return null; 101 } 102 103 @Override 104 public String toString() { 105 return "JmsResponse [" + "response=" + this.response + ", destination=" + this.destination + ']'; 106 } 107 108 109 /** 110 * Create a {@link JmsResponse} targeting the queue with the specified name. 111 */ 112 public static <T> JmsResponse<T> forQueue(T result, String queueName) { 113 Assert.notNull(queueName, "Queue name must not be null"); 114 return new JmsResponse<T>(result, new DestinationNameHolder(queueName, false)); 115 } 116 117 /** 118 * Create a {@link JmsResponse} targeting the topic with the specified name. 119 */ 120 public static <T> JmsResponse<T> forTopic(T result, String topicName) { 121 Assert.notNull(topicName, "Topic name must not be null"); 122 return new JmsResponse<T>(result, new DestinationNameHolder(topicName, true)); 123 } 124 125 /** 126 * Create a {@link JmsResponse} targeting the specified {@link Destination}. 127 */ 128 public static <T> JmsResponse<T> forDestination(T result, Destination destination) { 129 Assert.notNull(destination, "Destination must not be null"); 130 return new JmsResponse<T>(result, destination); 131 } 132 133 134 /** 135 * Internal class combining a destination name 136 * and its target destination type (queue or topic). 137 */ 138 private static class DestinationNameHolder { 139 140 private final String destinationName; 141 142 private final boolean pubSubDomain; 143 144 public DestinationNameHolder(String destinationName, boolean pubSubDomain) { 145 this.destinationName = destinationName; 146 this.pubSubDomain = pubSubDomain; 147 } 148 149 @Override 150 public String toString() { 151 return this.destinationName + "{" + "pubSubDomain=" + this.pubSubDomain + '}'; 152 } 153 } 154 155}