/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.sjms;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import javax.jms.ConnectionFactory;
import org.apache.camel.CamelException;
import org.apache.camel.Endpoint;
import org.apache.camel.ExchangePattern;
import org.apache.camel.component.sjms.jms.ConnectionResource;
import org.apache.camel.component.sjms.jms.DefaultJmsKeyFormatStrategy;
import org.apache.camel.component.sjms.jms.DestinationCreationStrategy;
import org.apache.camel.component.sjms.jms.JmsKeyFormatStrategy;
import org.apache.camel.component.sjms.jms.MessageCreatedStrategy;
import org.apache.camel.component.sjms.taskmanager.TimedTaskManager;
import org.apache.camel.impl.HeaderFilterStrategyComponent;
import org.apache.camel.spi.Metadata;
/**
* The <a href="http://camel.apache.org/sjms">Simple JMS</a> component.
*/
public class SjmsComponent extends HeaderFilterStrategyComponent {
private ExecutorService asyncStartStopExecutorService;
@Metadata(label = "advanced", description = "A ConnectionFactory is required to enable the SjmsComponent. It can be set directly or set set as part of a ConnectionResource.")
private ConnectionFactory connectionFactory;
@Metadata(label = "advanced", description = "A ConnectionResource is an interface that allows for customization and container control of the ConnectionFactory."
+ " * See Plugable Connection Resource Management for further details.")
private ConnectionResource connectionResource;
@Metadata(label = "advanced", description = "Pluggable strategy for encoding and decoding JMS keys so they can be compliant with the JMS specification."
+ " Camel provides one implementation out of the box: default. The default strategy will safely marshal dots and hyphens (. and -)."
+ " Can be used for JMS brokers which do not care whether JMS header keys contain illegal characters. You can provide your own implementation"
+ " of the org.apache.camel.component.jms.JmsKeyFormatStrategy and refer to it using the # notation.")
private JmsKeyFormatStrategy jmsKeyFormatStrategy = new DefaultJmsKeyFormatStrategy();
@Metadata(defaultValue = "1", description = "The maximum number of connections available to endpoints started under this component")
private Integer connectionCount = 1;
@Metadata(label = "transaction", description = "To configure which kind of commit strategy to use. Camel provides two implementations out of the box, default and batch.")
private TransactionCommitStrategy transactionCommitStrategy;
@Metadata(label = "advanced", description = "To use a custom TimedTaskManager")
private TimedTaskManager timedTaskManager;
@Metadata(label = "advanced", description = "To use a custom DestinationCreationStrategy.")
private DestinationCreationStrategy destinationCreationStrategy;
@Metadata(label = "advanced", description = "To use the given MessageCreatedStrategy which are invoked when Camel creates new instances"
+ " of <tt>javax.jms.Message</tt> objects when Camel is sending a JMS message.")
private MessageCreatedStrategy messageCreatedStrategy;
@Metadata(label = "advanced", defaultValue = "true", description = "When using the default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource}"
+ " then should each {@link javax.jms.Connection} be tested (calling start) before returned from the pool.")
private boolean connectionTestOnBorrow = true;
@Metadata(label = "security", secret = true, description = "The username to use when creating {@link javax.jms.Connection} when using the"
+ " default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource}.")
private String connectionUsername;
@Metadata(label = "security", secret = true, description = "The password to use when creating {@link javax.jms.Connection} when using the"
+ " default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource}.")
private String connectionPassword;
@Metadata(label = "advanced", description = "The client ID to use when creating {@link javax.jms.Connection} when using the"
+ " default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource}.")
private String connectionClientId;
@Metadata(label = "advanced", defaultValue = "5000", description = "The max wait time in millis to block and wait on free connection when the pool"
+ " is exhausted when using the default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource}.")
private long connectionMaxWait = 5000;
public SjmsComponent() {
super(SjmsEndpoint.class);
}
protected SjmsComponent(Class<? extends Endpoint> endpointClass) {
super(endpointClass);
}
@Override
protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
validateMepAndReplyTo(parameters);
SjmsEndpoint endpoint = createSjmsEndpoint(uri, remaining);
setProperties(endpoint, parameters);
if (endpoint.isTransacted()) {
endpoint.setSynchronous(true);
}
if (transactionCommitStrategy != null) {
endpoint.setTransactionCommitStrategy(transactionCommitStrategy);
}
if (destinationCreationStrategy != null) {
endpoint.setDestinationCreationStrategy(destinationCreationStrategy);
}
if (getHeaderFilterStrategy() != null) {
endpoint.setHeaderFilterStrategy(getHeaderFilterStrategy());
}
if (messageCreatedStrategy != null) {
endpoint.setMessageCreatedStrategy(messageCreatedStrategy);
}
return endpoint;
}
protected SjmsEndpoint createSjmsEndpoint(String uri, String remaining) {
return new SjmsEndpoint(uri, this, remaining);
}
/**
* Helper method used to verify that when there is a namedReplyTo value we
* are using the InOut MEP. If namedReplyTo is defined and the MEP is InOnly
* the endpoint won't be expecting a reply so throw an error to alert the
* user.
*
* @param parameters {@link Endpoint} parameters
* @throws Exception throws a {@link CamelException} when MEP equals InOnly
* and namedReplyTo is defined.
*/
private static void validateMepAndReplyTo(Map<String, Object> parameters) throws Exception {
boolean namedReplyToSet = parameters.containsKey("namedReplyTo");
boolean mepSet = parameters.containsKey("exchangePattern");
if (namedReplyToSet && mepSet) {
if (!parameters.get("exchangePattern").equals(ExchangePattern.InOut.toString())) {
String namedReplyTo = (String) parameters.get("namedReplyTo");
ExchangePattern mep = ExchangePattern.valueOf((String) parameters.get("exchangePattern"));
throw new CamelException("Setting parameter namedReplyTo=" + namedReplyTo + " requires a MEP of type InOut. Parameter exchangePattern is set to " + mep);
}
}
}
@Override
protected void doStart() throws Exception {
super.doStart();
timedTaskManager = new TimedTaskManager();
}
@Override
protected void doStop() throws Exception {
if (timedTaskManager != null) {
timedTaskManager.cancelTasks();
timedTaskManager = null;
}
super.doStop();
}
@Override
protected void doShutdown() throws Exception {
if (asyncStartStopExecutorService != null) {
getCamelContext().getExecutorServiceManager().shutdownNow(asyncStartStopExecutorService);
asyncStartStopExecutorService = null;
}
super.doShutdown();
}
protected synchronized ExecutorService getAsyncStartStopExecutorService() {
if (asyncStartStopExecutorService == null) {
// use a cached thread pool for async start tasks as they can run for a while, and we need a dedicated thread
// for each task, and the thread pool will shrink when no more tasks running
asyncStartStopExecutorService = getCamelContext().getExecutorServiceManager().newCachedThreadPool(this, "AsyncStartStopListener");
}
return asyncStartStopExecutorService;
}
/**
* A ConnectionFactory is required to enable the SjmsComponent.
* It can be set directly or set set as part of a ConnectionResource.
*/
public void setConnectionFactory(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
public ConnectionFactory getConnectionFactory() {
return connectionFactory;
}
/**
* A ConnectionResource is an interface that allows for customization and container control of the ConnectionFactory.
* See Plugable Connection Resource Management for further details.
*/
public void setConnectionResource(ConnectionResource connectionResource) {
this.connectionResource = connectionResource;
}
public ConnectionResource getConnectionResource() {
return connectionResource;
}
/**
* The maximum number of connections available to endpoints started under this component
*/
public void setConnectionCount(Integer maxConnections) {
this.connectionCount = maxConnections;
}
public Integer getConnectionCount() {
return connectionCount;
}
/**
* Pluggable strategy for encoding and decoding JMS keys so they can be compliant with the JMS specification.
* Camel provides one implementation out of the box: default.
* The default strategy will safely marshal dots and hyphens (. and -).
* Can be used for JMS brokers which do not care whether JMS header keys contain illegal characters.
* You can provide your own implementation of the org.apache.camel.component.jms.JmsKeyFormatStrategy
* and refer to it using the # notation.
*/
public void setJmsKeyFormatStrategy(JmsKeyFormatStrategy jmsKeyFormatStrategy) {
this.jmsKeyFormatStrategy = jmsKeyFormatStrategy;
}
public JmsKeyFormatStrategy getJmsKeyFormatStrategy() {
return jmsKeyFormatStrategy;
}
public TransactionCommitStrategy getTransactionCommitStrategy() {
return transactionCommitStrategy;
}
/**
* To configure which kind of commit strategy to use. Camel provides two implementations out
* of the box, default and batch.
*/
public void setTransactionCommitStrategy(TransactionCommitStrategy commitStrategy) {
this.transactionCommitStrategy = commitStrategy;
}
public DestinationCreationStrategy getDestinationCreationStrategy() {
return destinationCreationStrategy;
}
/**
* To use a custom DestinationCreationStrategy.
*/
public void setDestinationCreationStrategy(DestinationCreationStrategy destinationCreationStrategy) {
this.destinationCreationStrategy = destinationCreationStrategy;
}
public TimedTaskManager getTimedTaskManager() {
return timedTaskManager;
}
/**
* To use a custom TimedTaskManager
*/
public void setTimedTaskManager(TimedTaskManager timedTaskManager) {
this.timedTaskManager = timedTaskManager;
}
public MessageCreatedStrategy getMessageCreatedStrategy() {
return messageCreatedStrategy;
}
/**
* To use the given MessageCreatedStrategy which are invoked when Camel creates new instances of <tt>javax.jms.Message</tt>
* objects when Camel is sending a JMS message.
*/
public void setMessageCreatedStrategy(MessageCreatedStrategy messageCreatedStrategy) {
this.messageCreatedStrategy = messageCreatedStrategy;
}
public boolean isConnectionTestOnBorrow() {
return connectionTestOnBorrow;
}
/**
* When using the default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource} then should each {@link javax.jms.Connection}
* be tested (calling start) before returned from the pool.
*/
public void setConnectionTestOnBorrow(boolean connectionTestOnBorrow) {
this.connectionTestOnBorrow = connectionTestOnBorrow;
}
public String getConnectionUsername() {
return connectionUsername;
}
/**
* The username to use when creating {@link javax.jms.Connection} when using the default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource}.
*/
public void setConnectionUsername(String connectionUsername) {
this.connectionUsername = connectionUsername;
}
public String getConnectionPassword() {
return connectionPassword;
}
/**
* The password to use when creating {@link javax.jms.Connection} when using the default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource}.
*/
public void setConnectionPassword(String connectionPassword) {
this.connectionPassword = connectionPassword;
}
public String getConnectionClientId() {
return connectionClientId;
}
/**
* The client ID to use when creating {@link javax.jms.Connection} when using the default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource}.
*/
public void setConnectionClientId(String connectionClientId) {
this.connectionClientId = connectionClientId;
}
public long getConnectionMaxWait() {
return connectionMaxWait;
}
/**
* The max wait time in millis to block and wait on free connection when the pool is exhausted
* when using the default {@link org.apache.camel.component.sjms.jms.ConnectionFactoryResource}.
*/
public void setConnectionMaxWait(long connectionMaxWait) {
this.connectionMaxWait = connectionMaxWait;
}
}