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;
018
019 import java.util.Map;
020 import java.util.concurrent.ScheduledExecutorService;
021 import javax.jms.ConnectionFactory;
022 import javax.jms.ExceptionListener;
023 import javax.jms.Session;
024
025 import org.apache.camel.CamelContext;
026 import org.apache.camel.Endpoint;
027 import org.apache.camel.component.jms.requestor.Requestor;
028 import org.apache.camel.impl.DefaultComponent;
029 import org.apache.camel.spi.HeaderFilterStrategy;
030 import org.apache.camel.spi.HeaderFilterStrategyAware;
031 import org.apache.camel.util.CastUtils;
032 import org.apache.camel.util.EndpointHelper;
033 import org.apache.camel.util.ObjectHelper;
034 import org.apache.commons.logging.Log;
035 import org.apache.commons.logging.LogFactory;
036 import org.springframework.beans.BeansException;
037 import org.springframework.context.ApplicationContext;
038 import org.springframework.context.ApplicationContextAware;
039 import org.springframework.core.task.TaskExecutor;
040 import org.springframework.jms.connection.JmsTransactionManager;
041 import org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter;
042 import org.springframework.jms.core.JmsOperations;
043 import org.springframework.jms.support.converter.MessageConverter;
044 import org.springframework.jms.support.destination.DestinationResolver;
045 import org.springframework.transaction.PlatformTransactionManager;
046
047 import static org.apache.camel.util.ObjectHelper.removeStartingCharacters;
048
049 /**
050 * A <a href="http://activemq.apache.org/jms.html">JMS Component</a>
051 *
052 * @version $Revision:520964 $
053 */
054 public class JmsComponent extends DefaultComponent implements ApplicationContextAware, HeaderFilterStrategyAware {
055
056 private static final transient Log LOG = LogFactory.getLog(JmsComponent.class);
057 private static final int DEFAULT_THREADPOOL_SIZE = 100;
058 private static final String DEFAULT_QUEUE_BROWSE_STRATEGY = "org.apache.camel.component.jms.DefaultQueueBrowseStrategy";
059 private static final String KEY_FORMAT_STRATEGY_PARAM = "jmsKeyFormatStrategy";
060 private ScheduledExecutorService scheduledExecutorService;
061 private JmsConfiguration configuration;
062 private ApplicationContext applicationContext;
063 private Requestor requestor;
064 private QueueBrowseStrategy queueBrowseStrategy;
065 private boolean attemptedToCreateQueueBrowserStrategy;
066 private HeaderFilterStrategy headerFilterStrategy = new JmsHeaderFilterStrategy();
067
068 public JmsComponent() {
069 }
070
071 public JmsComponent(CamelContext context) {
072 super(context);
073 }
074
075 public JmsComponent(JmsConfiguration configuration) {
076 this.configuration = configuration;
077 }
078
079 /**
080 * Static builder method
081 */
082 public static JmsComponent jmsComponent() {
083 return new JmsComponent();
084 }
085
086 /**
087 * Static builder method
088 */
089 public static JmsComponent jmsComponent(JmsConfiguration configuration) {
090 return new JmsComponent(configuration);
091 }
092
093 /**
094 * Static builder method
095 */
096 public static JmsComponent jmsComponent(ConnectionFactory connectionFactory) {
097 return jmsComponent(new JmsConfiguration(connectionFactory));
098 }
099
100 /**
101 * Static builder method
102 */
103 public static JmsComponent jmsComponentClientAcknowledge(ConnectionFactory connectionFactory) {
104 JmsConfiguration template = new JmsConfiguration(connectionFactory);
105 template.setAcknowledgementMode(Session.CLIENT_ACKNOWLEDGE);
106 return jmsComponent(template);
107 }
108
109 /**
110 * Static builder method
111 */
112 public static JmsComponent jmsComponentAutoAcknowledge(ConnectionFactory connectionFactory) {
113 JmsConfiguration template = new JmsConfiguration(connectionFactory);
114 template.setAcknowledgementMode(Session.AUTO_ACKNOWLEDGE);
115 return jmsComponent(template);
116 }
117
118 public static JmsComponent jmsComponentTransacted(ConnectionFactory connectionFactory) {
119 JmsTransactionManager transactionManager = new JmsTransactionManager();
120 transactionManager.setConnectionFactory(connectionFactory);
121 return jmsComponentTransacted(connectionFactory, transactionManager);
122 }
123
124 public static JmsComponent jmsComponentTransacted(ConnectionFactory connectionFactory,
125 PlatformTransactionManager transactionManager) {
126 JmsConfiguration template = new JmsConfiguration(connectionFactory);
127 template.setTransactionManager(transactionManager);
128 template.setTransacted(true);
129 template.setTransactedInOut(true);
130 return jmsComponent(template);
131 }
132
133 // Properties
134 // -------------------------------------------------------------------------
135
136 public JmsConfiguration getConfiguration() {
137 if (configuration == null) {
138 configuration = createConfiguration();
139
140 // If we are being configured with spring...
141 if (applicationContext != null) {
142 Map<String, Object> beansOfType =
143 CastUtils.cast(applicationContext.getBeansOfType(ConnectionFactory.class));
144 if (!beansOfType.isEmpty()) {
145 ConnectionFactory cf = (ConnectionFactory)beansOfType.values().iterator().next();
146 configuration.setConnectionFactory(cf);
147 }
148 beansOfType = CastUtils.cast(applicationContext.getBeansOfType(DestinationResolver.class));
149 if (!beansOfType.isEmpty()) {
150 DestinationResolver destinationResolver = (DestinationResolver)beansOfType.values()
151 .iterator().next();
152 configuration.setDestinationResolver(destinationResolver);
153 }
154 }
155 }
156 return configuration;
157 }
158
159 /**
160 * Sets the JMS configuration
161 *
162 * @param configuration the configuration to use by default for endpoints
163 */
164 public void setConfiguration(JmsConfiguration configuration) {
165 this.configuration = configuration;
166 }
167
168 public void setAcceptMessagesWhileStopping(boolean acceptMessagesWhileStopping) {
169 getConfiguration().setAcceptMessagesWhileStopping(acceptMessagesWhileStopping);
170 }
171
172 public void setAcknowledgementMode(int consumerAcknowledgementMode) {
173 getConfiguration().setAcknowledgementMode(consumerAcknowledgementMode);
174 }
175
176 public void setEagerLoadingOfProperties(boolean eagerLoadingOfProperties) {
177 getConfiguration().setEagerLoadingOfProperties(eagerLoadingOfProperties);
178 }
179
180 public void setAcknowledgementModeName(String consumerAcknowledgementMode) {
181 getConfiguration().setAcknowledgementModeName(consumerAcknowledgementMode);
182 }
183
184 public void setAutoStartup(boolean autoStartup) {
185 getConfiguration().setAutoStartup(autoStartup);
186 }
187
188 public void setCacheLevel(int cacheLevel) {
189 getConfiguration().setCacheLevel(cacheLevel);
190 }
191
192 public void setCacheLevelName(String cacheName) {
193 getConfiguration().setCacheLevelName(cacheName);
194 }
195
196 public void setClientId(String consumerClientId) {
197 getConfiguration().setClientId(consumerClientId);
198 }
199
200 public void setConcurrentConsumers(int concurrentConsumers) {
201 getConfiguration().setConcurrentConsumers(concurrentConsumers);
202 }
203
204 public void setConnectionFactory(ConnectionFactory connectionFactory) {
205 getConfiguration().setConnectionFactory(connectionFactory);
206 }
207
208 public void setConsumerType(ConsumerType consumerType) {
209 getConfiguration().setConsumerType(consumerType);
210 }
211
212 public void setDeliveryPersistent(boolean deliveryPersistent) {
213 getConfiguration().setDeliveryPersistent(deliveryPersistent);
214 }
215
216 public void setDurableSubscriptionName(String durableSubscriptionName) {
217 getConfiguration().setDurableSubscriptionName(durableSubscriptionName);
218 }
219
220 public void setExceptionListener(ExceptionListener exceptionListener) {
221 getConfiguration().setExceptionListener(exceptionListener);
222 }
223
224 public void setExplicitQosEnabled(boolean explicitQosEnabled) {
225 getConfiguration().setExplicitQosEnabled(explicitQosEnabled);
226 }
227
228 public void setExposeListenerSession(boolean exposeListenerSession) {
229 getConfiguration().setExposeListenerSession(exposeListenerSession);
230 }
231
232 public void setIdleTaskExecutionLimit(int idleTaskExecutionLimit) {
233 getConfiguration().setIdleTaskExecutionLimit(idleTaskExecutionLimit);
234 }
235
236 public void setMaxConcurrentConsumers(int maxConcurrentConsumers) {
237 getConfiguration().setMaxConcurrentConsumers(maxConcurrentConsumers);
238 }
239
240 public void setMaxMessagesPerTask(int maxMessagesPerTask) {
241 getConfiguration().setMaxMessagesPerTask(maxMessagesPerTask);
242 }
243
244 public void setMessageConverter(MessageConverter messageConverter) {
245 getConfiguration().setMessageConverter(messageConverter);
246 }
247
248 public void setMapJmsMessage(boolean mapJmsMessage) {
249 getConfiguration().setMapJmsMessage(mapJmsMessage);
250 }
251
252 public void setMessageIdEnabled(boolean messageIdEnabled) {
253 getConfiguration().setMessageIdEnabled(messageIdEnabled);
254 }
255
256 public void setMessageTimestampEnabled(boolean messageTimestampEnabled) {
257 getConfiguration().setMessageTimestampEnabled(messageTimestampEnabled);
258 }
259
260 public void setAlwaysCopyMessage(boolean alwaysCopyMessage) {
261 getConfiguration().setAlwaysCopyMessage(alwaysCopyMessage);
262 }
263
264 public void setUseMessageIDAsCorrelationID(boolean useMessageIDAsCorrelationID) {
265 getConfiguration().setUseMessageIDAsCorrelationID(useMessageIDAsCorrelationID);
266 }
267
268 public void setPriority(int priority) {
269 getConfiguration().setPriority(priority);
270 }
271
272 public void setPubSubNoLocal(boolean pubSubNoLocal) {
273 getConfiguration().setPubSubNoLocal(pubSubNoLocal);
274 }
275
276 public void setReceiveTimeout(long receiveTimeout) {
277 getConfiguration().setReceiveTimeout(receiveTimeout);
278 }
279
280 public void setRecoveryInterval(long recoveryInterval) {
281 getConfiguration().setRecoveryInterval(recoveryInterval);
282 }
283
284 public void setSubscriptionDurable(boolean subscriptionDurable) {
285 getConfiguration().setSubscriptionDurable(subscriptionDurable);
286 }
287
288 public void setTaskExecutor(TaskExecutor taskExecutor) {
289 getConfiguration().setTaskExecutor(taskExecutor);
290 }
291
292 public void setTimeToLive(long timeToLive) {
293 getConfiguration().setTimeToLive(timeToLive);
294 }
295
296 public void setTransacted(boolean consumerTransacted) {
297 getConfiguration().setTransacted(consumerTransacted);
298 }
299
300 public void setTransactionManager(PlatformTransactionManager transactionManager) {
301 getConfiguration().setTransactionManager(transactionManager);
302 }
303
304 public void setTransactionName(String transactionName) {
305 getConfiguration().setTransactionName(transactionName);
306 }
307
308 public void setTransactionTimeout(int transactionTimeout) {
309 getConfiguration().setTransactionTimeout(transactionTimeout);
310 }
311
312 public void setTestConnectionOnStartup(boolean testConnectionOnStartup) {
313 getConfiguration().setTestConnectionOnStartup(testConnectionOnStartup);
314 }
315
316 public void setRequestTimeout(long requestTimeout) {
317 getConfiguration().setRequestTimeout(requestTimeout);
318 }
319
320 public void setTransferExchange(boolean transferExchange) {
321 getConfiguration().setTransferExchange(transferExchange);
322 }
323
324 public void setTransferException(boolean transferException) {
325 getConfiguration().setTransferException(transferException);
326 }
327
328 /**
329 * @deprecated will be removed in Camel 2.2
330 */
331 @Deprecated
332 public void setUseVersion102(boolean useVersion102) {
333 getConfiguration().setUseVersion102(useVersion102);
334 }
335
336 public void setJmsOperations(JmsOperations jmsOperations) {
337 getConfiguration().setJmsOperations(jmsOperations);
338 }
339
340 public void setDestinationResolver(DestinationResolver destinationResolver) {
341 getConfiguration().setDestinationResolver(destinationResolver);
342 }
343
344 public synchronized Requestor getRequestor() throws Exception {
345 if (requestor == null) {
346 requestor = new Requestor(getConfiguration(), getScheduledExecutorService());
347 requestor.start();
348 }
349 return requestor;
350 }
351
352 public void setRequestor(Requestor requestor) {
353 this.requestor = requestor;
354 }
355
356 public synchronized ScheduledExecutorService getScheduledExecutorService() {
357 if (scheduledExecutorService == null) {
358 scheduledExecutorService = getCamelContext().getExecutorServiceStrategy()
359 .newScheduledThreadPool(this, "JmsComponent", DEFAULT_THREADPOOL_SIZE);
360 }
361 return scheduledExecutorService;
362 }
363
364 public void setScheduledExecutorService(ScheduledExecutorService scheduledExecutorService) {
365 this.scheduledExecutorService = scheduledExecutorService;
366 }
367
368 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
369 this.applicationContext = applicationContext;
370 }
371
372 public QueueBrowseStrategy getQueueBrowseStrategy() {
373 if (queueBrowseStrategy == null) {
374 if (!attemptedToCreateQueueBrowserStrategy) {
375 attemptedToCreateQueueBrowserStrategy = true;
376 try {
377 queueBrowseStrategy = tryCreateDefaultQueueBrowseStrategy(getCamelContext());
378 } catch (Throwable e) {
379 LOG.warn("Could not instantiate the QueueBrowseStrategy are you using Spring 2.0.x"
380 + " by any chance? Error: " + e, e);
381 }
382 }
383 }
384 return queueBrowseStrategy;
385 }
386
387 public void setQueueBrowseStrategy(QueueBrowseStrategy queueBrowseStrategy) {
388 this.queueBrowseStrategy = queueBrowseStrategy;
389 }
390
391 public HeaderFilterStrategy getHeaderFilterStrategy() {
392 return headerFilterStrategy;
393 }
394
395 public void setHeaderFilterStrategy(HeaderFilterStrategy strategy) {
396 this.headerFilterStrategy = strategy;
397 }
398
399 // Implementation methods
400 // -------------------------------------------------------------------------
401
402 @Override
403 protected void doStop() throws Exception {
404 if (requestor != null) {
405 requestor.stop();
406 }
407 super.doStop();
408 }
409
410 @Override
411 protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters)
412 throws Exception {
413
414 boolean pubSubDomain = false;
415 boolean tempDestination = false;
416 if (remaining.startsWith(JmsConfiguration.QUEUE_PREFIX)) {
417 pubSubDomain = false;
418 remaining = removeStartingCharacters(remaining.substring(JmsConfiguration.QUEUE_PREFIX.length()), '/');
419 } else if (remaining.startsWith(JmsConfiguration.TOPIC_PREFIX)) {
420 pubSubDomain = true;
421 remaining = removeStartingCharacters(remaining.substring(JmsConfiguration.TOPIC_PREFIX.length()), '/');
422 } else if (remaining.startsWith(JmsConfiguration.TEMP_QUEUE_PREFIX)) {
423 pubSubDomain = false;
424 tempDestination = true;
425 remaining = removeStartingCharacters(remaining.substring(JmsConfiguration.TEMP_QUEUE_PREFIX.length()), '/');
426 } else if (remaining.startsWith(JmsConfiguration.TEMP_TOPIC_PREFIX)) {
427 pubSubDomain = true;
428 tempDestination = true;
429 remaining = removeStartingCharacters(remaining.substring(JmsConfiguration.TEMP_TOPIC_PREFIX.length()), '/');
430 }
431
432 final String subject = convertPathToActualDestination(remaining, parameters);
433
434 // lets make sure we copy the configuration as each endpoint can
435 // customize its own version
436 JmsConfiguration newConfiguration = getConfiguration().copy();
437 JmsEndpoint endpoint;
438 if (pubSubDomain) {
439 if (tempDestination) {
440 endpoint = new JmsTemporaryTopicEndpoint(uri, this, subject, newConfiguration);
441 } else {
442 endpoint = new JmsEndpoint(uri, this, subject, pubSubDomain, newConfiguration);
443 }
444 } else {
445 QueueBrowseStrategy strategy = getQueueBrowseStrategy();
446 if (tempDestination) {
447 endpoint = new JmsTemporaryQueueEndpoint(uri, this, subject, newConfiguration, strategy);
448 } else {
449 endpoint = new JmsQueueEndpoint(uri, this, subject, newConfiguration, strategy);
450 }
451 }
452
453 String selector = getAndRemoveParameter(parameters, "selector", String.class);
454 if (selector != null) {
455 endpoint.setSelector(selector);
456 }
457 String username = getAndRemoveParameter(parameters, "username", String.class);
458 String password = getAndRemoveParameter(parameters, "password", String.class);
459 if (username != null && password != null) {
460 ConnectionFactory cf = endpoint.getConfiguration().getConnectionFactory();
461 UserCredentialsConnectionFactoryAdapter ucfa = new UserCredentialsConnectionFactoryAdapter();
462 ucfa.setTargetConnectionFactory(cf);
463 ucfa.setPassword(password);
464 ucfa.setUsername(username);
465 endpoint.getConfiguration().setConnectionFactory(ucfa);
466 } else {
467 if (username != null || password != null) {
468 // exclude the the saturation of username and password are all empty
469 throw new IllegalArgumentException("The JmsComponent's username or password is null");
470 }
471 }
472
473 // jms header strategy
474 String strategyVal = getAndRemoveParameter(parameters, KEY_FORMAT_STRATEGY_PARAM, String.class);
475 if ("default".equalsIgnoreCase(strategyVal)) {
476 endpoint.setJmsKeyFormatStrategy(new DefaultJmsKeyFormatStrategy());
477 } else if ("passthrough".equalsIgnoreCase(strategyVal)) {
478 endpoint.setJmsKeyFormatStrategy(new PassThroughJmsKeyFormatStrategy());
479 } else { // a reference
480 parameters.put(KEY_FORMAT_STRATEGY_PARAM, strategyVal);
481 endpoint.setJmsKeyFormatStrategy(resolveAndRemoveReferenceParameter(
482 parameters, KEY_FORMAT_STRATEGY_PARAM, JmsKeyFormatStrategy.class));
483 }
484
485 setProperties(endpoint.getConfiguration(), parameters);
486 endpoint.setHeaderFilterStrategy(getHeaderFilterStrategy());
487
488 return endpoint;
489 }
490
491 /**
492 * A strategy method allowing the URI destination to be translated into the
493 * actual JMS destination name (say by looking up in JNDI or something)
494 */
495 protected String convertPathToActualDestination(String path, Map<String, Object> parameters) {
496 return path;
497 }
498
499 /**
500 * Factory method to create the default configuration instance
501 *
502 * @return a newly created configuration object which can then be further
503 * customized
504 */
505 protected JmsConfiguration createConfiguration() {
506 return new JmsConfiguration();
507 }
508
509 /**
510 * Attempts to instantiate the default {@link QueueBrowseStrategy} which
511 * should work fine if Spring 2.5.x or later is on the classpath but this
512 * will fail if 2.0.x are on the classpath. We can continue to operate on
513 * this version we just cannot support the browseable queues supported by
514 * {@link JmsQueueEndpoint}
515 *
516 * @return the queue browse strategy or null if it cannot be supported
517 */
518 protected static QueueBrowseStrategy tryCreateDefaultQueueBrowseStrategy(CamelContext context) {
519 // lets try instantiate the default implementation
520 // use the class loading this class from camel-jms to work in OSGi environments as the camel-jms
521 // should import the spring-jms jars.
522 if (JmsHelper.isSpring20x()) {
523 // not possible with spring 2.0.x
524 return null;
525 } else {
526 // lets try instantiate the default implementation
527 Class<?> type = ObjectHelper.loadClass(DEFAULT_QUEUE_BROWSE_STRATEGY, JmsComponent.class.getClassLoader());
528 if (type != null) {
529 return ObjectHelper.newInstance(type, QueueBrowseStrategy.class);
530 } else {
531 return null;
532 }
533 }
534 }
535
536 }