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 */
017package org.apache.activemq;
018
019import java.net.URI;
020import java.net.URISyntaxException;
021import java.security.AccessController;
022import java.security.PrivilegedAction;
023import java.util.*;
024import java.util.concurrent.RejectedExecutionHandler;
025
026import javax.jms.Connection;
027import javax.jms.ConnectionFactory;
028import javax.jms.ExceptionListener;
029import javax.jms.JMSException;
030import javax.jms.QueueConnection;
031import javax.jms.QueueConnectionFactory;
032import javax.jms.TopicConnection;
033import javax.jms.TopicConnectionFactory;
034import javax.naming.Context;
035
036import org.apache.activemq.blob.BlobTransferPolicy;
037import org.apache.activemq.broker.region.policy.RedeliveryPolicyMap;
038import org.apache.activemq.jndi.JNDIBaseStorable;
039import org.apache.activemq.management.JMSStatsImpl;
040import org.apache.activemq.management.StatsCapable;
041import org.apache.activemq.management.StatsImpl;
042import org.apache.activemq.thread.TaskRunnerFactory;
043import org.apache.activemq.transport.Transport;
044import org.apache.activemq.transport.TransportFactory;
045import org.apache.activemq.transport.TransportListener;
046import org.apache.activemq.util.*;
047import org.apache.activemq.util.URISupport.CompositeData;
048import org.slf4j.Logger;
049import org.slf4j.LoggerFactory;
050
051/**
052 * A ConnectionFactory is an an Administered object, and is used for creating
053 * Connections. <p/> This class also implements QueueConnectionFactory and
054 * TopicConnectionFactory. You can use this connection to create both
055 * QueueConnections and TopicConnections.
056 *
057 *
058 * @see javax.jms.ConnectionFactory
059 */
060public class ActiveMQConnectionFactory extends JNDIBaseStorable implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory, StatsCapable, Cloneable {
061    private static final Logger LOG = LoggerFactory.getLogger(ActiveMQConnectionFactory.class);
062    private static final String DEFAULT_BROKER_HOST;
063    private static final int DEFAULT_BROKER_PORT;
064    static{
065        String host = null;
066        String port = null;
067        try {
068             host = AccessController.doPrivileged(new PrivilegedAction<String>() {
069                 @Override
070                 public String run() {
071                     String result = System.getProperty("org.apache.activemq.AMQ_HOST");
072                     result = (result==null||result.isEmpty()) ?  System.getProperty("AMQ_HOST","localhost") : result;
073                     return result;
074                 }
075             });
076             port = AccessController.doPrivileged(new PrivilegedAction<String>() {
077                 @Override
078                 public String run() {
079                     String result = System.getProperty("org.apache.activemq.AMQ_PORT");
080                     result = (result==null||result.isEmpty()) ?  System.getProperty("AMQ_PORT","61616") : result;
081                     return result;
082                 }
083             });
084        }catch(Throwable e){
085            LOG.debug("Failed to look up System properties for host and port",e);
086        }
087        host = (host == null || host.isEmpty()) ? "localhost" : host;
088        port = (port == null || port.isEmpty()) ? "61616" : port;
089        DEFAULT_BROKER_HOST = host;
090        DEFAULT_BROKER_PORT = Integer.parseInt(port);
091    }
092
093
094    public static final String DEFAULT_BROKER_BIND_URL;
095
096    static{
097        final String defaultURL = "tcp://" + DEFAULT_BROKER_HOST + ":" + DEFAULT_BROKER_PORT;
098        String bindURL = null;
099
100        try {
101            bindURL = AccessController.doPrivileged(new PrivilegedAction<String>() {
102                @Override
103                public String run() {
104                    String result = System.getProperty("org.apache.activemq.BROKER_BIND_URL");
105                    result = (result==null||result.isEmpty()) ?  System.getProperty("BROKER_BIND_URL",defaultURL) : result;
106                    return result;
107                }
108            });
109        }catch(Throwable e){
110            LOG.debug("Failed to look up System properties for host and port",e);
111        }
112        bindURL = (bindURL == null || bindURL.isEmpty()) ? defaultURL : bindURL;
113        DEFAULT_BROKER_BIND_URL = bindURL;
114    }
115
116    public static final String DEFAULT_BROKER_URL = "failover://"+DEFAULT_BROKER_BIND_URL;
117    public static final String DEFAULT_USER = null;
118    public static final String DEFAULT_PASSWORD = null;
119    public static final int DEFAULT_PRODUCER_WINDOW_SIZE = 0;
120
121    protected URI brokerURL;
122    protected String userName;
123    protected String password;
124    protected String clientID;
125    protected boolean dispatchAsync=true;
126    protected boolean alwaysSessionAsync=true;
127
128    JMSStatsImpl factoryStats = new JMSStatsImpl();
129
130    private IdGenerator clientIdGenerator;
131    private String clientIDPrefix;
132    private IdGenerator connectionIdGenerator;
133    private String connectionIDPrefix;
134
135    // client policies
136    private ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy();
137    private RedeliveryPolicyMap redeliveryPolicyMap = new RedeliveryPolicyMap();
138    {
139        redeliveryPolicyMap.setDefaultEntry(new RedeliveryPolicy());
140    }
141    private BlobTransferPolicy blobTransferPolicy = new BlobTransferPolicy();
142    private MessageTransformer transformer;
143
144    private boolean disableTimeStampsByDefault;
145    private boolean optimizedMessageDispatch = true;
146    private long optimizeAcknowledgeTimeOut = 300;
147    private long optimizedAckScheduledAckInterval = 0;
148    private boolean copyMessageOnSend = true;
149    private boolean useCompression;
150    private boolean objectMessageSerializationDefered;
151    private boolean useAsyncSend;
152    private boolean optimizeAcknowledge;
153    private int closeTimeout = 15000;
154    private boolean useRetroactiveConsumer;
155    private boolean exclusiveConsumer;
156    private boolean nestedMapAndListEnabled = true;
157    private boolean alwaysSyncSend;
158    private boolean watchTopicAdvisories = true;
159    private int producerWindowSize = DEFAULT_PRODUCER_WINDOW_SIZE;
160    private long warnAboutUnstartedConnectionTimeout = 500L;
161    private int sendTimeout = 0;
162    private boolean sendAcksAsync=true;
163    private TransportListener transportListener;
164    private ExceptionListener exceptionListener;
165    private int auditDepth = ActiveMQMessageAudit.DEFAULT_WINDOW_SIZE;
166    private int auditMaximumProducerNumber = ActiveMQMessageAudit.MAXIMUM_PRODUCER_COUNT;
167    private boolean useDedicatedTaskRunner;
168    private long consumerFailoverRedeliveryWaitPeriod = 0;
169    private boolean checkForDuplicates = true;
170    private ClientInternalExceptionListener clientInternalExceptionListener;
171    private boolean messagePrioritySupported = false;
172    private boolean transactedIndividualAck = false;
173    private boolean nonBlockingRedelivery = false;
174    private int maxThreadPoolSize = ActiveMQConnection.DEFAULT_THREAD_POOL_SIZE;
175    private TaskRunnerFactory sessionTaskRunner;
176    private RejectedExecutionHandler rejectedTaskHandler = null;
177    protected int xaAckMode = -1; // ensure default init before setting via brokerUrl introspection in sub class
178    private boolean rmIdFromConnectionId = false;
179    private boolean consumerExpiryCheckEnabled = true;
180    private List<String> trustedPackages = Arrays.asList(ClassLoadingAwareObjectInputStream.serializablePackages);
181    private boolean trustAllPackages = false;
182
183    // /////////////////////////////////////////////
184    //
185    // ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory Methods
186    //
187    // /////////////////////////////////////////////
188
189    public ActiveMQConnectionFactory() {
190        this(DEFAULT_BROKER_URL);
191    }
192
193    public ActiveMQConnectionFactory(String brokerURL) {
194        this(createURI(brokerURL));
195    }
196
197    public ActiveMQConnectionFactory(URI brokerURL) {
198        setBrokerURL(brokerURL.toString());
199    }
200
201    public ActiveMQConnectionFactory(String userName, String password, URI brokerURL) {
202        setUserName(userName);
203        setPassword(password);
204        setBrokerURL(brokerURL.toString());
205    }
206
207    public ActiveMQConnectionFactory(String userName, String password, String brokerURL) {
208        setUserName(userName);
209        setPassword(password);
210        setBrokerURL(brokerURL);
211    }
212
213    /**
214     * Returns a copy of the given connection factory
215     */
216    public ActiveMQConnectionFactory copy() {
217        try {
218            return (ActiveMQConnectionFactory)super.clone();
219        } catch (CloneNotSupportedException e) {
220            throw new RuntimeException("This should never happen: " + e, e);
221        }
222    }
223
224    /*boolean*
225     * @param brokerURL
226     * @return
227     * @throws URISyntaxException
228     */
229    private static URI createURI(String brokerURL) {
230        try {
231            return new URI(brokerURL);
232        } catch (URISyntaxException e) {
233            throw (IllegalArgumentException)new IllegalArgumentException("Invalid broker URI: " + brokerURL).initCause(e);
234        }
235    }
236
237    /**
238     * @return Returns the Connection.
239     */
240    @Override
241    public Connection createConnection() throws JMSException {
242        return createActiveMQConnection();
243    }
244
245    /**
246     * @return Returns the Connection.
247     */
248    @Override
249    public Connection createConnection(String userName, String password) throws JMSException {
250        return createActiveMQConnection(userName, password);
251    }
252
253    /**
254     * @return Returns the QueueConnection.
255     * @throws JMSException
256     */
257    @Override
258    public QueueConnection createQueueConnection() throws JMSException {
259        return createActiveMQConnection().enforceQueueOnlyConnection();
260    }
261
262    /**
263     * @return Returns the QueueConnection.
264     */
265    @Override
266    public QueueConnection createQueueConnection(String userName, String password) throws JMSException {
267        return createActiveMQConnection(userName, password).enforceQueueOnlyConnection();
268    }
269
270    /**
271     * @return Returns the TopicConnection.
272     * @throws JMSException
273     */
274    @Override
275    public TopicConnection createTopicConnection() throws JMSException {
276        return createActiveMQConnection();
277    }
278
279    /**
280     * @return Returns the TopicConnection.
281     */
282    @Override
283    public TopicConnection createTopicConnection(String userName, String password) throws JMSException {
284        return createActiveMQConnection(userName, password);
285    }
286
287    /**
288     * @return the StatsImpl associated with this ConnectionFactory.
289     */
290    @Override
291    public StatsImpl getStats() {
292        return this.factoryStats;
293    }
294
295    // /////////////////////////////////////////////
296    //
297    // Implementation methods.
298    //
299    // /////////////////////////////////////////////
300
301    protected ActiveMQConnection createActiveMQConnection() throws JMSException {
302        return createActiveMQConnection(userName, password);
303    }
304
305    /**
306     * Creates a Transport based on this object's connection settings. Separated
307     * from createActiveMQConnection to allow for subclasses to override.
308     *
309     * @return The newly created Transport.
310     * @throws JMSException If unable to create trasnport.
311     */
312    protected Transport createTransport() throws JMSException {
313        try {
314            return TransportFactory.connect(brokerURL);
315        } catch (Exception e) {
316            throw JMSExceptionSupport.create("Could not create Transport. Reason: " + e, e);
317        }
318    }
319
320    /**
321     * @return Returns the Connection.
322     */
323    protected ActiveMQConnection createActiveMQConnection(String userName, String password) throws JMSException {
324        if (brokerURL == null) {
325            throw new ConfigurationException("brokerURL not set.");
326        }
327        ActiveMQConnection connection = null;
328        try {
329            Transport transport = createTransport();
330            connection = createActiveMQConnection(transport, factoryStats);
331
332            connection.setUserName(userName);
333            connection.setPassword(password);
334
335            configureConnection(connection);
336
337            transport.start();
338
339            if (clientID != null) {
340                connection.setDefaultClientID(clientID);
341            }
342
343            return connection;
344        } catch (JMSException e) {
345            // Clean up!
346            try {
347                connection.close();
348            } catch (Throwable ignore) {
349            }
350            throw e;
351        } catch (Exception e) {
352            // Clean up!
353            try {
354                connection.close();
355            } catch (Throwable ignore) {
356            }
357            throw JMSExceptionSupport.create("Could not connect to broker URL: " + brokerURL + ". Reason: " + e, e);
358        }
359    }
360
361    protected ActiveMQConnection createActiveMQConnection(Transport transport, JMSStatsImpl stats) throws Exception {
362        ActiveMQConnection connection = new ActiveMQConnection(transport, getClientIdGenerator(),
363                getConnectionIdGenerator(), stats);
364        return connection;
365    }
366
367    protected void configureConnection(ActiveMQConnection connection) throws JMSException {
368        connection.setPrefetchPolicy(getPrefetchPolicy());
369        connection.setDisableTimeStampsByDefault(isDisableTimeStampsByDefault());
370        connection.setOptimizedMessageDispatch(isOptimizedMessageDispatch());
371        connection.setCopyMessageOnSend(isCopyMessageOnSend());
372        connection.setUseCompression(isUseCompression());
373        connection.setObjectMessageSerializationDefered(isObjectMessageSerializationDefered());
374        connection.setDispatchAsync(isDispatchAsync());
375        connection.setUseAsyncSend(isUseAsyncSend());
376        connection.setAlwaysSyncSend(isAlwaysSyncSend());
377        connection.setAlwaysSessionAsync(isAlwaysSessionAsync());
378        connection.setOptimizeAcknowledge(isOptimizeAcknowledge());
379        connection.setOptimizeAcknowledgeTimeOut(getOptimizeAcknowledgeTimeOut());
380        connection.setOptimizedAckScheduledAckInterval(getOptimizedAckScheduledAckInterval());
381        connection.setUseRetroactiveConsumer(isUseRetroactiveConsumer());
382        connection.setExclusiveConsumer(isExclusiveConsumer());
383        connection.setRedeliveryPolicyMap(getRedeliveryPolicyMap());
384        connection.setTransformer(getTransformer());
385        connection.setBlobTransferPolicy(getBlobTransferPolicy().copy());
386        connection.setWatchTopicAdvisories(isWatchTopicAdvisories());
387        connection.setProducerWindowSize(getProducerWindowSize());
388        connection.setWarnAboutUnstartedConnectionTimeout(getWarnAboutUnstartedConnectionTimeout());
389        connection.setSendTimeout(getSendTimeout());
390        connection.setCloseTimeout(getCloseTimeout());
391        connection.setSendAcksAsync(isSendAcksAsync());
392        connection.setAuditDepth(getAuditDepth());
393        connection.setAuditMaximumProducerNumber(getAuditMaximumProducerNumber());
394        connection.setUseDedicatedTaskRunner(isUseDedicatedTaskRunner());
395        connection.setConsumerFailoverRedeliveryWaitPeriod(getConsumerFailoverRedeliveryWaitPeriod());
396        connection.setCheckForDuplicates(isCheckForDuplicates());
397        connection.setMessagePrioritySupported(isMessagePrioritySupported());
398        connection.setTransactedIndividualAck(isTransactedIndividualAck());
399        connection.setNonBlockingRedelivery(isNonBlockingRedelivery());
400        connection.setMaxThreadPoolSize(getMaxThreadPoolSize());
401        connection.setSessionTaskRunner(getSessionTaskRunner());
402        connection.setRejectedTaskHandler(getRejectedTaskHandler());
403        connection.setNestedMapAndListEnabled(isNestedMapAndListEnabled());
404        connection.setRmIdFromConnectionId(isRmIdFromConnectionId());
405        connection.setConsumerExpiryCheckEnabled(isConsumerExpiryCheckEnabled());
406        connection.setTrustedPackages(getTrustedPackages());
407        connection.setTrustAllPackages(isTrustAllPackages());
408        if (transportListener != null) {
409            connection.addTransportListener(transportListener);
410        }
411        if (exceptionListener != null) {
412            connection.setExceptionListener(exceptionListener);
413        }
414        if (clientInternalExceptionListener != null) {
415            connection.setClientInternalExceptionListener(clientInternalExceptionListener);
416        }
417    }
418
419    // /////////////////////////////////////////////
420    //
421    // Property Accessors
422    //
423    // /////////////////////////////////////////////
424
425    public String getBrokerURL() {
426        return brokerURL == null ? null : brokerURL.toString();
427    }
428
429    /**
430     * Sets the <a
431     * href="http://activemq.apache.org/configuring-transports.html">connection
432     * URL</a> used to connect to the ActiveMQ broker.
433     */
434    public void setBrokerURL(String brokerURL) {
435        this.brokerURL = createURI(brokerURL);
436
437        // Use all the properties prefixed with 'jms.' to set the connection
438        // factory
439        // options.
440        if (this.brokerURL.getQuery() != null) {
441            // It might be a standard URI or...
442            try {
443
444                Map<String,String> map = URISupport.parseQuery(this.brokerURL.getQuery());
445                Map<String,Object> jmsOptionsMap = IntrospectionSupport.extractProperties(map, "jms.");
446                if (buildFromMap(jmsOptionsMap)) {
447                    if (!jmsOptionsMap.isEmpty()) {
448                        String msg = "There are " + jmsOptionsMap.size()
449                            + " jms options that couldn't be set on the ConnectionFactory."
450                            + " Check the options are spelled correctly."
451                            + " Unknown parameters=[" + jmsOptionsMap + "]."
452                            + " This connection factory cannot be started.";
453                        throw new IllegalArgumentException(msg);
454                    }
455
456                    this.brokerURL = URISupport.createRemainingURI(this.brokerURL, map);
457                }
458
459            } catch (URISyntaxException e) {
460            }
461
462        } else {
463
464            // It might be a composite URI.
465            try {
466                CompositeData data = URISupport.parseComposite(this.brokerURL);
467                Map<String,Object> jmsOptionsMap = IntrospectionSupport.extractProperties(data.getParameters(), "jms.");
468                if (buildFromMap(jmsOptionsMap)) {
469                    if (!jmsOptionsMap.isEmpty()) {
470                        String msg = "There are " + jmsOptionsMap.size()
471                            + " jms options that couldn't be set on the ConnectionFactory."
472                            + " Check the options are spelled correctly."
473                            + " Unknown parameters=[" + jmsOptionsMap + "]."
474                            + " This connection factory cannot be started.";
475                        throw new IllegalArgumentException(msg);
476                    }
477
478                    this.brokerURL = data.toURI();
479                }
480            } catch (URISyntaxException e) {
481            }
482        }
483    }
484
485    public String getClientID() {
486        return clientID;
487    }
488
489    /**
490     * Sets the JMS clientID to use for the created connection. Note that this
491     * can only be used by one connection at once so generally its a better idea
492     * to set the clientID on a Connection
493     */
494    public void setClientID(String clientID) {
495        this.clientID = clientID;
496    }
497
498    public boolean isCopyMessageOnSend() {
499        return copyMessageOnSend;
500    }
501
502    /**
503     * Should a JMS message be copied to a new JMS Message object as part of the
504     * send() method in JMS. This is enabled by default to be compliant with the
505     * JMS specification. You can disable it if you do not mutate JMS messages
506     * after they are sent for a performance boost
507     */
508    public void setCopyMessageOnSend(boolean copyMessageOnSend) {
509        this.copyMessageOnSend = copyMessageOnSend;
510    }
511
512    public boolean isDisableTimeStampsByDefault() {
513        return disableTimeStampsByDefault;
514    }
515
516    /**
517     * Sets whether or not timestamps on messages should be disabled or not. If
518     * you disable them it adds a small performance boost.
519     */
520    public void setDisableTimeStampsByDefault(boolean disableTimeStampsByDefault) {
521        this.disableTimeStampsByDefault = disableTimeStampsByDefault;
522    }
523
524    public boolean isOptimizedMessageDispatch() {
525        return optimizedMessageDispatch;
526    }
527
528    /**
529     * If this flag is set then an larger prefetch limit is used - only
530     * applicable for durable topic subscribers.
531     */
532    public void setOptimizedMessageDispatch(boolean optimizedMessageDispatch) {
533        this.optimizedMessageDispatch = optimizedMessageDispatch;
534    }
535
536    public String getPassword() {
537        return password;
538    }
539
540    /**
541     * Sets the JMS password used for connections created from this factory
542     */
543    public void setPassword(String password) {
544        this.password = password;
545    }
546
547    public ActiveMQPrefetchPolicy getPrefetchPolicy() {
548        return prefetchPolicy;
549    }
550
551    /**
552     * Sets the <a
553     * href="http://activemq.apache.org/what-is-the-prefetch-limit-for.html">prefetch
554     * policy</a> for consumers created by this connection.
555     */
556    public void setPrefetchPolicy(ActiveMQPrefetchPolicy prefetchPolicy) {
557        this.prefetchPolicy = prefetchPolicy;
558    }
559
560    public boolean isUseAsyncSend() {
561        return useAsyncSend;
562    }
563
564    public BlobTransferPolicy getBlobTransferPolicy() {
565        return blobTransferPolicy;
566    }
567
568    /**
569     * Sets the policy used to describe how out-of-band BLOBs (Binary Large
570     * OBjects) are transferred from producers to brokers to consumers
571     */
572    public void setBlobTransferPolicy(BlobTransferPolicy blobTransferPolicy) {
573        this.blobTransferPolicy = blobTransferPolicy;
574    }
575
576    /**
577     * Forces the use of <a
578     * href="http://activemq.apache.org/async-sends.html">Async Sends</a> which
579     * adds a massive performance boost; but means that the send() method will
580     * return immediately whether the message has been sent or not which could
581     * lead to message loss.
582     */
583    public void setUseAsyncSend(boolean useAsyncSend) {
584        this.useAsyncSend = useAsyncSend;
585    }
586
587    public synchronized boolean isWatchTopicAdvisories() {
588        return watchTopicAdvisories;
589    }
590
591    public synchronized void setWatchTopicAdvisories(boolean watchTopicAdvisories) {
592        this.watchTopicAdvisories = watchTopicAdvisories;
593    }
594
595    /**
596     * @return true if always sync send messages
597     */
598    public boolean isAlwaysSyncSend() {
599        return this.alwaysSyncSend;
600    }
601
602    /**
603     * Set true if always require messages to be sync sent
604     *
605     * @param alwaysSyncSend
606     */
607    public void setAlwaysSyncSend(boolean alwaysSyncSend) {
608        this.alwaysSyncSend = alwaysSyncSend;
609    }
610
611    public String getUserName() {
612        return userName;
613    }
614
615    /**
616     * Sets the JMS userName used by connections created by this factory
617     */
618    public void setUserName(String userName) {
619        this.userName = userName;
620    }
621
622    public boolean isUseRetroactiveConsumer() {
623        return useRetroactiveConsumer;
624    }
625
626    /**
627     * Sets whether or not retroactive consumers are enabled. Retroactive
628     * consumers allow non-durable topic subscribers to receive old messages
629     * that were published before the non-durable subscriber started.
630     */
631    public void setUseRetroactiveConsumer(boolean useRetroactiveConsumer) {
632        this.useRetroactiveConsumer = useRetroactiveConsumer;
633    }
634
635    public boolean isExclusiveConsumer() {
636        return exclusiveConsumer;
637    }
638
639    /**
640     * Enables or disables whether or not queue consumers should be exclusive or
641     * not for example to preserve ordering when not using <a
642     * href="http://activemq.apache.org/message-groups.html">Message Groups</a>
643     *
644     * @param exclusiveConsumer
645     */
646    public void setExclusiveConsumer(boolean exclusiveConsumer) {
647        this.exclusiveConsumer = exclusiveConsumer;
648    }
649
650    public RedeliveryPolicy getRedeliveryPolicy() {
651        return redeliveryPolicyMap.getDefaultEntry();
652    }
653
654    /**
655     * Sets the global default redelivery policy to be used when a message is delivered
656     * but the session is rolled back
657     */
658    public void setRedeliveryPolicy(RedeliveryPolicy redeliveryPolicy) {
659        this.redeliveryPolicyMap.setDefaultEntry(redeliveryPolicy);
660    }
661
662    public RedeliveryPolicyMap getRedeliveryPolicyMap() {
663        return this.redeliveryPolicyMap;
664    }
665
666    /**
667     * Sets the global redelivery policy mapping to be used when a message is delivered
668     * but the session is rolled back
669     */
670    public void setRedeliveryPolicyMap(RedeliveryPolicyMap redeliveryPolicyMap) {
671        this.redeliveryPolicyMap = redeliveryPolicyMap;
672    }
673
674    public MessageTransformer getTransformer() {
675        return transformer;
676    }
677
678    /**
679     * @return the sendTimeout (in milliseconds)
680     */
681    public int getSendTimeout() {
682        return sendTimeout;
683    }
684
685    /**
686     * @param sendTimeout the sendTimeout to set (in milliseconds)
687     */
688    public void setSendTimeout(int sendTimeout) {
689        this.sendTimeout = sendTimeout;
690    }
691
692    /**
693     * @return the sendAcksAsync
694     */
695    public boolean isSendAcksAsync() {
696        return sendAcksAsync;
697    }
698
699    /**
700     * @param sendAcksAsync the sendAcksAsync to set
701     */
702    public void setSendAcksAsync(boolean sendAcksAsync) {
703        this.sendAcksAsync = sendAcksAsync;
704    }
705
706    /**
707     * @return the messagePrioritySupported
708     */
709    public boolean isMessagePrioritySupported() {
710        return this.messagePrioritySupported;
711    }
712
713    /**
714     * @param messagePrioritySupported the messagePrioritySupported to set
715     */
716    public void setMessagePrioritySupported(boolean messagePrioritySupported) {
717        this.messagePrioritySupported = messagePrioritySupported;
718    }
719
720
721    /**
722     * Sets the transformer used to transform messages before they are sent on
723     * to the JMS bus or when they are received from the bus but before they are
724     * delivered to the JMS client
725     */
726    public void setTransformer(MessageTransformer transformer) {
727        this.transformer = transformer;
728    }
729
730    @SuppressWarnings({ "unchecked", "rawtypes" })
731    @Override
732    public void buildFromProperties(Properties properties) {
733
734        if (properties == null) {
735            properties = new Properties();
736        }
737
738        String temp = properties.getProperty(Context.PROVIDER_URL);
739        if (temp == null || temp.length() == 0) {
740            temp = properties.getProperty("brokerURL");
741        }
742        if (temp != null && temp.length() > 0) {
743            setBrokerURL(temp);
744        }
745
746        Map<String, Object> p = new HashMap(properties);
747        buildFromMap(p);
748    }
749
750    public boolean buildFromMap(Map<String, Object> properties) {
751        boolean rc = false;
752
753        ActiveMQPrefetchPolicy p = new ActiveMQPrefetchPolicy();
754        if (IntrospectionSupport.setProperties(p, properties, "prefetchPolicy.")) {
755            setPrefetchPolicy(p);
756            rc = true;
757        }
758
759        RedeliveryPolicy rp = new RedeliveryPolicy();
760        if (IntrospectionSupport.setProperties(rp, properties, "redeliveryPolicy.")) {
761            setRedeliveryPolicy(rp);
762            rc = true;
763        }
764
765        BlobTransferPolicy blobTransferPolicy = new BlobTransferPolicy();
766        if (IntrospectionSupport.setProperties(blobTransferPolicy, properties, "blobTransferPolicy.")) {
767            setBlobTransferPolicy(blobTransferPolicy);
768            rc = true;
769        }
770
771        rc |= IntrospectionSupport.setProperties(this, properties);
772
773        return rc;
774    }
775
776    @Override
777    public void populateProperties(Properties props) {
778        props.setProperty("dispatchAsync", Boolean.toString(isDispatchAsync()));
779
780        if (getBrokerURL() != null) {
781            props.setProperty(Context.PROVIDER_URL, getBrokerURL());
782            props.setProperty("brokerURL", getBrokerURL());
783        }
784
785        if (getClientID() != null) {
786            props.setProperty("clientID", getClientID());
787        }
788
789        IntrospectionSupport.getProperties(getPrefetchPolicy(), props, "prefetchPolicy.");
790        IntrospectionSupport.getProperties(getRedeliveryPolicy(), props, "redeliveryPolicy.");
791        IntrospectionSupport.getProperties(getBlobTransferPolicy(), props, "blobTransferPolicy.");
792
793        props.setProperty("copyMessageOnSend", Boolean.toString(isCopyMessageOnSend()));
794        props.setProperty("disableTimeStampsByDefault", Boolean.toString(isDisableTimeStampsByDefault()));
795        props.setProperty("objectMessageSerializationDefered", Boolean.toString(isObjectMessageSerializationDefered()));
796        props.setProperty("optimizedMessageDispatch", Boolean.toString(isOptimizedMessageDispatch()));
797
798        if (getPassword() != null) {
799            props.setProperty("password", getPassword());
800        }
801
802        props.setProperty("useAsyncSend", Boolean.toString(isUseAsyncSend()));
803        props.setProperty("useCompression", Boolean.toString(isUseCompression()));
804        props.setProperty("useRetroactiveConsumer", Boolean.toString(isUseRetroactiveConsumer()));
805        props.setProperty("watchTopicAdvisories", Boolean.toString(isWatchTopicAdvisories()));
806
807        if (getUserName() != null) {
808            props.setProperty("userName", getUserName());
809        }
810
811        props.setProperty("closeTimeout", Integer.toString(getCloseTimeout()));
812        props.setProperty("alwaysSessionAsync", Boolean.toString(isAlwaysSessionAsync()));
813        props.setProperty("optimizeAcknowledge", Boolean.toString(isOptimizeAcknowledge()));
814        props.setProperty("statsEnabled", Boolean.toString(isStatsEnabled()));
815        props.setProperty("alwaysSyncSend", Boolean.toString(isAlwaysSyncSend()));
816        props.setProperty("producerWindowSize", Integer.toString(getProducerWindowSize()));
817        props.setProperty("sendTimeout", Integer.toString(getSendTimeout()));
818        props.setProperty("sendAcksAsync",Boolean.toString(isSendAcksAsync()));
819        props.setProperty("auditDepth", Integer.toString(getAuditDepth()));
820        props.setProperty("auditMaximumProducerNumber", Integer.toString(getAuditMaximumProducerNumber()));
821        props.setProperty("checkForDuplicates", Boolean.toString(isCheckForDuplicates()));
822        props.setProperty("messagePrioritySupported", Boolean.toString(isMessagePrioritySupported()));
823        props.setProperty("transactedIndividualAck", Boolean.toString(isTransactedIndividualAck()));
824        props.setProperty("nonBlockingRedelivery", Boolean.toString(isNonBlockingRedelivery()));
825        props.setProperty("maxThreadPoolSize", Integer.toString(getMaxThreadPoolSize()));
826        props.setProperty("nestedMapAndListEnabled", Boolean.toString(isNestedMapAndListEnabled()));
827        props.setProperty("consumerFailoverRedeliveryWaitPeriod", Long.toString(getConsumerFailoverRedeliveryWaitPeriod()));
828        props.setProperty("rmIdFromConnectionId", Boolean.toString(isRmIdFromConnectionId()));
829        props.setProperty("consumerExpiryCheckEnabled", Boolean.toString(isConsumerExpiryCheckEnabled()));
830    }
831
832    public boolean isUseCompression() {
833        return useCompression;
834    }
835
836    /**
837     * Enables the use of compression of the message bodies
838     */
839    public void setUseCompression(boolean useCompression) {
840        this.useCompression = useCompression;
841    }
842
843    public boolean isObjectMessageSerializationDefered() {
844        return objectMessageSerializationDefered;
845    }
846
847    /**
848     * When an object is set on an ObjectMessage, the JMS spec requires the
849     * object to be serialized by that set method. Enabling this flag causes the
850     * object to not get serialized. The object may subsequently get serialized
851     * if the message needs to be sent over a socket or stored to disk.
852     */
853    public void setObjectMessageSerializationDefered(boolean objectMessageSerializationDefered) {
854        this.objectMessageSerializationDefered = objectMessageSerializationDefered;
855    }
856
857    public boolean isDispatchAsync() {
858        return dispatchAsync;
859    }
860
861    /**
862     * Enables or disables the default setting of whether or not consumers have
863     * their messages <a
864     * href="http://activemq.apache.org/consumer-dispatch-async.html">dispatched
865     * synchronously or asynchronously by the broker</a>. For non-durable
866     * topics for example we typically dispatch synchronously by default to
867     * minimize context switches which boost performance. However sometimes its
868     * better to go slower to ensure that a single blocked consumer socket does
869     * not block delivery to other consumers.
870     *
871     * @param asyncDispatch If true then consumers created on this connection
872     *                will default to having their messages dispatched
873     *                asynchronously. The default value is true.
874     */
875    public void setDispatchAsync(boolean asyncDispatch) {
876        this.dispatchAsync = asyncDispatch;
877    }
878
879    /**
880     * @return Returns the closeTimeout.
881     */
882    public int getCloseTimeout() {
883        return closeTimeout;
884    }
885
886    /**
887     * Sets the timeout before a close is considered complete. Normally a
888     * close() on a connection waits for confirmation from the broker; this
889     * allows that operation to timeout to save the client hanging if there is
890     * no broker
891     */
892    public void setCloseTimeout(int closeTimeout) {
893        this.closeTimeout = closeTimeout;
894    }
895
896    /**
897     * @return Returns the alwaysSessionAsync.
898     */
899    public boolean isAlwaysSessionAsync() {
900        return alwaysSessionAsync;
901    }
902
903    /**
904     * If this flag is not set then a separate thread is not used for dispatching messages for each Session in
905     * the Connection. However, a separate thread is always used if there is more than one session, or the session
906     * isn't in auto acknowledge or duplicates ok mode.  By default this value is set to true and session dispatch
907     * happens asynchronously.
908     */
909    public void setAlwaysSessionAsync(boolean alwaysSessionAsync) {
910        this.alwaysSessionAsync = alwaysSessionAsync;
911    }
912
913    /**
914     * @return Returns the optimizeAcknowledge.
915     */
916    public boolean isOptimizeAcknowledge() {
917        return optimizeAcknowledge;
918    }
919
920    /**
921     * @param optimizeAcknowledge The optimizeAcknowledge to set.
922     */
923    public void setOptimizeAcknowledge(boolean optimizeAcknowledge) {
924        this.optimizeAcknowledge = optimizeAcknowledge;
925    }
926
927    /**
928     * The max time in milliseconds between optimized ack batches
929     * @param optimizeAcknowledgeTimeOut
930     */
931    public void setOptimizeAcknowledgeTimeOut(long optimizeAcknowledgeTimeOut) {
932        this.optimizeAcknowledgeTimeOut =  optimizeAcknowledgeTimeOut;
933    }
934
935    public long getOptimizeAcknowledgeTimeOut() {
936        return optimizeAcknowledgeTimeOut;
937    }
938
939    public boolean isNestedMapAndListEnabled() {
940        return nestedMapAndListEnabled;
941    }
942
943    /**
944     * Enables/disables whether or not Message properties and MapMessage entries
945     * support <a
946     * href="http://activemq.apache.org/structured-message-properties-and-mapmessages.html">Nested
947     * Structures</a> of Map and List objects
948     */
949    public void setNestedMapAndListEnabled(boolean structuredMapsEnabled) {
950        this.nestedMapAndListEnabled = structuredMapsEnabled;
951    }
952
953    public String getClientIDPrefix() {
954        return clientIDPrefix;
955    }
956
957    /**
958     * Sets the prefix used by autogenerated JMS Client ID values which are used
959     * if the JMS client does not explicitly specify on.
960     *
961     * @param clientIDPrefix
962     */
963    public void setClientIDPrefix(String clientIDPrefix) {
964        this.clientIDPrefix = clientIDPrefix;
965    }
966
967    protected synchronized IdGenerator getClientIdGenerator() {
968        if (clientIdGenerator == null) {
969            if (clientIDPrefix != null) {
970                clientIdGenerator = new IdGenerator(clientIDPrefix);
971            } else {
972                clientIdGenerator = new IdGenerator();
973            }
974        }
975        return clientIdGenerator;
976    }
977
978    protected void setClientIdGenerator(IdGenerator clientIdGenerator) {
979        this.clientIdGenerator = clientIdGenerator;
980    }
981
982    /**
983     * Sets the prefix used by connection id generator
984     * @param connectionIDPrefix
985     */
986    public void setConnectionIDPrefix(String connectionIDPrefix) {
987        this.connectionIDPrefix = connectionIDPrefix;
988    }
989
990    protected synchronized IdGenerator getConnectionIdGenerator() {
991        if (connectionIdGenerator == null) {
992            if (connectionIDPrefix != null) {
993                connectionIdGenerator = new IdGenerator(connectionIDPrefix);
994            } else {
995                connectionIdGenerator = new IdGenerator();
996            }
997        }
998        return connectionIdGenerator;
999    }
1000
1001    protected void setConnectionIdGenerator(IdGenerator connectionIdGenerator) {
1002        this.connectionIdGenerator = connectionIdGenerator;
1003    }
1004
1005    /**
1006     * @return the statsEnabled
1007     */
1008    public boolean isStatsEnabled() {
1009        return this.factoryStats.isEnabled();
1010    }
1011
1012    /**
1013     * @param statsEnabled the statsEnabled to set
1014     */
1015    public void setStatsEnabled(boolean statsEnabled) {
1016        this.factoryStats.setEnabled(statsEnabled);
1017    }
1018
1019    public synchronized int getProducerWindowSize() {
1020        return producerWindowSize;
1021    }
1022
1023    public synchronized void setProducerWindowSize(int producerWindowSize) {
1024        this.producerWindowSize = producerWindowSize;
1025    }
1026
1027    public long getWarnAboutUnstartedConnectionTimeout() {
1028        return warnAboutUnstartedConnectionTimeout;
1029    }
1030
1031    /**
1032     * Enables the timeout from a connection creation to when a warning is
1033     * generated if the connection is not properly started via
1034     * {@link Connection#start()} and a message is received by a consumer. It is
1035     * a very common gotcha to forget to <a
1036     * href="http://activemq.apache.org/i-am-not-receiving-any-messages-what-is-wrong.html">start
1037     * the connection</a> so this option makes the default case to create a
1038     * warning if the user forgets. To disable the warning just set the value to <
1039     * 0 (say -1).
1040     */
1041    public void setWarnAboutUnstartedConnectionTimeout(long warnAboutUnstartedConnectionTimeout) {
1042        this.warnAboutUnstartedConnectionTimeout = warnAboutUnstartedConnectionTimeout;
1043    }
1044
1045    public TransportListener getTransportListener() {
1046        return transportListener;
1047    }
1048
1049    /**
1050     * Allows a listener to be configured on the ConnectionFactory so that when this factory is used
1051     * with frameworks which don't expose the Connection such as Spring JmsTemplate, you can still register
1052     * a transport listener.
1053     *
1054     * @param transportListener sets the listener to be registered on all connections
1055     * created by this factory
1056     */
1057    public void setTransportListener(TransportListener transportListener) {
1058        this.transportListener = transportListener;
1059    }
1060
1061
1062    public ExceptionListener getExceptionListener() {
1063        return exceptionListener;
1064    }
1065
1066    /**
1067     * Allows an {@link ExceptionListener} to be configured on the ConnectionFactory so that when this factory
1068     * is used by frameworks which don't expose the Connection such as Spring JmsTemplate, you can register
1069     * an exception listener.
1070     * <p> Note: access to this exceptionLinstener will <b>not</b> be serialized if it is associated with more than
1071     * on connection (as it will be if more than one connection is subsequently created by this connection factory)
1072     * @param exceptionListener sets the exception listener to be registered on all connections
1073     * created by this factory
1074     */
1075    public void setExceptionListener(ExceptionListener exceptionListener) {
1076        this.exceptionListener = exceptionListener;
1077    }
1078
1079    public int getAuditDepth() {
1080        return auditDepth;
1081    }
1082
1083    public void setAuditDepth(int auditDepth) {
1084        this.auditDepth = auditDepth;
1085    }
1086
1087    public int getAuditMaximumProducerNumber() {
1088        return auditMaximumProducerNumber;
1089    }
1090
1091    public void setAuditMaximumProducerNumber(int auditMaximumProducerNumber) {
1092        this.auditMaximumProducerNumber = auditMaximumProducerNumber;
1093    }
1094
1095    public void setUseDedicatedTaskRunner(boolean useDedicatedTaskRunner) {
1096        this.useDedicatedTaskRunner = useDedicatedTaskRunner;
1097    }
1098
1099    public boolean isUseDedicatedTaskRunner() {
1100        return useDedicatedTaskRunner;
1101    }
1102
1103    public void setConsumerFailoverRedeliveryWaitPeriod(long consumerFailoverRedeliveryWaitPeriod) {
1104        this.consumerFailoverRedeliveryWaitPeriod = consumerFailoverRedeliveryWaitPeriod;
1105    }
1106
1107    public long getConsumerFailoverRedeliveryWaitPeriod() {
1108        return consumerFailoverRedeliveryWaitPeriod;
1109    }
1110
1111    public ClientInternalExceptionListener getClientInternalExceptionListener() {
1112        return clientInternalExceptionListener;
1113    }
1114
1115    /**
1116     * Allows an {@link ClientInternalExceptionListener} to be configured on the ConnectionFactory so that when this factory
1117     * is used by frameworks which don't expose the Connection such as Spring JmsTemplate, you can register
1118     * an exception listener.
1119     * <p> Note: access to this clientInternalExceptionListener will <b>not</b> be serialized if it is associated with more than
1120     * on connection (as it will be if more than one connection is subsequently created by this connection factory)
1121     * @param clientInternalExceptionListener sets the exception listener to be registered on all connections
1122     * created by this factory
1123     */
1124    public void setClientInternalExceptionListener(
1125            ClientInternalExceptionListener clientInternalExceptionListener) {
1126        this.clientInternalExceptionListener = clientInternalExceptionListener;
1127    }
1128
1129    /**
1130     * @return the checkForDuplicates
1131     */
1132    public boolean isCheckForDuplicates() {
1133        return this.checkForDuplicates;
1134    }
1135
1136    /**
1137     * @param checkForDuplicates the checkForDuplicates to set
1138     */
1139    public void setCheckForDuplicates(boolean checkForDuplicates) {
1140        this.checkForDuplicates = checkForDuplicates;
1141    }
1142
1143    public boolean isTransactedIndividualAck() {
1144         return transactedIndividualAck;
1145     }
1146
1147     /**
1148      * when true, submit individual transacted acks immediately rather than with transaction completion.
1149      * This allows the acks to represent delivery status which can be persisted on rollback
1150      * Used in conjunction with org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter#setRewriteOnRedelivery(boolean)  true
1151      */
1152     public void setTransactedIndividualAck(boolean transactedIndividualAck) {
1153         this.transactedIndividualAck = transactedIndividualAck;
1154     }
1155
1156
1157     public boolean isNonBlockingRedelivery() {
1158         return nonBlockingRedelivery;
1159     }
1160
1161     /**
1162      * When true a MessageConsumer will not stop Message delivery before re-delivering Messages
1163      * from a rolled back transaction.  This implies that message order will not be preserved and
1164      * also will result in the TransactedIndividualAck option to be enabled.
1165      */
1166     public void setNonBlockingRedelivery(boolean nonBlockingRedelivery) {
1167         this.nonBlockingRedelivery = nonBlockingRedelivery;
1168     }
1169
1170    public int getMaxThreadPoolSize() {
1171        return maxThreadPoolSize;
1172    }
1173
1174    public void setMaxThreadPoolSize(int maxThreadPoolSize) {
1175        this.maxThreadPoolSize = maxThreadPoolSize;
1176    }
1177
1178    public TaskRunnerFactory getSessionTaskRunner() {
1179        return sessionTaskRunner;
1180    }
1181
1182    public void setSessionTaskRunner(TaskRunnerFactory sessionTaskRunner) {
1183        this.sessionTaskRunner = sessionTaskRunner;
1184    }
1185
1186    public RejectedExecutionHandler getRejectedTaskHandler() {
1187        return rejectedTaskHandler;
1188    }
1189
1190    public void setRejectedTaskHandler(RejectedExecutionHandler rejectedTaskHandler) {
1191        this.rejectedTaskHandler = rejectedTaskHandler;
1192    }
1193
1194    /**
1195     * Gets the configured time interval that is used to force all MessageConsumers that have optimizedAcknowledge enabled
1196     * to send an ack for any outstanding Message Acks.  By default this value is set to zero meaning that the consumers
1197     * will not do any background Message acknowledgment.
1198     *
1199     * @return the scheduledOptimizedAckInterval
1200     */
1201    public long getOptimizedAckScheduledAckInterval() {
1202        return optimizedAckScheduledAckInterval;
1203    }
1204
1205    /**
1206     * Sets the amount of time between scheduled sends of any outstanding Message Acks for consumers that
1207     * have been configured with optimizeAcknowledge enabled.
1208     *
1209     * @param optimizedAckScheduledAckInterval the scheduledOptimizedAckInterval to set
1210     */
1211    public void setOptimizedAckScheduledAckInterval(long optimizedAckScheduledAckInterval) {
1212        this.optimizedAckScheduledAckInterval = optimizedAckScheduledAckInterval;
1213    }
1214
1215
1216    public boolean isRmIdFromConnectionId() {
1217        return rmIdFromConnectionId;
1218    }
1219
1220    /**
1221     * uses the connection id as the resource identity for XAResource.isSameRM
1222     * ensuring join will only occur on a single connection
1223     */
1224    public void setRmIdFromConnectionId(boolean rmIdFromConnectionId) {
1225        this.rmIdFromConnectionId = rmIdFromConnectionId;
1226    }
1227
1228    /**
1229     * @return true if MessageConsumer instance will check for expired messages before dispatch.
1230     */
1231    public boolean isConsumerExpiryCheckEnabled() {
1232        return consumerExpiryCheckEnabled;
1233    }
1234
1235    /**
1236     * Controls whether message expiration checking is done in each MessageConsumer
1237     * prior to dispatching a message.  Disabling this check can lead to consumption
1238     * of expired messages.
1239     *
1240     * @param consumerExpiryCheckEnabled
1241     *        controls whether expiration checking is done prior to dispatch.
1242     */
1243    public void setConsumerExpiryCheckEnabled(boolean consumerExpiryCheckEnabled) {
1244        this.consumerExpiryCheckEnabled = consumerExpiryCheckEnabled;
1245    }
1246
1247    public List<String> getTrustedPackages() {
1248        return trustedPackages;
1249    }
1250
1251    public void setTrustedPackages(List<String> trustedPackages) {
1252        this.trustedPackages = trustedPackages;
1253    }
1254
1255    public boolean isTrustAllPackages() {
1256        return trustAllPackages;
1257    }
1258
1259    public void setTrustAllPackages(boolean trustAllPackages) {
1260        this.trustAllPackages = trustAllPackages;
1261    }
1262}