001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.component.jms.requestor;
018
019 import java.math.BigInteger;
020 import java.util.Random;
021 import java.util.concurrent.ScheduledExecutorService;
022
023 import javax.jms.Destination;
024 import javax.jms.ExceptionListener;
025 import javax.jms.JMSException;
026 import javax.jms.Message;
027 import javax.jms.Session;
028
029 import org.apache.camel.component.jms.JmsConfiguration;
030 import org.apache.camel.component.jms.requestor.DeferredRequestReplyMap.DeferredMessageSentCallback;
031 import org.springframework.core.task.TaskExecutor;
032 import org.springframework.jms.listener.AbstractMessageListenerContainer;
033 import org.springframework.jms.listener.DefaultMessageListenerContainer;
034 import org.springframework.jms.listener.DefaultMessageListenerContainer102;
035 import org.springframework.jms.support.destination.DestinationResolver;
036 import org.springframework.transaction.PlatformTransactionManager;
037
038 public class PersistentReplyToRequestor extends Requestor {
039 private String replyToSelectorValue;
040
041 public class DestinationResolverDelegate implements DestinationResolver {
042 private DestinationResolver delegate;
043 private Destination destination;
044
045 public DestinationResolverDelegate(DestinationResolver delegate) {
046 this.delegate = delegate;
047 }
048
049 public Destination resolveDestinationName(Session session, String destinationName,
050 boolean pubSubDomain) throws JMSException {
051 synchronized (getOutterInstance()) {
052 try {
053 if (destination == null) {
054 destination = delegate.resolveDestinationName(session, destinationName, pubSubDomain);
055 setReplyTo(destination);
056 }
057 } finally {
058 getOutterInstance().notifyAll();
059 }
060 }
061 return destination;
062 }
063 };
064
065 public static interface MessageSelectorComposer {
066 void addCorrelationID(String id);
067 void removeCorrelationID(String id);
068 }
069
070 public static class CamelDefaultMessageListenerContainer102 extends DefaultMessageListenerContainer102
071 implements MessageSelectorComposer {
072 MessageSelectorProvider provider = new MessageSelectorProvider();
073
074 public void addCorrelationID(String id) {
075 provider.addCorrelationID(id);
076 }
077
078 public void removeCorrelationID(String id) {
079 provider.removeCorrelationID(id);
080 }
081
082 @Override
083 public void setMessageSelector(String messageSelector) {
084 throw new UnsupportedOperationException();
085 }
086
087 @Override
088 public String getMessageSelector() {
089 return provider.get();
090 }
091 }
092
093 public static class CamelDefaultMessageListenerContainer extends DefaultMessageListenerContainer
094 implements MessageSelectorComposer {
095
096 MessageSelectorProvider provider = new MessageSelectorProvider();
097
098 public void addCorrelationID(String id) {
099 provider.addCorrelationID(id);
100 }
101
102 public void removeCorrelationID(String id) {
103 provider.removeCorrelationID(id);
104 }
105
106 @Override
107 public void setMessageSelector(String messageSelector) {
108 throw new UnsupportedOperationException();
109 }
110
111 @Override
112 public String getMessageSelector() {
113 return provider.get();
114 }
115 }
116
117 public PersistentReplyToRequestor(JmsConfiguration configuration,
118 ScheduledExecutorService executorService) {
119 super(configuration, executorService);
120 }
121
122
123 @Override
124 protected FutureHandler createFutureHandler(String correlationID) {
125 boolean dynamicSelector = getConfiguration().getReplyToDestinationSelectorName() == null;
126 if (dynamicSelector) {
127 return new PersistentReplyToFutureHandler(this, correlationID);
128 }
129 return new FutureHandler();
130 }
131
132 @Override
133 protected FutureHandler createFutureHandler(DeferredMessageSentCallback callback) {
134 boolean dynamicSelector = getConfiguration().getReplyToDestinationSelectorName() == null;
135 if (dynamicSelector) {
136 return new PersistentReplyToFutureHandler(this, callback);
137 }
138 return new FutureHandler();
139 }
140
141 @Override
142 public AbstractMessageListenerContainer createListenerContainer() {
143 JmsConfiguration config = getConfiguration();
144 String replyToSelectorName = getConfiguration().getReplyToDestinationSelectorName();
145
146 DefaultMessageListenerContainer container =
147 config.isUseVersion102()
148 ? (replyToSelectorName != null) ? new DefaultMessageListenerContainer102()
149 : new CamelDefaultMessageListenerContainer102()
150 : (replyToSelectorName != null) ? new DefaultMessageListenerContainer()
151 : new CamelDefaultMessageListenerContainer();
152
153 container.setConnectionFactory(config.getListenerConnectionFactory());
154
155 DestinationResolver resolver = config.getDestinationResolver();
156 if (resolver == null) {
157 resolver = container.getDestinationResolver();
158 }
159
160 container.setDestinationResolver(new DestinationResolverDelegate(resolver));
161 container.setDestinationName(getConfiguration().getReplyTo());
162
163 if (replyToSelectorName != null) {
164 replyToSelectorValue = "ID:" + new BigInteger(24 * 8, new Random()).toString(16);
165 container.setMessageSelector(replyToSelectorName + "='" + replyToSelectorValue + "'");
166 } else {
167 ((MessageSelectorComposer)container).addCorrelationID("ID:" + new BigInteger(24 * 8, new Random()).toString(16));
168 }
169
170 container.setAutoStartup(true);
171 container.setMessageListener(this);
172 container.setPubSubDomain(false);
173 container.setSubscriptionDurable(false);
174
175 ExceptionListener exceptionListener = config.getExceptionListener();
176 if (exceptionListener != null) {
177 container.setExceptionListener(exceptionListener);
178 }
179
180 container.setSessionTransacted(config.isTransacted());
181 if (config.isTransacted()) {
182 container.setSessionAcknowledgeMode(Session.SESSION_TRANSACTED);
183 } else {
184 if (config.getAcknowledgementMode() >= 0) {
185 container.setSessionAcknowledgeMode(config.getAcknowledgementMode());
186 } else if (config.getAcknowledgementModeName() != null) {
187 container.setSessionAcknowledgeModeName(config.getAcknowledgementModeName());
188 }
189 }
190
191 container.setConcurrentConsumers(1);
192 container.setCacheLevel(DefaultMessageListenerContainer.CACHE_SESSION);
193
194 if (config.getReceiveTimeout() >= 0) {
195 container.setReceiveTimeout(config.getReceiveTimeout());
196 }
197 if (config.getRecoveryInterval() >= 0) {
198 container.setRecoveryInterval(config.getRecoveryInterval());
199 }
200 TaskExecutor taskExecutor = config.getTaskExecutor();
201 if (taskExecutor != null) {
202 container.setTaskExecutor(taskExecutor);
203 }
204 PlatformTransactionManager tm = config.getTransactionManager();
205 if (tm != null) {
206 container.setTransactionManager(tm);
207 } else if (config.isTransacted()) {
208 throw new IllegalArgumentException("Property transacted is enabled but a transactionManager was not injected!");
209 }
210 if (config.getTransactionName() != null) {
211 container.setTransactionName(config.getTransactionName());
212 }
213 if (config.getTransactionTimeout() >= 0) {
214 container.setTransactionTimeout(config.getTransactionTimeout());
215 }
216
217 return container;
218 }
219
220 @Override
221 public void setReplyToSelectorHeader(org.apache.camel.Message in, Message jmsIn) throws JMSException {
222 String replyToSelectorName = getConfiguration().getReplyToDestinationSelectorName();
223 if (replyToSelectorValue != null) {
224 in.setHeader(replyToSelectorName, replyToSelectorValue);
225 jmsIn.setStringProperty(replyToSelectorName, replyToSelectorValue);
226 }
227 }
228 }