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.broker;
018
019import java.io.BufferedReader;
020import java.io.File;
021import java.io.IOException;
022import java.io.InputStream;
023import java.io.InputStreamReader;
024import java.net.URI;
025import java.net.URISyntaxException;
026import java.net.UnknownHostException;
027import java.security.Provider;
028import java.security.Security;
029import java.util.ArrayList;
030import java.util.Date;
031import java.util.HashMap;
032import java.util.HashSet;
033import java.util.Iterator;
034import java.util.List;
035import java.util.Locale;
036import java.util.Map;
037import java.util.Set;
038import java.util.concurrent.CopyOnWriteArrayList;
039import java.util.concurrent.CountDownLatch;
040import java.util.concurrent.LinkedBlockingQueue;
041import java.util.concurrent.RejectedExecutionException;
042import java.util.concurrent.RejectedExecutionHandler;
043import java.util.concurrent.SynchronousQueue;
044import java.util.concurrent.ThreadFactory;
045import java.util.concurrent.ThreadPoolExecutor;
046import java.util.concurrent.TimeUnit;
047import java.util.concurrent.atomic.AtomicBoolean;
048import java.util.concurrent.atomic.AtomicInteger;
049import java.util.concurrent.atomic.AtomicLong;
050
051import javax.annotation.PostConstruct;
052import javax.annotation.PreDestroy;
053import javax.management.MalformedObjectNameException;
054import javax.management.ObjectName;
055
056import org.apache.activemq.ActiveMQConnectionMetaData;
057import org.apache.activemq.ConfigurationException;
058import org.apache.activemq.Service;
059import org.apache.activemq.advisory.AdvisoryBroker;
060import org.apache.activemq.broker.cluster.ConnectionSplitBroker;
061import org.apache.activemq.broker.jmx.AnnotatedMBean;
062import org.apache.activemq.broker.jmx.BrokerMBeanSupport;
063import org.apache.activemq.broker.jmx.BrokerView;
064import org.apache.activemq.broker.jmx.ConnectorView;
065import org.apache.activemq.broker.jmx.ConnectorViewMBean;
066import org.apache.activemq.broker.jmx.HealthView;
067import org.apache.activemq.broker.jmx.HealthViewMBean;
068import org.apache.activemq.broker.jmx.JmsConnectorView;
069import org.apache.activemq.broker.jmx.JobSchedulerView;
070import org.apache.activemq.broker.jmx.JobSchedulerViewMBean;
071import org.apache.activemq.broker.jmx.Log4JConfigView;
072import org.apache.activemq.broker.jmx.ManagedRegionBroker;
073import org.apache.activemq.broker.jmx.ManagementContext;
074import org.apache.activemq.broker.jmx.NetworkConnectorView;
075import org.apache.activemq.broker.jmx.NetworkConnectorViewMBean;
076import org.apache.activemq.broker.jmx.ProxyConnectorView;
077import org.apache.activemq.broker.region.CompositeDestinationInterceptor;
078import org.apache.activemq.broker.region.Destination;
079import org.apache.activemq.broker.region.DestinationFactory;
080import org.apache.activemq.broker.region.DestinationFactoryImpl;
081import org.apache.activemq.broker.region.DestinationInterceptor;
082import org.apache.activemq.broker.region.RegionBroker;
083import org.apache.activemq.broker.region.policy.PolicyMap;
084import org.apache.activemq.broker.region.virtual.MirroredQueue;
085import org.apache.activemq.broker.region.virtual.VirtualDestination;
086import org.apache.activemq.broker.region.virtual.VirtualDestinationInterceptor;
087import org.apache.activemq.broker.region.virtual.VirtualTopic;
088import org.apache.activemq.broker.scheduler.JobSchedulerStore;
089import org.apache.activemq.broker.scheduler.SchedulerBroker;
090import org.apache.activemq.broker.scheduler.memory.InMemoryJobSchedulerStore;
091import org.apache.activemq.command.ActiveMQDestination;
092import org.apache.activemq.command.ActiveMQQueue;
093import org.apache.activemq.command.BrokerId;
094import org.apache.activemq.command.ProducerInfo;
095import org.apache.activemq.filter.DestinationFilter;
096import org.apache.activemq.network.ConnectionFilter;
097import org.apache.activemq.network.DiscoveryNetworkConnector;
098import org.apache.activemq.network.NetworkConnector;
099import org.apache.activemq.network.jms.JmsConnector;
100import org.apache.activemq.openwire.OpenWireFormat;
101import org.apache.activemq.proxy.ProxyConnector;
102import org.apache.activemq.security.MessageAuthorizationPolicy;
103import org.apache.activemq.selector.SelectorParser;
104import org.apache.activemq.store.JournaledStore;
105import org.apache.activemq.store.PListStore;
106import org.apache.activemq.store.PersistenceAdapter;
107import org.apache.activemq.store.PersistenceAdapterFactory;
108import org.apache.activemq.store.memory.MemoryPersistenceAdapter;
109import org.apache.activemq.thread.Scheduler;
110import org.apache.activemq.thread.TaskRunnerFactory;
111import org.apache.activemq.transport.TransportFactorySupport;
112import org.apache.activemq.transport.TransportServer;
113import org.apache.activemq.transport.vm.VMTransportFactory;
114import org.apache.activemq.usage.SystemUsage;
115import org.apache.activemq.util.BrokerSupport;
116import org.apache.activemq.util.DefaultIOExceptionHandler;
117import org.apache.activemq.util.IOExceptionHandler;
118import org.apache.activemq.util.IOExceptionSupport;
119import org.apache.activemq.util.IOHelper;
120import org.apache.activemq.util.InetAddressUtil;
121import org.apache.activemq.util.ServiceStopper;
122import org.apache.activemq.util.ThreadPoolUtils;
123import org.apache.activemq.util.TimeUtils;
124import org.apache.activemq.util.URISupport;
125import org.slf4j.Logger;
126import org.slf4j.LoggerFactory;
127import org.slf4j.MDC;
128
129/**
130 * Manages the life-cycle of an ActiveMQ Broker. A BrokerService consists of a
131 * number of transport connectors, network connectors and a bunch of properties
132 * which can be used to configure the broker as its lazily created.
133 *
134 * @org.apache.xbean.XBean
135 */
136public class BrokerService implements Service {
137    public static final String DEFAULT_PORT = "61616";
138    public static final String LOCAL_HOST_NAME;
139    public static final String BROKER_VERSION;
140    public static final String DEFAULT_BROKER_NAME = "localhost";
141    public static final int DEFAULT_MAX_FILE_LENGTH = 1024 * 1024 * 32;
142    public static final long DEFAULT_START_TIMEOUT = 600000L;
143
144    private static final Logger LOG = LoggerFactory.getLogger(BrokerService.class);
145
146    @SuppressWarnings("unused")
147    private static final long serialVersionUID = 7353129142305630237L;
148
149    private boolean useJmx = true;
150    private boolean enableStatistics = true;
151    private boolean persistent = true;
152    private boolean populateJMSXUserID;
153    private boolean useAuthenticatedPrincipalForJMSXUserID;
154    private boolean populateUserNameInMBeans;
155    private long mbeanInvocationTimeout = 0;
156
157    private boolean useShutdownHook = true;
158    private boolean useLoggingForShutdownErrors;
159    private boolean shutdownOnMasterFailure;
160    private boolean shutdownOnSlaveFailure;
161    private boolean waitForSlave;
162    private long waitForSlaveTimeout = DEFAULT_START_TIMEOUT;
163    private boolean passiveSlave;
164    private String brokerName = DEFAULT_BROKER_NAME;
165    private File dataDirectoryFile;
166    private File tmpDataDirectory;
167    private Broker broker;
168    private BrokerView adminView;
169    private ManagementContext managementContext;
170    private ObjectName brokerObjectName;
171    private TaskRunnerFactory taskRunnerFactory;
172    private TaskRunnerFactory persistenceTaskRunnerFactory;
173    private SystemUsage systemUsage;
174    private SystemUsage producerSystemUsage;
175    private SystemUsage consumerSystemUsaage;
176    private PersistenceAdapter persistenceAdapter;
177    private PersistenceAdapterFactory persistenceFactory;
178    protected DestinationFactory destinationFactory;
179    private MessageAuthorizationPolicy messageAuthorizationPolicy;
180    private final List<TransportConnector> transportConnectors = new CopyOnWriteArrayList<TransportConnector>();
181    private final List<NetworkConnector> networkConnectors = new CopyOnWriteArrayList<NetworkConnector>();
182    private final List<ProxyConnector> proxyConnectors = new CopyOnWriteArrayList<ProxyConnector>();
183    private final List<JmsConnector> jmsConnectors = new CopyOnWriteArrayList<JmsConnector>();
184    private final List<Service> services = new ArrayList<Service>();
185    private transient Thread shutdownHook;
186    private String[] transportConnectorURIs;
187    private String[] networkConnectorURIs;
188    private JmsConnector[] jmsBridgeConnectors; // these are Jms to Jms bridges
189    // to other jms messaging systems
190    private boolean deleteAllMessagesOnStartup;
191    private boolean advisorySupport = true;
192    private URI vmConnectorURI;
193    private String defaultSocketURIString;
194    private PolicyMap destinationPolicy;
195    private final AtomicBoolean started = new AtomicBoolean(false);
196    private final AtomicBoolean stopped = new AtomicBoolean(false);
197    private final AtomicBoolean stopping = new AtomicBoolean(false);
198    private BrokerPlugin[] plugins;
199    private boolean keepDurableSubsActive = true;
200    private boolean useVirtualTopics = true;
201    private boolean useMirroredQueues = false;
202    private boolean useTempMirroredQueues = true;
203    private BrokerId brokerId;
204    private volatile DestinationInterceptor[] destinationInterceptors;
205    private ActiveMQDestination[] destinations;
206    private PListStore tempDataStore;
207    private int persistenceThreadPriority = Thread.MAX_PRIORITY;
208    private boolean useLocalHostBrokerName;
209    private final CountDownLatch stoppedLatch = new CountDownLatch(1);
210    private final CountDownLatch startedLatch = new CountDownLatch(1);
211    private Broker regionBroker;
212    private int producerSystemUsagePortion = 60;
213    private int consumerSystemUsagePortion = 40;
214    private boolean splitSystemUsageForProducersConsumers;
215    private boolean monitorConnectionSplits = false;
216    private int taskRunnerPriority = Thread.NORM_PRIORITY;
217    private boolean dedicatedTaskRunner;
218    private boolean cacheTempDestinations = false;// useful for failover
219    private int timeBeforePurgeTempDestinations = 5000;
220    private final List<Runnable> shutdownHooks = new ArrayList<Runnable>();
221    private boolean systemExitOnShutdown;
222    private int systemExitOnShutdownExitCode;
223    private SslContext sslContext;
224    private boolean forceStart = false;
225    private IOExceptionHandler ioExceptionHandler;
226    private boolean schedulerSupport = false;
227    private File schedulerDirectoryFile;
228    private Scheduler scheduler;
229    private ThreadPoolExecutor executor;
230    private int schedulePeriodForDestinationPurge= 0;
231    private int maxPurgedDestinationsPerSweep = 0;
232    private BrokerContext brokerContext;
233    private boolean networkConnectorStartAsync = false;
234    private boolean allowTempAutoCreationOnSend;
235    private JobSchedulerStore jobSchedulerStore;
236    private final AtomicLong totalConnections = new AtomicLong();
237    private final AtomicInteger currentConnections = new AtomicInteger();
238
239    private long offlineDurableSubscriberTimeout = -1;
240    private long offlineDurableSubscriberTaskSchedule = 300000;
241    private DestinationFilter virtualConsumerDestinationFilter;
242
243    private final Object persistenceAdapterLock = new Object();
244    private Throwable startException = null;
245    private boolean startAsync = false;
246    private Date startDate;
247    private boolean slave = true;
248
249    private boolean restartAllowed = true;
250    private boolean restartRequested = false;
251    private boolean rejectDurableConsumers = false;
252    private boolean rollbackOnlyOnAsyncException = true;
253
254    private int storeOpenWireVersion = OpenWireFormat.DEFAULT_VERSION;
255
256    static {
257
258        try {
259            ClassLoader loader = BrokerService.class.getClassLoader();
260            Class<?> clazz = loader.loadClass("org.bouncycastle.jce.provider.BouncyCastleProvider");
261            Provider bouncycastle = (Provider) clazz.newInstance();
262            Security.insertProviderAt(bouncycastle, 2);
263            LOG.info("Loaded the Bouncy Castle security provider.");
264        } catch(Throwable e) {
265            // No BouncyCastle found so we use the default Java Security Provider
266        }
267
268        String localHostName = "localhost";
269        try {
270            localHostName =  InetAddressUtil.getLocalHostName();
271        } catch (UnknownHostException e) {
272            LOG.error("Failed to resolve localhost");
273        }
274        LOCAL_HOST_NAME = localHostName;
275
276        InputStream in = null;
277        String version = null;
278        if ((in = BrokerService.class.getResourceAsStream("/org/apache/activemq/version.txt")) != null) {
279            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
280            try {
281                version = reader.readLine();
282            } catch(Exception e) {
283            }
284        }
285        BROKER_VERSION = version;
286    }
287
288    @Override
289    public String toString() {
290        return "BrokerService[" + getBrokerName() + "]";
291    }
292
293    private String getBrokerVersion() {
294        String version = ActiveMQConnectionMetaData.PROVIDER_VERSION;
295        if (version == null) {
296            version = BROKER_VERSION;
297        }
298
299        return version;
300    }
301
302    /**
303     * Adds a new transport connector for the given bind address
304     *
305     * @return the newly created and added transport connector
306     * @throws Exception
307     */
308    public TransportConnector addConnector(String bindAddress) throws Exception {
309        return addConnector(new URI(bindAddress));
310    }
311
312    /**
313     * Adds a new transport connector for the given bind address
314     *
315     * @return the newly created and added transport connector
316     * @throws Exception
317     */
318    public TransportConnector addConnector(URI bindAddress) throws Exception {
319        return addConnector(createTransportConnector(bindAddress));
320    }
321
322    /**
323     * Adds a new transport connector for the given TransportServer transport
324     *
325     * @return the newly created and added transport connector
326     * @throws Exception
327     */
328    public TransportConnector addConnector(TransportServer transport) throws Exception {
329        return addConnector(new TransportConnector(transport));
330    }
331
332    /**
333     * Adds a new transport connector
334     *
335     * @return the transport connector
336     * @throws Exception
337     */
338    public TransportConnector addConnector(TransportConnector connector) throws Exception {
339        transportConnectors.add(connector);
340        return connector;
341    }
342
343    /**
344     * Stops and removes a transport connector from the broker.
345     *
346     * @param connector
347     * @return true if the connector has been previously added to the broker
348     * @throws Exception
349     */
350    public boolean removeConnector(TransportConnector connector) throws Exception {
351        boolean rc = transportConnectors.remove(connector);
352        if (rc) {
353            unregisterConnectorMBean(connector);
354        }
355        return rc;
356    }
357
358    /**
359     * Adds a new network connector using the given discovery address
360     *
361     * @return the newly created and added network connector
362     * @throws Exception
363     */
364    public NetworkConnector addNetworkConnector(String discoveryAddress) throws Exception {
365        return addNetworkConnector(new URI(discoveryAddress));
366    }
367
368    /**
369     * Adds a new proxy connector using the given bind address
370     *
371     * @return the newly created and added network connector
372     * @throws Exception
373     */
374    public ProxyConnector addProxyConnector(String bindAddress) throws Exception {
375        return addProxyConnector(new URI(bindAddress));
376    }
377
378    /**
379     * Adds a new network connector using the given discovery address
380     *
381     * @return the newly created and added network connector
382     * @throws Exception
383     */
384    public NetworkConnector addNetworkConnector(URI discoveryAddress) throws Exception {
385        NetworkConnector connector = new DiscoveryNetworkConnector(discoveryAddress);
386        return addNetworkConnector(connector);
387    }
388
389    /**
390     * Adds a new proxy connector using the given bind address
391     *
392     * @return the newly created and added network connector
393     * @throws Exception
394     */
395    public ProxyConnector addProxyConnector(URI bindAddress) throws Exception {
396        ProxyConnector connector = new ProxyConnector();
397        connector.setBind(bindAddress);
398        connector.setRemote(new URI("fanout:multicast://default"));
399        return addProxyConnector(connector);
400    }
401
402    /**
403     * Adds a new network connector to connect this broker to a federated
404     * network
405     */
406    public NetworkConnector addNetworkConnector(NetworkConnector connector) throws Exception {
407        connector.setBrokerService(this);
408        URI uri = getVmConnectorURI();
409        Map<String, String> map = new HashMap<String, String>(URISupport.parseParameters(uri));
410        map.put("network", "true");
411        uri = URISupport.createURIWithQuery(uri, URISupport.createQueryString(map));
412        connector.setLocalUri(uri);
413        // Set a connection filter so that the connector does not establish loop
414        // back connections.
415        connector.setConnectionFilter(new ConnectionFilter() {
416            @Override
417            public boolean connectTo(URI location) {
418                List<TransportConnector> transportConnectors = getTransportConnectors();
419                for (Iterator<TransportConnector> iter = transportConnectors.iterator(); iter.hasNext();) {
420                    try {
421                        TransportConnector tc = iter.next();
422                        if (location.equals(tc.getConnectUri())) {
423                            return false;
424                        }
425                    } catch (Throwable e) {
426                    }
427                }
428                return true;
429            }
430        });
431        networkConnectors.add(connector);
432        return connector;
433    }
434
435    /**
436     * Removes the given network connector without stopping it. The caller
437     * should call {@link NetworkConnector#stop()} to close the connector
438     */
439    public boolean removeNetworkConnector(NetworkConnector connector) {
440        boolean answer = networkConnectors.remove(connector);
441        if (answer) {
442            unregisterNetworkConnectorMBean(connector);
443        }
444        return answer;
445    }
446
447    public ProxyConnector addProxyConnector(ProxyConnector connector) throws Exception {
448        URI uri = getVmConnectorURI();
449        connector.setLocalUri(uri);
450        proxyConnectors.add(connector);
451        if (isUseJmx()) {
452            registerProxyConnectorMBean(connector);
453        }
454        return connector;
455    }
456
457    public JmsConnector addJmsConnector(JmsConnector connector) throws Exception {
458        connector.setBrokerService(this);
459        jmsConnectors.add(connector);
460        if (isUseJmx()) {
461            registerJmsConnectorMBean(connector);
462        }
463        return connector;
464    }
465
466    public JmsConnector removeJmsConnector(JmsConnector connector) {
467        if (jmsConnectors.remove(connector)) {
468            return connector;
469        }
470        return null;
471    }
472
473    public void masterFailed() {
474        if (shutdownOnMasterFailure) {
475            LOG.error("The Master has failed ... shutting down");
476            try {
477                stop();
478            } catch (Exception e) {
479                LOG.error("Failed to stop for master failure", e);
480            }
481        } else {
482            LOG.warn("Master Failed - starting all connectors");
483            try {
484                startAllConnectors();
485                broker.nowMasterBroker();
486            } catch (Exception e) {
487                LOG.error("Failed to startAllConnectors", e);
488            }
489        }
490    }
491
492    public String getUptime() {
493        long delta = getUptimeMillis();
494
495        if (delta == 0) {
496            return "not started";
497        }
498
499        return TimeUtils.printDuration(delta);
500    }
501
502    public long getUptimeMillis() {
503        if (startDate == null) {
504            return 0;
505        }
506
507        return new Date().getTime() - startDate.getTime();
508    }
509
510    public boolean isStarted() {
511        return started.get() && startedLatch.getCount() == 0;
512    }
513
514    /**
515     * Forces a start of the broker.
516     * By default a BrokerService instance that was
517     * previously stopped using BrokerService.stop() cannot be restarted
518     * using BrokerService.start().
519     * This method enforces a restart.
520     * It is not recommended to force a restart of the broker and will not work
521     * for most but some very trivial broker configurations.
522     * For restarting a broker instance we recommend to first call stop() on
523     * the old instance and then recreate a new BrokerService instance.
524     *
525     * @param force - if true enforces a restart.
526     * @throws Exception
527     */
528    public void start(boolean force) throws Exception {
529        forceStart = force;
530        stopped.set(false);
531        started.set(false);
532        start();
533    }
534
535    // Service interface
536    // -------------------------------------------------------------------------
537
538    protected boolean shouldAutostart() {
539        return true;
540    }
541
542    /**
543     * JSR-250 callback wrapper; converts checked exceptions to runtime exceptions
544     *
545     * delegates to autoStart, done to prevent backwards incompatible signature change
546     */
547    @PostConstruct
548    private void postConstruct() {
549        try {
550            autoStart();
551        } catch (Exception ex) {
552            throw new RuntimeException(ex);
553        }
554    }
555
556    /**
557     *
558     * @throws Exception
559     * @org. apache.xbean.InitMethod
560     */
561    public void autoStart() throws Exception {
562        if(shouldAutostart()) {
563            start();
564        }
565    }
566
567    @Override
568    public void start() throws Exception {
569        if (stopped.get() || !started.compareAndSet(false, true)) {
570            // lets just ignore redundant start() calls
571            // as its way too easy to not be completely sure if start() has been
572            // called or not with the gazillion of different configuration
573            // mechanisms
574            // throw new IllegalStateException("Already started.");
575            return;
576        }
577
578        setStartException(null);
579        stopping.set(false);
580        startDate = new Date();
581        MDC.put("activemq.broker", brokerName);
582
583        try {
584            if (systemExitOnShutdown && useShutdownHook) {
585                throw new ConfigurationException("'useShutdownHook' property cannot be be used with 'systemExitOnShutdown', please turn it off (useShutdownHook=false)");
586            }
587            processHelperProperties();
588            if (isUseJmx()) {
589                // need to remove MDC during starting JMX, as that would otherwise causes leaks, as spawned threads inheirt the MDC and
590                // we cannot cleanup clear that during shutdown of the broker.
591                MDC.remove("activemq.broker");
592                try {
593                    startManagementContext();
594                    for (NetworkConnector connector : getNetworkConnectors()) {
595                        registerNetworkConnectorMBean(connector);
596                    }
597                } finally {
598                    MDC.put("activemq.broker", brokerName);
599                }
600            }
601
602            // in jvm master slave, lets not publish over existing broker till we get the lock
603            final BrokerRegistry brokerRegistry = BrokerRegistry.getInstance();
604            if (brokerRegistry.lookup(getBrokerName()) == null) {
605                brokerRegistry.bind(getBrokerName(), BrokerService.this);
606            }
607            startPersistenceAdapter(startAsync);
608            startBroker(startAsync);
609            brokerRegistry.bind(getBrokerName(), BrokerService.this);
610        } catch (Exception e) {
611            LOG.error("Failed to start Apache ActiveMQ ({}, {})", new Object[]{ getBrokerName(), brokerId }, e);
612            try {
613                if (!stopped.get()) {
614                    stop();
615                }
616            } catch (Exception ex) {
617                LOG.warn("Failed to stop broker after failure in start. This exception will be ignored.", ex);
618            }
619            throw e;
620        } finally {
621            MDC.remove("activemq.broker");
622        }
623    }
624
625    private void startPersistenceAdapter(boolean async) throws Exception {
626        if (async) {
627            new Thread("Persistence Adapter Starting Thread") {
628                @Override
629                public void run() {
630                    try {
631                        doStartPersistenceAdapter();
632                    } catch (Throwable e) {
633                        setStartException(e);
634                    } finally {
635                        synchronized (persistenceAdapterLock) {
636                            persistenceAdapterLock.notifyAll();
637                        }
638                    }
639                }
640            }.start();
641        } else {
642            doStartPersistenceAdapter();
643        }
644    }
645
646    private void doStartPersistenceAdapter() throws Exception {
647        PersistenceAdapter persistenceAdapterToStart = getPersistenceAdapter();
648        if (persistenceAdapterToStart == null) {
649            checkStartException();
650            throw new ConfigurationException("Cannot start null persistence adapter");
651        }
652        persistenceAdapterToStart.setUsageManager(getProducerSystemUsage());
653        persistenceAdapterToStart.setBrokerName(getBrokerName());
654        LOG.info("Using Persistence Adapter: {}", persistenceAdapterToStart);
655        if (deleteAllMessagesOnStartup) {
656            deleteAllMessages();
657        }
658        persistenceAdapterToStart.start();
659
660        getJobSchedulerStore();
661        if (jobSchedulerStore != null) {
662            try {
663                jobSchedulerStore.start();
664            } catch (Exception e) {
665                RuntimeException exception = new RuntimeException(
666                        "Failed to start job scheduler store: " + jobSchedulerStore, e);
667                LOG.error(exception.getLocalizedMessage(), e);
668                throw exception;
669            }
670        }
671    }
672
673    private void startBroker(boolean async) throws Exception {
674        if (async) {
675            new Thread("Broker Starting Thread") {
676                @Override
677                public void run() {
678                    try {
679                        synchronized (persistenceAdapterLock) {
680                            persistenceAdapterLock.wait();
681                        }
682                        doStartBroker();
683                    } catch (Throwable t) {
684                        setStartException(t);
685                    }
686                }
687            }.start();
688        } else {
689            doStartBroker();
690        }
691    }
692
693    private void doStartBroker() throws Exception {
694        checkStartException();
695        startDestinations();
696        addShutdownHook();
697
698        broker = getBroker();
699        brokerId = broker.getBrokerId();
700
701        // need to log this after creating the broker so we have its id and name
702        LOG.info("Apache ActiveMQ {} ({}, {}) is starting", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId });
703        broker.start();
704
705        if (isUseJmx()) {
706            if (getManagementContext().isCreateConnector() && !getManagementContext().isConnectorStarted()) {
707                // try to restart management context
708                // typical for slaves that use the same ports as master
709                managementContext.stop();
710                startManagementContext();
711            }
712            ManagedRegionBroker managedBroker = (ManagedRegionBroker) regionBroker;
713            managedBroker.setContextBroker(broker);
714            adminView.setBroker(managedBroker);
715        }
716
717        if (ioExceptionHandler == null) {
718            setIoExceptionHandler(new DefaultIOExceptionHandler());
719        }
720
721        if (isUseJmx() && Log4JConfigView.isLog4JAvailable()) {
722            ObjectName objectName = BrokerMBeanSupport.createLog4JConfigViewName(getBrokerObjectName().toString());
723            Log4JConfigView log4jConfigView = new Log4JConfigView();
724            AnnotatedMBean.registerMBean(getManagementContext(), log4jConfigView, objectName);
725        }
726
727        startAllConnectors();
728
729        LOG.info("Apache ActiveMQ {} ({}, {}) started", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId});
730        LOG.info("For help or more information please see: http://activemq.apache.org");
731
732        getBroker().brokerServiceStarted();
733        checkSystemUsageLimits();
734        startedLatch.countDown();
735        getBroker().nowMasterBroker();
736    }
737
738    /**
739     * JSR-250 callback wrapper; converts checked exceptions to runtime exceptions
740     *
741     * delegates to stop, done to prevent backwards incompatible signature change
742     */
743    @PreDestroy
744    private void preDestroy () {
745        try {
746            stop();
747        } catch (Exception ex) {
748            throw new RuntimeException();
749        }
750    }
751
752    /**
753     *
754     * @throws Exception
755     * @org.apache .xbean.DestroyMethod
756     */
757    @Override
758    public void stop() throws Exception {
759        if (!stopping.compareAndSet(false, true)) {
760            LOG.trace("Broker already stopping/stopped");
761            return;
762        }
763
764        setStartException(new BrokerStoppedException("Stop invoked"));
765        MDC.put("activemq.broker", brokerName);
766
767        if (systemExitOnShutdown) {
768            new Thread() {
769                @Override
770                public void run() {
771                    System.exit(systemExitOnShutdownExitCode);
772                }
773            }.start();
774        }
775
776        LOG.info("Apache ActiveMQ {} ({}, {}) is shutting down", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId} );
777
778        removeShutdownHook();
779        if (this.scheduler != null) {
780            this.scheduler.stop();
781            this.scheduler = null;
782        }
783        ServiceStopper stopper = new ServiceStopper();
784        if (services != null) {
785            for (Service service : services) {
786                stopper.stop(service);
787            }
788        }
789        stopAllConnectors(stopper);
790        this.slave = true;
791        // remove any VMTransports connected
792        // this has to be done after services are stopped,
793        // to avoid timing issue with discovery (spinning up a new instance)
794        BrokerRegistry.getInstance().unbind(getBrokerName());
795        VMTransportFactory.stopped(getBrokerName());
796        if (broker != null) {
797            stopper.stop(broker);
798            broker = null;
799        }
800
801        if (jobSchedulerStore != null) {
802            jobSchedulerStore.stop();
803            jobSchedulerStore = null;
804        }
805        if (tempDataStore != null) {
806            tempDataStore.stop();
807            tempDataStore = null;
808        }
809        try {
810            stopper.stop(getPersistenceAdapter());
811            persistenceAdapter = null;
812            if (isUseJmx()) {
813                stopper.stop(managementContext);
814                managementContext = null;
815            }
816            // Clear SelectorParser cache to free memory
817            SelectorParser.clearCache();
818        } finally {
819            started.set(false);
820            stopped.set(true);
821            stoppedLatch.countDown();
822        }
823
824        if (this.taskRunnerFactory != null) {
825            this.taskRunnerFactory.shutdown();
826            this.taskRunnerFactory = null;
827        }
828        if (this.executor != null) {
829            ThreadPoolUtils.shutdownNow(executor);
830            this.executor = null;
831        }
832
833        this.destinationInterceptors = null;
834        this.destinationFactory = null;
835
836        if (startDate != null) {
837            LOG.info("Apache ActiveMQ {} ({}, {}) uptime {}", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId, getUptime()});
838        }
839        LOG.info("Apache ActiveMQ {} ({}, {}) is shutdown", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId});
840
841        synchronized (shutdownHooks) {
842            for (Runnable hook : shutdownHooks) {
843                try {
844                    hook.run();
845                } catch (Throwable e) {
846                    stopper.onException(hook, e);
847                }
848            }
849        }
850
851        MDC.remove("activemq.broker");
852
853        // and clear start date
854        startDate = null;
855
856        stopper.throwFirstException();
857    }
858
859    public boolean checkQueueSize(String queueName) {
860        long count = 0;
861        long queueSize = 0;
862        Map<ActiveMQDestination, Destination> destinationMap = regionBroker.getDestinationMap();
863        for (Map.Entry<ActiveMQDestination, Destination> entry : destinationMap.entrySet()) {
864            if (entry.getKey().isQueue()) {
865                if (entry.getValue().getName().matches(queueName)) {
866                    queueSize = entry.getValue().getDestinationStatistics().getMessages().getCount();
867                    count += queueSize;
868                    if (queueSize > 0) {
869                        LOG.info("Queue has pending message: {} queueSize is: {}", entry.getValue().getName(), queueSize);
870                    }
871                }
872            }
873        }
874        return count == 0;
875    }
876
877    /**
878     * This method (both connectorName and queueName are using regex to match)
879     * 1. stop the connector (supposed the user input the connector which the
880     * clients connect to) 2. to check whether there is any pending message on
881     * the queues defined by queueName 3. supposedly, after stop the connector,
882     * client should failover to other broker and pending messages should be
883     * forwarded. if no pending messages, the method finally call stop to stop
884     * the broker.
885     *
886     * @param connectorName
887     * @param queueName
888     * @param timeout
889     * @param pollInterval
890     * @throws Exception
891     */
892    public void stopGracefully(String connectorName, String queueName, long timeout, long pollInterval) throws Exception {
893        if (isUseJmx()) {
894            if (connectorName == null || queueName == null || timeout <= 0) {
895                throw new Exception(
896                        "connectorName and queueName cannot be null and timeout should be >0 for stopGracefully.");
897            }
898            if (pollInterval <= 0) {
899                pollInterval = 30;
900            }
901            LOG.info("Stop gracefully with connectorName: {} queueName: {} timeout: {} pollInterval: {}", new Object[]{
902                    connectorName, queueName, timeout, pollInterval
903            });
904            TransportConnector connector;
905            for (int i = 0; i < transportConnectors.size(); i++) {
906                connector = transportConnectors.get(i);
907                if (connector != null && connector.getName() != null && connector.getName().matches(connectorName)) {
908                    connector.stop();
909                }
910            }
911            long start = System.currentTimeMillis();
912            while (System.currentTimeMillis() - start < timeout * 1000) {
913                // check quesize until it gets zero
914                if (checkQueueSize(queueName)) {
915                    stop();
916                    break;
917                } else {
918                    Thread.sleep(pollInterval * 1000);
919                }
920            }
921            if (stopped.get()) {
922                LOG.info("Successfully stop the broker.");
923            } else {
924                LOG.info("There is still pending message on the queue. Please check and stop the broker manually.");
925            }
926        }
927    }
928
929    /**
930     * A helper method to block the caller thread until the broker has been
931     * stopped
932     */
933    public void waitUntilStopped() {
934        while (isStarted() && !stopped.get()) {
935            try {
936                stoppedLatch.await();
937            } catch (InterruptedException e) {
938                // ignore
939            }
940        }
941    }
942
943    public boolean isStopped() {
944        return stopped.get();
945    }
946
947    /**
948     * A helper method to block the caller thread until the broker has fully started
949     * @return boolean true if wait succeeded false if broker was not started or was stopped
950     */
951    public boolean waitUntilStarted() {
952        return waitUntilStarted(DEFAULT_START_TIMEOUT);
953    }
954
955    /**
956     * A helper method to block the caller thread until the broker has fully started
957     *
958     * @param timeout
959     *        the amount of time to wait before giving up and returning false.
960     *
961     * @return boolean true if wait succeeded false if broker was not started or was stopped
962     */
963    public boolean waitUntilStarted(long timeout) {
964        boolean waitSucceeded = isStarted();
965        long expiration = Math.max(0, timeout + System.currentTimeMillis());
966        while (!isStarted() && !stopped.get() && !waitSucceeded && expiration > System.currentTimeMillis()) {
967            try {
968                if (getStartException() != null) {
969                    return waitSucceeded;
970                }
971                waitSucceeded = startedLatch.await(100L, TimeUnit.MILLISECONDS);
972            } catch (InterruptedException ignore) {
973            }
974        }
975        return waitSucceeded;
976    }
977
978    // Properties
979    // -------------------------------------------------------------------------
980    /**
981     * Returns the message broker
982     */
983    public Broker getBroker() throws Exception {
984        if (broker == null) {
985            checkStartException();
986            broker = createBroker();
987        }
988        return broker;
989    }
990
991    /**
992     * Returns the administration view of the broker; used to create and destroy
993     * resources such as queues and topics. Note this method returns null if JMX
994     * is disabled.
995     */
996    public BrokerView getAdminView() throws Exception {
997        if (adminView == null) {
998            // force lazy creation
999            getBroker();
1000        }
1001        return adminView;
1002    }
1003
1004    public void setAdminView(BrokerView adminView) {
1005        this.adminView = adminView;
1006    }
1007
1008    public String getBrokerName() {
1009        return brokerName;
1010    }
1011
1012    /**
1013     * Sets the name of this broker; which must be unique in the network
1014     *
1015     * @param brokerName
1016     */
1017    private static final String brokerNameReplacedCharsRegExp = "[^a-zA-Z0-9\\.\\_\\-\\:]";
1018    public void setBrokerName(String brokerName) {
1019        if (brokerName == null) {
1020            throw new NullPointerException("The broker name cannot be null");
1021        }
1022        String str = brokerName.replaceAll(brokerNameReplacedCharsRegExp, "_");
1023        if (!str.equals(brokerName)) {
1024            LOG.error("Broker Name: {} contained illegal characters matching regExp: {} - replaced with {}", brokerName, brokerNameReplacedCharsRegExp, str);
1025        }
1026        this.brokerName = str.trim();
1027    }
1028
1029    public PersistenceAdapterFactory getPersistenceFactory() {
1030        return persistenceFactory;
1031    }
1032
1033    public File getDataDirectoryFile() {
1034        if (dataDirectoryFile == null) {
1035            dataDirectoryFile = new File(IOHelper.getDefaultDataDirectory());
1036        }
1037        return dataDirectoryFile;
1038    }
1039
1040    public File getBrokerDataDirectory() {
1041        String brokerDir = getBrokerName();
1042        return new File(getDataDirectoryFile(), brokerDir);
1043    }
1044
1045    /**
1046     * Sets the directory in which the data files will be stored by default for
1047     * the JDBC and Journal persistence adaptors.
1048     *
1049     * @param dataDirectory
1050     *            the directory to store data files
1051     */
1052    public void setDataDirectory(String dataDirectory) {
1053        setDataDirectoryFile(new File(dataDirectory));
1054    }
1055
1056    /**
1057     * Sets the directory in which the data files will be stored by default for
1058     * the JDBC and Journal persistence adaptors.
1059     *
1060     * @param dataDirectoryFile
1061     *            the directory to store data files
1062     */
1063    public void setDataDirectoryFile(File dataDirectoryFile) {
1064        this.dataDirectoryFile = dataDirectoryFile;
1065    }
1066
1067    /**
1068     * @return the tmpDataDirectory
1069     */
1070    public File getTmpDataDirectory() {
1071        if (tmpDataDirectory == null) {
1072            tmpDataDirectory = new File(getBrokerDataDirectory(), "tmp_storage");
1073        }
1074        return tmpDataDirectory;
1075    }
1076
1077    /**
1078     * @param tmpDataDirectory
1079     *            the tmpDataDirectory to set
1080     */
1081    public void setTmpDataDirectory(File tmpDataDirectory) {
1082        this.tmpDataDirectory = tmpDataDirectory;
1083    }
1084
1085    public void setPersistenceFactory(PersistenceAdapterFactory persistenceFactory) {
1086        this.persistenceFactory = persistenceFactory;
1087    }
1088
1089    public void setDestinationFactory(DestinationFactory destinationFactory) {
1090        this.destinationFactory = destinationFactory;
1091    }
1092
1093    public boolean isPersistent() {
1094        return persistent;
1095    }
1096
1097    /**
1098     * Sets whether or not persistence is enabled or disabled.
1099     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
1100     */
1101    public void setPersistent(boolean persistent) {
1102        this.persistent = persistent;
1103    }
1104
1105    public boolean isPopulateJMSXUserID() {
1106        return populateJMSXUserID;
1107    }
1108
1109    /**
1110     * Sets whether or not the broker should populate the JMSXUserID header.
1111     */
1112    public void setPopulateJMSXUserID(boolean populateJMSXUserID) {
1113        this.populateJMSXUserID = populateJMSXUserID;
1114    }
1115
1116    public SystemUsage getSystemUsage() {
1117        try {
1118            if (systemUsage == null) {
1119
1120                systemUsage = new SystemUsage("Main", getPersistenceAdapter(), getTempDataStore(), getJobSchedulerStore());
1121                systemUsage.setExecutor(getExecutor());
1122                systemUsage.getMemoryUsage().setLimit(1024L * 1024 * 1024 * 1); // 1 GB
1123                systemUsage.getTempUsage().setLimit(1024L * 1024 * 1024 * 50); // 50 GB
1124                systemUsage.getStoreUsage().setLimit(1024L * 1024 * 1024 * 100); // 100 GB
1125                systemUsage.getJobSchedulerUsage().setLimit(1024L * 1024 * 1024 * 50); // 50 GB
1126                addService(this.systemUsage);
1127            }
1128            return systemUsage;
1129        } catch (IOException e) {
1130            LOG.error("Cannot create SystemUsage", e);
1131            throw new RuntimeException("Fatally failed to create SystemUsage" + e.getMessage(), e);
1132        }
1133    }
1134
1135    public void setSystemUsage(SystemUsage memoryManager) {
1136        if (this.systemUsage != null) {
1137            removeService(this.systemUsage);
1138        }
1139        this.systemUsage = memoryManager;
1140        if (this.systemUsage.getExecutor()==null) {
1141            this.systemUsage.setExecutor(getExecutor());
1142        }
1143        addService(this.systemUsage);
1144    }
1145
1146    /**
1147     * @return the consumerUsageManager
1148     * @throws IOException
1149     */
1150    public SystemUsage getConsumerSystemUsage() throws IOException {
1151        if (this.consumerSystemUsaage == null) {
1152            if (splitSystemUsageForProducersConsumers) {
1153                this.consumerSystemUsaage = new SystemUsage(getSystemUsage(), "Consumer");
1154                float portion = consumerSystemUsagePortion / 100f;
1155                this.consumerSystemUsaage.getMemoryUsage().setUsagePortion(portion);
1156                addService(this.consumerSystemUsaage);
1157            } else {
1158                consumerSystemUsaage = getSystemUsage();
1159            }
1160        }
1161        return this.consumerSystemUsaage;
1162    }
1163
1164    /**
1165     * @param consumerSystemUsaage
1166     *            the storeSystemUsage to set
1167     */
1168    public void setConsumerSystemUsage(SystemUsage consumerSystemUsaage) {
1169        if (this.consumerSystemUsaage != null) {
1170            removeService(this.consumerSystemUsaage);
1171        }
1172        this.consumerSystemUsaage = consumerSystemUsaage;
1173        addService(this.consumerSystemUsaage);
1174    }
1175
1176    /**
1177     * @return the producerUsageManager
1178     * @throws IOException
1179     */
1180    public SystemUsage getProducerSystemUsage() throws IOException {
1181        if (producerSystemUsage == null) {
1182            if (splitSystemUsageForProducersConsumers) {
1183                producerSystemUsage = new SystemUsage(getSystemUsage(), "Producer");
1184                float portion = producerSystemUsagePortion / 100f;
1185                producerSystemUsage.getMemoryUsage().setUsagePortion(portion);
1186                addService(producerSystemUsage);
1187            } else {
1188                producerSystemUsage = getSystemUsage();
1189            }
1190        }
1191        return producerSystemUsage;
1192    }
1193
1194    /**
1195     * @param producerUsageManager
1196     *            the producerUsageManager to set
1197     */
1198    public void setProducerSystemUsage(SystemUsage producerUsageManager) {
1199        if (this.producerSystemUsage != null) {
1200            removeService(this.producerSystemUsage);
1201        }
1202        this.producerSystemUsage = producerUsageManager;
1203        addService(this.producerSystemUsage);
1204    }
1205
1206    public synchronized PersistenceAdapter getPersistenceAdapter() throws IOException {
1207        if (persistenceAdapter == null && !hasStartException()) {
1208            persistenceAdapter = createPersistenceAdapter();
1209            configureService(persistenceAdapter);
1210            this.persistenceAdapter = registerPersistenceAdapterMBean(persistenceAdapter);
1211        }
1212        return persistenceAdapter;
1213    }
1214
1215    /**
1216     * Sets the persistence adaptor implementation to use for this broker
1217     *
1218     * @throws IOException
1219     */
1220    public void setPersistenceAdapter(PersistenceAdapter persistenceAdapter) throws IOException {
1221        if (!isPersistent() && ! (persistenceAdapter instanceof MemoryPersistenceAdapter)) {
1222            LOG.warn("persistent=\"false\", ignoring configured persistenceAdapter: {}", persistenceAdapter);
1223            return;
1224        }
1225        this.persistenceAdapter = persistenceAdapter;
1226        configureService(this.persistenceAdapter);
1227        this.persistenceAdapter = registerPersistenceAdapterMBean(persistenceAdapter);
1228    }
1229
1230    public TaskRunnerFactory getTaskRunnerFactory() {
1231        if (this.taskRunnerFactory == null) {
1232            this.taskRunnerFactory = new TaskRunnerFactory("ActiveMQ BrokerService["+getBrokerName()+"] Task", getTaskRunnerPriority(), true, 1000,
1233                    isDedicatedTaskRunner());
1234            this.taskRunnerFactory.setThreadClassLoader(this.getClass().getClassLoader());
1235        }
1236        return this.taskRunnerFactory;
1237    }
1238
1239    public void setTaskRunnerFactory(TaskRunnerFactory taskRunnerFactory) {
1240        this.taskRunnerFactory = taskRunnerFactory;
1241    }
1242
1243    public TaskRunnerFactory getPersistenceTaskRunnerFactory() {
1244        if (taskRunnerFactory == null) {
1245            persistenceTaskRunnerFactory = new TaskRunnerFactory("Persistence Adaptor Task", persistenceThreadPriority,
1246                    true, 1000, isDedicatedTaskRunner());
1247        }
1248        return persistenceTaskRunnerFactory;
1249    }
1250
1251    public void setPersistenceTaskRunnerFactory(TaskRunnerFactory persistenceTaskRunnerFactory) {
1252        this.persistenceTaskRunnerFactory = persistenceTaskRunnerFactory;
1253    }
1254
1255    public boolean isUseJmx() {
1256        return useJmx;
1257    }
1258
1259    public boolean isEnableStatistics() {
1260        return enableStatistics;
1261    }
1262
1263    /**
1264     * Sets whether or not the Broker's services enable statistics or not.
1265     */
1266    public void setEnableStatistics(boolean enableStatistics) {
1267        this.enableStatistics = enableStatistics;
1268    }
1269
1270    /**
1271     * Sets whether or not the Broker's services should be exposed into JMX or
1272     * not.
1273     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
1274     */
1275    public void setUseJmx(boolean useJmx) {
1276        this.useJmx = useJmx;
1277    }
1278
1279    public ObjectName getBrokerObjectName() throws MalformedObjectNameException {
1280        if (brokerObjectName == null) {
1281            brokerObjectName = createBrokerObjectName();
1282        }
1283        return brokerObjectName;
1284    }
1285
1286    /**
1287     * Sets the JMX ObjectName for this broker
1288     */
1289    public void setBrokerObjectName(ObjectName brokerObjectName) {
1290        this.brokerObjectName = brokerObjectName;
1291    }
1292
1293    public ManagementContext getManagementContext() {
1294        if (managementContext == null) {
1295            checkStartException();
1296            managementContext = new ManagementContext();
1297        }
1298        return managementContext;
1299    }
1300
1301    synchronized private void checkStartException() {
1302        if (startException != null) {
1303            throw new BrokerStoppedException(startException);
1304        }
1305    }
1306
1307    synchronized private boolean hasStartException() {
1308        return startException != null;
1309    }
1310
1311    synchronized private void setStartException(Throwable t) {
1312        startException = t;
1313    }
1314
1315    public void setManagementContext(ManagementContext managementContext) {
1316        this.managementContext = managementContext;
1317    }
1318
1319    public NetworkConnector getNetworkConnectorByName(String connectorName) {
1320        for (NetworkConnector connector : networkConnectors) {
1321            if (connector.getName().equals(connectorName)) {
1322                return connector;
1323            }
1324        }
1325        return null;
1326    }
1327
1328    public String[] getNetworkConnectorURIs() {
1329        return networkConnectorURIs;
1330    }
1331
1332    public void setNetworkConnectorURIs(String[] networkConnectorURIs) {
1333        this.networkConnectorURIs = networkConnectorURIs;
1334    }
1335
1336    public TransportConnector getConnectorByName(String connectorName) {
1337        for (TransportConnector connector : transportConnectors) {
1338            if (connector.getName().equals(connectorName)) {
1339                return connector;
1340            }
1341        }
1342        return null;
1343    }
1344
1345    public Map<String, String> getTransportConnectorURIsAsMap() {
1346        Map<String, String> answer = new HashMap<String, String>();
1347        for (TransportConnector connector : transportConnectors) {
1348            try {
1349                URI uri = connector.getConnectUri();
1350                if (uri != null) {
1351                    String scheme = uri.getScheme();
1352                    if (scheme != null) {
1353                        answer.put(scheme.toLowerCase(Locale.ENGLISH), uri.toString());
1354                    }
1355                }
1356            } catch (Exception e) {
1357                LOG.debug("Failed to read URI to build transportURIsAsMap", e);
1358            }
1359        }
1360        return answer;
1361    }
1362
1363    public ProducerBrokerExchange getProducerBrokerExchange(ProducerInfo producerInfo){
1364        ProducerBrokerExchange result = null;
1365
1366        for (TransportConnector connector : transportConnectors) {
1367            for (TransportConnection tc: connector.getConnections()){
1368                result = tc.getProducerBrokerExchangeIfExists(producerInfo);
1369                if (result !=null){
1370                    return result;
1371                }
1372            }
1373        }
1374        return result;
1375    }
1376
1377    public String[] getTransportConnectorURIs() {
1378        return transportConnectorURIs;
1379    }
1380
1381    public void setTransportConnectorURIs(String[] transportConnectorURIs) {
1382        this.transportConnectorURIs = transportConnectorURIs;
1383    }
1384
1385    /**
1386     * @return Returns the jmsBridgeConnectors.
1387     */
1388    public JmsConnector[] getJmsBridgeConnectors() {
1389        return jmsBridgeConnectors;
1390    }
1391
1392    /**
1393     * @param jmsConnectors
1394     *            The jmsBridgeConnectors to set.
1395     */
1396    public void setJmsBridgeConnectors(JmsConnector[] jmsConnectors) {
1397        this.jmsBridgeConnectors = jmsConnectors;
1398    }
1399
1400    public Service[] getServices() {
1401        return services.toArray(new Service[0]);
1402    }
1403
1404    /**
1405     * Sets the services associated with this broker.
1406     */
1407    public void setServices(Service[] services) {
1408        this.services.clear();
1409        if (services != null) {
1410            for (int i = 0; i < services.length; i++) {
1411                this.services.add(services[i]);
1412            }
1413        }
1414    }
1415
1416    /**
1417     * Adds a new service so that it will be started as part of the broker
1418     * lifecycle
1419     */
1420    public void addService(Service service) {
1421        services.add(service);
1422    }
1423
1424    public void removeService(Service service) {
1425        services.remove(service);
1426    }
1427
1428    public boolean isUseLoggingForShutdownErrors() {
1429        return useLoggingForShutdownErrors;
1430    }
1431
1432    /**
1433     * Sets whether or not we should use commons-logging when reporting errors
1434     * when shutting down the broker
1435     */
1436    public void setUseLoggingForShutdownErrors(boolean useLoggingForShutdownErrors) {
1437        this.useLoggingForShutdownErrors = useLoggingForShutdownErrors;
1438    }
1439
1440    public boolean isUseShutdownHook() {
1441        return useShutdownHook;
1442    }
1443
1444    /**
1445     * Sets whether or not we should use a shutdown handler to close down the
1446     * broker cleanly if the JVM is terminated. It is recommended you leave this
1447     * enabled.
1448     */
1449    public void setUseShutdownHook(boolean useShutdownHook) {
1450        this.useShutdownHook = useShutdownHook;
1451    }
1452
1453    public boolean isAdvisorySupport() {
1454        return advisorySupport;
1455    }
1456
1457    /**
1458     * Allows the support of advisory messages to be disabled for performance
1459     * reasons.
1460     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
1461     */
1462    public void setAdvisorySupport(boolean advisorySupport) {
1463        this.advisorySupport = advisorySupport;
1464    }
1465
1466    public List<TransportConnector> getTransportConnectors() {
1467        return new ArrayList<TransportConnector>(transportConnectors);
1468    }
1469
1470    /**
1471     * Sets the transport connectors which this broker will listen on for new
1472     * clients
1473     *
1474     * @org.apache.xbean.Property
1475     *                            nestedType="org.apache.activemq.broker.TransportConnector"
1476     */
1477    public void setTransportConnectors(List<TransportConnector> transportConnectors) throws Exception {
1478        for (TransportConnector connector : transportConnectors) {
1479            addConnector(connector);
1480        }
1481    }
1482
1483    public TransportConnector getTransportConnectorByName(String name){
1484        for (TransportConnector transportConnector : transportConnectors){
1485           if (name.equals(transportConnector.getName())){
1486               return transportConnector;
1487           }
1488        }
1489        return null;
1490    }
1491
1492    public TransportConnector getTransportConnectorByScheme(String scheme){
1493        for (TransportConnector transportConnector : transportConnectors){
1494            if (scheme.equals(transportConnector.getUri().getScheme())){
1495                return transportConnector;
1496            }
1497        }
1498        return null;
1499    }
1500
1501    public List<NetworkConnector> getNetworkConnectors() {
1502        return new ArrayList<NetworkConnector>(networkConnectors);
1503    }
1504
1505    public List<ProxyConnector> getProxyConnectors() {
1506        return new ArrayList<ProxyConnector>(proxyConnectors);
1507    }
1508
1509    /**
1510     * Sets the network connectors which this broker will use to connect to
1511     * other brokers in a federated network
1512     *
1513     * @org.apache.xbean.Property
1514     *                            nestedType="org.apache.activemq.network.NetworkConnector"
1515     */
1516    public void setNetworkConnectors(List<?> networkConnectors) throws Exception {
1517        for (Object connector : networkConnectors) {
1518            addNetworkConnector((NetworkConnector) connector);
1519        }
1520    }
1521
1522    /**
1523     * Sets the network connectors which this broker will use to connect to
1524     * other brokers in a federated network
1525     */
1526    public void setProxyConnectors(List<?> proxyConnectors) throws Exception {
1527        for (Object connector : proxyConnectors) {
1528            addProxyConnector((ProxyConnector) connector);
1529        }
1530    }
1531
1532    public PolicyMap getDestinationPolicy() {
1533        return destinationPolicy;
1534    }
1535
1536    /**
1537     * Sets the destination specific policies available either for exact
1538     * destinations or for wildcard areas of destinations.
1539     */
1540    public void setDestinationPolicy(PolicyMap policyMap) {
1541        this.destinationPolicy = policyMap;
1542    }
1543
1544    public BrokerPlugin[] getPlugins() {
1545        return plugins;
1546    }
1547
1548    /**
1549     * Sets a number of broker plugins to install such as for security
1550     * authentication or authorization
1551     */
1552    public void setPlugins(BrokerPlugin[] plugins) {
1553        this.plugins = plugins;
1554    }
1555
1556    public MessageAuthorizationPolicy getMessageAuthorizationPolicy() {
1557        return messageAuthorizationPolicy;
1558    }
1559
1560    /**
1561     * Sets the policy used to decide if the current connection is authorized to
1562     * consume a given message
1563     */
1564    public void setMessageAuthorizationPolicy(MessageAuthorizationPolicy messageAuthorizationPolicy) {
1565        this.messageAuthorizationPolicy = messageAuthorizationPolicy;
1566    }
1567
1568    /**
1569     * Delete all messages from the persistent store
1570     *
1571     * @throws IOException
1572     */
1573    public void deleteAllMessages() throws IOException {
1574        getPersistenceAdapter().deleteAllMessages();
1575    }
1576
1577    public boolean isDeleteAllMessagesOnStartup() {
1578        return deleteAllMessagesOnStartup;
1579    }
1580
1581    /**
1582     * Sets whether or not all messages are deleted on startup - mostly only
1583     * useful for testing.
1584     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
1585     */
1586    public void setDeleteAllMessagesOnStartup(boolean deletePersistentMessagesOnStartup) {
1587        this.deleteAllMessagesOnStartup = deletePersistentMessagesOnStartup;
1588    }
1589
1590    public URI getVmConnectorURI() {
1591        if (vmConnectorURI == null) {
1592            try {
1593                vmConnectorURI = new URI("vm://" + getBrokerName());
1594            } catch (URISyntaxException e) {
1595                LOG.error("Badly formed URI from {}", getBrokerName(), e);
1596            }
1597        }
1598        return vmConnectorURI;
1599    }
1600
1601    public void setVmConnectorURI(URI vmConnectorURI) {
1602        this.vmConnectorURI = vmConnectorURI;
1603    }
1604
1605    public String getDefaultSocketURIString() {
1606        if (started.get()) {
1607            if (this.defaultSocketURIString == null) {
1608                for (TransportConnector tc:this.transportConnectors) {
1609                    String result = null;
1610                    try {
1611                        result = tc.getPublishableConnectString();
1612                    } catch (Exception e) {
1613                      LOG.warn("Failed to get the ConnectURI for {}", tc, e);
1614                    }
1615                    if (result != null) {
1616                        // find first publishable uri
1617                        if (tc.isUpdateClusterClients() || tc.isRebalanceClusterClients()) {
1618                            this.defaultSocketURIString = result;
1619                            break;
1620                        } else {
1621                        // or use the first defined
1622                            if (this.defaultSocketURIString == null) {
1623                                this.defaultSocketURIString = result;
1624                            }
1625                        }
1626                    }
1627                }
1628
1629            }
1630            return this.defaultSocketURIString;
1631        }
1632       return null;
1633    }
1634
1635    /**
1636     * @return Returns the shutdownOnMasterFailure.
1637     */
1638    public boolean isShutdownOnMasterFailure() {
1639        return shutdownOnMasterFailure;
1640    }
1641
1642    /**
1643     * @param shutdownOnMasterFailure
1644     *            The shutdownOnMasterFailure to set.
1645     */
1646    public void setShutdownOnMasterFailure(boolean shutdownOnMasterFailure) {
1647        this.shutdownOnMasterFailure = shutdownOnMasterFailure;
1648    }
1649
1650    public boolean isKeepDurableSubsActive() {
1651        return keepDurableSubsActive;
1652    }
1653
1654    public void setKeepDurableSubsActive(boolean keepDurableSubsActive) {
1655        this.keepDurableSubsActive = keepDurableSubsActive;
1656    }
1657
1658    public boolean isUseVirtualTopics() {
1659        return useVirtualTopics;
1660    }
1661
1662    /**
1663     * Sets whether or not <a
1664     * href="http://activemq.apache.org/virtual-destinations.html">Virtual
1665     * Topics</a> should be supported by default if they have not been
1666     * explicitly configured.
1667     */
1668    public void setUseVirtualTopics(boolean useVirtualTopics) {
1669        this.useVirtualTopics = useVirtualTopics;
1670    }
1671
1672    public DestinationInterceptor[] getDestinationInterceptors() {
1673        return destinationInterceptors;
1674    }
1675
1676    public boolean isUseMirroredQueues() {
1677        return useMirroredQueues;
1678    }
1679
1680    /**
1681     * Sets whether or not <a
1682     * href="http://activemq.apache.org/mirrored-queues.html">Mirrored
1683     * Queues</a> should be supported by default if they have not been
1684     * explicitly configured.
1685     */
1686    public void setUseMirroredQueues(boolean useMirroredQueues) {
1687        this.useMirroredQueues = useMirroredQueues;
1688    }
1689
1690    /**
1691     * Sets the destination interceptors to use
1692     */
1693    public void setDestinationInterceptors(DestinationInterceptor[] destinationInterceptors) {
1694        this.destinationInterceptors = destinationInterceptors;
1695    }
1696
1697    public ActiveMQDestination[] getDestinations() {
1698        return destinations;
1699    }
1700
1701    /**
1702     * Sets the destinations which should be loaded/created on startup
1703     */
1704    public void setDestinations(ActiveMQDestination[] destinations) {
1705        this.destinations = destinations;
1706    }
1707
1708    /**
1709     * @return the tempDataStore
1710     */
1711    public synchronized PListStore getTempDataStore() {
1712        if (tempDataStore == null) {
1713            if (!isPersistent()) {
1714                return null;
1715            }
1716
1717            try {
1718                PersistenceAdapter pa = getPersistenceAdapter();
1719                if( pa!=null && pa instanceof PListStore) {
1720                    return (PListStore) pa;
1721                }
1722            } catch (IOException e) {
1723                throw new RuntimeException(e);
1724            }
1725
1726            boolean result = true;
1727            boolean empty = true;
1728            try {
1729                File directory = getTmpDataDirectory();
1730                if (directory.exists() && directory.isDirectory()) {
1731                    File[] files = directory.listFiles();
1732                    if (files != null && files.length > 0) {
1733                        empty = false;
1734                        for (int i = 0; i < files.length; i++) {
1735                            File file = files[i];
1736                            if (!file.isDirectory()) {
1737                                result &= file.delete();
1738                            }
1739                        }
1740                    }
1741                }
1742                if (!empty) {
1743                    String str = result ? "Successfully deleted" : "Failed to delete";
1744                    LOG.info("{} temporary storage", str);
1745                }
1746
1747                String clazz = "org.apache.activemq.store.kahadb.plist.PListStoreImpl";
1748                this.tempDataStore = (PListStore) getClass().getClassLoader().loadClass(clazz).newInstance();
1749                this.tempDataStore.setDirectory(getTmpDataDirectory());
1750                configureService(tempDataStore);
1751                this.tempDataStore.start();
1752            } catch (Exception e) {
1753                throw new RuntimeException(e);
1754            }
1755        }
1756        return tempDataStore;
1757    }
1758
1759    /**
1760     * @param tempDataStore
1761     *            the tempDataStore to set
1762     */
1763    public void setTempDataStore(PListStore tempDataStore) {
1764        this.tempDataStore = tempDataStore;
1765        configureService(tempDataStore);
1766        try {
1767            tempDataStore.start();
1768        } catch (Exception e) {
1769            RuntimeException exception = new RuntimeException("Failed to start provided temp data store: " + tempDataStore, e);
1770            LOG.error(exception.getLocalizedMessage(), e);
1771            throw exception;
1772        }
1773    }
1774
1775    public int getPersistenceThreadPriority() {
1776        return persistenceThreadPriority;
1777    }
1778
1779    public void setPersistenceThreadPriority(int persistenceThreadPriority) {
1780        this.persistenceThreadPriority = persistenceThreadPriority;
1781    }
1782
1783    /**
1784     * @return the useLocalHostBrokerName
1785     */
1786    public boolean isUseLocalHostBrokerName() {
1787        return this.useLocalHostBrokerName;
1788    }
1789
1790    /**
1791     * @param useLocalHostBrokerName
1792     *            the useLocalHostBrokerName to set
1793     */
1794    public void setUseLocalHostBrokerName(boolean useLocalHostBrokerName) {
1795        this.useLocalHostBrokerName = useLocalHostBrokerName;
1796        if (useLocalHostBrokerName && !started.get() && brokerName == null || brokerName == DEFAULT_BROKER_NAME) {
1797            brokerName = LOCAL_HOST_NAME;
1798        }
1799    }
1800
1801    /**
1802     * Looks up and lazily creates if necessary the destination for the given
1803     * JMS name
1804     */
1805    public Destination getDestination(ActiveMQDestination destination) throws Exception {
1806        return getBroker().addDestination(getAdminConnectionContext(), destination,false);
1807    }
1808
1809    public void removeDestination(ActiveMQDestination destination) throws Exception {
1810        getBroker().removeDestination(getAdminConnectionContext(), destination, 0);
1811    }
1812
1813    public int getProducerSystemUsagePortion() {
1814        return producerSystemUsagePortion;
1815    }
1816
1817    public void setProducerSystemUsagePortion(int producerSystemUsagePortion) {
1818        this.producerSystemUsagePortion = producerSystemUsagePortion;
1819    }
1820
1821    public int getConsumerSystemUsagePortion() {
1822        return consumerSystemUsagePortion;
1823    }
1824
1825    public void setConsumerSystemUsagePortion(int consumerSystemUsagePortion) {
1826        this.consumerSystemUsagePortion = consumerSystemUsagePortion;
1827    }
1828
1829    public boolean isSplitSystemUsageForProducersConsumers() {
1830        return splitSystemUsageForProducersConsumers;
1831    }
1832
1833    public void setSplitSystemUsageForProducersConsumers(boolean splitSystemUsageForProducersConsumers) {
1834        this.splitSystemUsageForProducersConsumers = splitSystemUsageForProducersConsumers;
1835    }
1836
1837    public boolean isMonitorConnectionSplits() {
1838        return monitorConnectionSplits;
1839    }
1840
1841    public void setMonitorConnectionSplits(boolean monitorConnectionSplits) {
1842        this.monitorConnectionSplits = monitorConnectionSplits;
1843    }
1844
1845    public int getTaskRunnerPriority() {
1846        return taskRunnerPriority;
1847    }
1848
1849    public void setTaskRunnerPriority(int taskRunnerPriority) {
1850        this.taskRunnerPriority = taskRunnerPriority;
1851    }
1852
1853    public boolean isDedicatedTaskRunner() {
1854        return dedicatedTaskRunner;
1855    }
1856
1857    public void setDedicatedTaskRunner(boolean dedicatedTaskRunner) {
1858        this.dedicatedTaskRunner = dedicatedTaskRunner;
1859    }
1860
1861    public boolean isCacheTempDestinations() {
1862        return cacheTempDestinations;
1863    }
1864
1865    public void setCacheTempDestinations(boolean cacheTempDestinations) {
1866        this.cacheTempDestinations = cacheTempDestinations;
1867    }
1868
1869    public int getTimeBeforePurgeTempDestinations() {
1870        return timeBeforePurgeTempDestinations;
1871    }
1872
1873    public void setTimeBeforePurgeTempDestinations(int timeBeforePurgeTempDestinations) {
1874        this.timeBeforePurgeTempDestinations = timeBeforePurgeTempDestinations;
1875    }
1876
1877    public boolean isUseTempMirroredQueues() {
1878        return useTempMirroredQueues;
1879    }
1880
1881    public void setUseTempMirroredQueues(boolean useTempMirroredQueues) {
1882        this.useTempMirroredQueues = useTempMirroredQueues;
1883    }
1884
1885    public synchronized JobSchedulerStore getJobSchedulerStore() {
1886
1887        // If support is off don't allow any scheduler even is user configured their own.
1888        if (!isSchedulerSupport()) {
1889            return null;
1890        }
1891
1892        // If the user configured their own we use it even if persistence is disabled since
1893        // we don't know anything about their implementation.
1894        if (jobSchedulerStore == null) {
1895
1896            if (!isPersistent()) {
1897                this.jobSchedulerStore = new InMemoryJobSchedulerStore();
1898                configureService(jobSchedulerStore);
1899                return this.jobSchedulerStore;
1900            }
1901
1902            try {
1903                PersistenceAdapter pa = getPersistenceAdapter();
1904                if (pa != null) {
1905                    this.jobSchedulerStore = pa.createJobSchedulerStore();
1906                    jobSchedulerStore.setDirectory(getSchedulerDirectoryFile());
1907                    configureService(jobSchedulerStore);
1908                    return this.jobSchedulerStore;
1909                }
1910            } catch (IOException e) {
1911                throw new RuntimeException(e);
1912            } catch (UnsupportedOperationException ex) {
1913                // It's ok if the store doesn't implement a scheduler.
1914            } catch (Exception e) {
1915                throw new RuntimeException(e);
1916            }
1917
1918            try {
1919                PersistenceAdapter pa = getPersistenceAdapter();
1920                if (pa != null && pa instanceof JobSchedulerStore) {
1921                    this.jobSchedulerStore = (JobSchedulerStore) pa;
1922                    configureService(jobSchedulerStore);
1923                    return this.jobSchedulerStore;
1924                }
1925            } catch (IOException e) {
1926                throw new RuntimeException(e);
1927            }
1928
1929            // Load the KahaDB store as a last resort, this only works if KahaDB is
1930            // included at runtime, otherwise this will fail.  User should disable
1931            // scheduler support if this fails.
1932            try {
1933                String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter";
1934                PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance();
1935                jobSchedulerStore = adaptor.createJobSchedulerStore();
1936                jobSchedulerStore.setDirectory(getSchedulerDirectoryFile());
1937                configureService(jobSchedulerStore);
1938                LOG.info("JobScheduler using directory: {}", getSchedulerDirectoryFile());
1939            } catch (Exception e) {
1940                throw new RuntimeException(e);
1941            }
1942        }
1943        return jobSchedulerStore;
1944    }
1945
1946    public void setJobSchedulerStore(JobSchedulerStore jobSchedulerStore) {
1947        this.jobSchedulerStore = jobSchedulerStore;
1948        configureService(jobSchedulerStore);
1949    }
1950
1951    //
1952    // Implementation methods
1953    // -------------------------------------------------------------------------
1954    /**
1955     * Handles any lazy-creation helper properties which are added to make
1956     * things easier to configure inside environments such as Spring
1957     *
1958     * @throws Exception
1959     */
1960    protected void processHelperProperties() throws Exception {
1961        if (transportConnectorURIs != null) {
1962            for (int i = 0; i < transportConnectorURIs.length; i++) {
1963                String uri = transportConnectorURIs[i];
1964                addConnector(uri);
1965            }
1966        }
1967        if (networkConnectorURIs != null) {
1968            for (int i = 0; i < networkConnectorURIs.length; i++) {
1969                String uri = networkConnectorURIs[i];
1970                addNetworkConnector(uri);
1971            }
1972        }
1973        if (jmsBridgeConnectors != null) {
1974            for (int i = 0; i < jmsBridgeConnectors.length; i++) {
1975                addJmsConnector(jmsBridgeConnectors[i]);
1976            }
1977        }
1978    }
1979
1980    protected void checkSystemUsageLimits() throws IOException {
1981        SystemUsage usage = getSystemUsage();
1982        long memLimit = usage.getMemoryUsage().getLimit();
1983        long jvmLimit = Runtime.getRuntime().maxMemory();
1984
1985        if (memLimit > jvmLimit) {
1986            usage.getMemoryUsage().setPercentOfJvmHeap(70);
1987            LOG.warn("Memory Usage for the Broker (" + memLimit / (1024 * 1024) +
1988                    " mb) is more than the maximum available for the JVM: " +
1989                    jvmLimit / (1024 * 1024) + " mb - resetting to 70% of maximum available: " + (usage.getMemoryUsage().getLimit() / (1024 * 1024)) + " mb");
1990        }
1991
1992        if (getPersistenceAdapter() != null) {
1993            PersistenceAdapter adapter = getPersistenceAdapter();
1994            File dir = adapter.getDirectory();
1995
1996            if (dir != null) {
1997                String dirPath = dir.getAbsolutePath();
1998                if (!dir.isAbsolute()) {
1999                    dir = new File(dirPath);
2000                }
2001
2002                while (dir != null && !dir.isDirectory()) {
2003                    dir = dir.getParentFile();
2004                }
2005                long storeLimit = usage.getStoreUsage().getLimit();
2006                long storeCurrent = usage.getStoreUsage().getUsage();
2007                long dirFreeSpace = dir.getUsableSpace();
2008                if (storeLimit > (dirFreeSpace + storeCurrent)) {
2009                    LOG.warn("Store limit is " + storeLimit / (1024 * 1024) +
2010                             " mb (current store usage is " + storeCurrent / (1024 * 1024) +
2011                             " mb). The data directory: " + dir.getAbsolutePath() +
2012                             " only has " + dirFreeSpace / (1024 * 1024) +
2013                             " mb of usable space - resetting to maximum available disk space: " +
2014                            (dirFreeSpace + storeCurrent) / (1024 * 1024) + " mb");
2015                    usage.getStoreUsage().setLimit(dirFreeSpace + storeCurrent);
2016                }
2017            }
2018
2019            long maxJournalFileSize = 0;
2020            long storeLimit = usage.getStoreUsage().getLimit();
2021
2022            if (adapter instanceof JournaledStore) {
2023                maxJournalFileSize = ((JournaledStore) adapter).getJournalMaxFileLength();
2024            }
2025
2026            if (storeLimit < maxJournalFileSize) {
2027                LOG.error("Store limit is " + storeLimit / (1024 * 1024) +
2028                          " mb, whilst the max journal file size for the store is: " +
2029                          maxJournalFileSize / (1024 * 1024) + " mb, " +
2030                          "the store will not accept any data when used.");
2031
2032            }
2033        }
2034
2035        File tmpDir = getTmpDataDirectory();
2036        if (tmpDir != null) {
2037
2038            String tmpDirPath = tmpDir.getAbsolutePath();
2039            if (!tmpDir.isAbsolute()) {
2040                tmpDir = new File(tmpDirPath);
2041            }
2042
2043            long storeLimit = usage.getTempUsage().getLimit();
2044            while (tmpDir != null && !tmpDir.isDirectory()) {
2045                tmpDir = tmpDir.getParentFile();
2046            }
2047            long dirFreeSpace = tmpDir.getUsableSpace();
2048            if (storeLimit > dirFreeSpace) {
2049                LOG.warn("Temporary Store limit is " + storeLimit / (1024 * 1024) +
2050                        " mb, whilst the temporary data directory: " + tmpDirPath +
2051                        " only has " + dirFreeSpace / (1024 * 1024) + " mb of usable space - resetting to maximum available " +
2052                        dirFreeSpace / (1024 * 1024) + " mb.");
2053                usage.getTempUsage().setLimit(dirFreeSpace);
2054            }
2055
2056            if (isPersistent()) {
2057                long maxJournalFileSize;
2058
2059                PListStore store = usage.getTempUsage().getStore();
2060                if (store != null && store instanceof JournaledStore) {
2061                    maxJournalFileSize = ((JournaledStore) store).getJournalMaxFileLength();
2062                } else {
2063                    maxJournalFileSize = DEFAULT_MAX_FILE_LENGTH;
2064                }
2065
2066                if (storeLimit < maxJournalFileSize) {
2067                    LOG.error("Temporary Store limit is " + storeLimit / (1024 * 1024) +
2068                              " mb, whilst the max journal file size for the temporary store is: " +
2069                              maxJournalFileSize / (1024 * 1024) + " mb, " +
2070                              "the temp store will not accept any data when used.");
2071                }
2072            }
2073        }
2074
2075        if (getJobSchedulerStore() != null) {
2076            JobSchedulerStore scheduler = getJobSchedulerStore();
2077            File schedulerDir = scheduler.getDirectory();
2078            if (schedulerDir != null) {
2079
2080                String schedulerDirPath = schedulerDir.getAbsolutePath();
2081                if (!schedulerDir.isAbsolute()) {
2082                    schedulerDir = new File(schedulerDirPath);
2083                }
2084
2085                while (schedulerDir != null && !schedulerDir.isDirectory()) {
2086                    schedulerDir = schedulerDir.getParentFile();
2087                }
2088                long schedulerLimit = usage.getJobSchedulerUsage().getLimit();
2089                long dirFreeSpace = schedulerDir.getUsableSpace();
2090                if (schedulerLimit > dirFreeSpace) {
2091                    LOG.warn("Job Scheduler Store limit is " + schedulerLimit / (1024 * 1024) +
2092                             " mb, whilst the data directory: " + schedulerDir.getAbsolutePath() +
2093                             " only has " + dirFreeSpace / (1024 * 1024) + " mb of usable space - resetting to " +
2094                            dirFreeSpace / (1024 * 1024) + " mb.");
2095                    usage.getJobSchedulerUsage().setLimit(dirFreeSpace);
2096                }
2097            }
2098        }
2099    }
2100
2101    public void stopAllConnectors(ServiceStopper stopper) {
2102        for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) {
2103            NetworkConnector connector = iter.next();
2104            unregisterNetworkConnectorMBean(connector);
2105            stopper.stop(connector);
2106        }
2107        for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) {
2108            ProxyConnector connector = iter.next();
2109            stopper.stop(connector);
2110        }
2111        for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) {
2112            JmsConnector connector = iter.next();
2113            stopper.stop(connector);
2114        }
2115        for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) {
2116            TransportConnector connector = iter.next();
2117            try {
2118                unregisterConnectorMBean(connector);
2119            } catch (IOException e) {
2120            }
2121            stopper.stop(connector);
2122        }
2123    }
2124
2125    protected TransportConnector registerConnectorMBean(TransportConnector connector) throws IOException {
2126        try {
2127            ObjectName objectName = createConnectorObjectName(connector);
2128            connector = connector.asManagedConnector(getManagementContext(), objectName);
2129            ConnectorViewMBean view = new ConnectorView(connector);
2130            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2131            return connector;
2132        } catch (Throwable e) {
2133            throw IOExceptionSupport.create("Transport Connector could not be registered in JMX: " + e, e);
2134        }
2135    }
2136
2137    protected void unregisterConnectorMBean(TransportConnector connector) throws IOException {
2138        if (isUseJmx()) {
2139            try {
2140                ObjectName objectName = createConnectorObjectName(connector);
2141                getManagementContext().unregisterMBean(objectName);
2142            } catch (Throwable e) {
2143                throw IOExceptionSupport.create(
2144                        "Transport Connector could not be unregistered in JMX: " + e.getMessage(), e);
2145            }
2146        }
2147    }
2148
2149    protected PersistenceAdapter registerPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException {
2150        return adaptor;
2151    }
2152
2153    protected void unregisterPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException {
2154        if (isUseJmx()) {}
2155    }
2156
2157    private ObjectName createConnectorObjectName(TransportConnector connector) throws MalformedObjectNameException {
2158        return BrokerMBeanSupport.createConnectorName(getBrokerObjectName(), "clientConnectors", connector.getName());
2159    }
2160
2161    public void registerNetworkConnectorMBean(NetworkConnector connector) throws IOException {
2162        NetworkConnectorViewMBean view = new NetworkConnectorView(connector);
2163        try {
2164            ObjectName objectName = createNetworkConnectorObjectName(connector);
2165            connector.setObjectName(objectName);
2166            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2167        } catch (Throwable e) {
2168            throw IOExceptionSupport.create("Network Connector could not be registered in JMX: " + e.getMessage(), e);
2169        }
2170    }
2171
2172    protected ObjectName createNetworkConnectorObjectName(NetworkConnector connector) throws MalformedObjectNameException {
2173        return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "networkConnectors", connector.getName());
2174    }
2175
2176    public ObjectName createDuplexNetworkConnectorObjectName(String transport) throws MalformedObjectNameException {
2177        return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "duplexNetworkConnectors", transport);
2178    }
2179
2180    protected void unregisterNetworkConnectorMBean(NetworkConnector connector) {
2181        if (isUseJmx()) {
2182            try {
2183                ObjectName objectName = createNetworkConnectorObjectName(connector);
2184                getManagementContext().unregisterMBean(objectName);
2185            } catch (Exception e) {
2186                LOG.warn("Network Connector could not be unregistered from JMX due " + e.getMessage() + ". This exception is ignored.", e);
2187            }
2188        }
2189    }
2190
2191    protected void registerProxyConnectorMBean(ProxyConnector connector) throws IOException {
2192        ProxyConnectorView view = new ProxyConnectorView(connector);
2193        try {
2194            ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "proxyConnectors", connector.getName());
2195            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2196        } catch (Throwable e) {
2197            throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e);
2198        }
2199    }
2200
2201    protected void registerJmsConnectorMBean(JmsConnector connector) throws IOException {
2202        JmsConnectorView view = new JmsConnectorView(connector);
2203        try {
2204            ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "jmsConnectors", connector.getName());
2205            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2206        } catch (Throwable e) {
2207            throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e);
2208        }
2209    }
2210
2211    /**
2212     * Factory method to create a new broker
2213     *
2214     * @throws Exception
2215     * @throws
2216     * @throws
2217     */
2218    protected Broker createBroker() throws Exception {
2219        regionBroker = createRegionBroker();
2220        Broker broker = addInterceptors(regionBroker);
2221        // Add a filter that will stop access to the broker once stopped
2222        broker = new MutableBrokerFilter(broker) {
2223            Broker old;
2224
2225            @Override
2226            public void stop() throws Exception {
2227                old = this.next.getAndSet(new ErrorBroker("Broker has been stopped: " + this) {
2228                    // Just ignore additional stop actions.
2229                    @Override
2230                    public void stop() throws Exception {
2231                    }
2232                });
2233                old.stop();
2234            }
2235
2236            @Override
2237            public void start() throws Exception {
2238                if (forceStart && old != null) {
2239                    this.next.set(old);
2240                }
2241                getNext().start();
2242            }
2243        };
2244        return broker;
2245    }
2246
2247    /**
2248     * Factory method to create the core region broker onto which interceptors
2249     * are added
2250     *
2251     * @throws Exception
2252     */
2253    protected Broker createRegionBroker() throws Exception {
2254        if (destinationInterceptors == null) {
2255            destinationInterceptors = createDefaultDestinationInterceptor();
2256        }
2257        configureServices(destinationInterceptors);
2258        DestinationInterceptor destinationInterceptor = new CompositeDestinationInterceptor(destinationInterceptors);
2259        if (destinationFactory == null) {
2260            destinationFactory = new DestinationFactoryImpl(this, getTaskRunnerFactory(), getPersistenceAdapter());
2261        }
2262        return createRegionBroker(destinationInterceptor);
2263    }
2264
2265    protected Broker createRegionBroker(DestinationInterceptor destinationInterceptor) throws IOException {
2266        RegionBroker regionBroker;
2267        if (isUseJmx()) {
2268            try {
2269                regionBroker = new ManagedRegionBroker(this, getManagementContext(), getBrokerObjectName(),
2270                    getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory, destinationInterceptor,getScheduler(),getExecutor());
2271            } catch(MalformedObjectNameException me){
2272                LOG.warn("Cannot create ManagedRegionBroker due " + me.getMessage(), me);
2273                throw new IOException(me);
2274            }
2275        } else {
2276            regionBroker = new RegionBroker(this, getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory,
2277                    destinationInterceptor,getScheduler(),getExecutor());
2278        }
2279        destinationFactory.setRegionBroker(regionBroker);
2280        regionBroker.setKeepDurableSubsActive(keepDurableSubsActive);
2281        regionBroker.setBrokerName(getBrokerName());
2282        regionBroker.getDestinationStatistics().setEnabled(enableStatistics);
2283        regionBroker.setAllowTempAutoCreationOnSend(isAllowTempAutoCreationOnSend());
2284        if (brokerId != null) {
2285            regionBroker.setBrokerId(brokerId);
2286        }
2287        return regionBroker;
2288    }
2289
2290    /**
2291     * Create the default destination interceptor
2292     */
2293    protected DestinationInterceptor[] createDefaultDestinationInterceptor() {
2294        List<DestinationInterceptor> answer = new ArrayList<DestinationInterceptor>();
2295        if (isUseVirtualTopics()) {
2296            VirtualDestinationInterceptor interceptor = new VirtualDestinationInterceptor();
2297            VirtualTopic virtualTopic = new VirtualTopic();
2298            virtualTopic.setName("VirtualTopic.>");
2299            VirtualDestination[] virtualDestinations = { virtualTopic };
2300            interceptor.setVirtualDestinations(virtualDestinations);
2301            answer.add(interceptor);
2302        }
2303        if (isUseMirroredQueues()) {
2304            MirroredQueue interceptor = new MirroredQueue();
2305            answer.add(interceptor);
2306        }
2307        DestinationInterceptor[] array = new DestinationInterceptor[answer.size()];
2308        answer.toArray(array);
2309        return array;
2310    }
2311
2312    /**
2313     * Strategy method to add interceptors to the broker
2314     *
2315     * @throws IOException
2316     */
2317    protected Broker addInterceptors(Broker broker) throws Exception {
2318        if (isSchedulerSupport()) {
2319            SchedulerBroker sb = new SchedulerBroker(this, broker, getJobSchedulerStore());
2320            if (isUseJmx()) {
2321                JobSchedulerViewMBean view = new JobSchedulerView(sb.getJobScheduler());
2322                try {
2323                    ObjectName objectName = BrokerMBeanSupport.createJobSchedulerServiceName(getBrokerObjectName());
2324                    AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2325                    this.adminView.setJMSJobScheduler(objectName);
2326                } catch (Throwable e) {
2327                    throw IOExceptionSupport.create("JobScheduler could not be registered in JMX: "
2328                            + e.getMessage(), e);
2329                }
2330            }
2331            broker = sb;
2332        }
2333        if (isUseJmx()) {
2334            HealthViewMBean statusView = new HealthView((ManagedRegionBroker)getRegionBroker());
2335            try {
2336                ObjectName objectName = BrokerMBeanSupport.createHealthServiceName(getBrokerObjectName());
2337                AnnotatedMBean.registerMBean(getManagementContext(), statusView, objectName);
2338            } catch (Throwable e) {
2339                throw IOExceptionSupport.create("Status MBean could not be registered in JMX: "
2340                        + e.getMessage(), e);
2341            }
2342        }
2343        if (isAdvisorySupport()) {
2344            broker = new AdvisoryBroker(broker);
2345        }
2346        broker = new CompositeDestinationBroker(broker);
2347        broker = new TransactionBroker(broker, getPersistenceAdapter().createTransactionStore());
2348        if (isPopulateJMSXUserID()) {
2349            UserIDBroker userIDBroker = new UserIDBroker(broker);
2350            userIDBroker.setUseAuthenticatePrincipal(isUseAuthenticatedPrincipalForJMSXUserID());
2351            broker = userIDBroker;
2352        }
2353        if (isMonitorConnectionSplits()) {
2354            broker = new ConnectionSplitBroker(broker);
2355        }
2356        if (plugins != null) {
2357            for (int i = 0; i < plugins.length; i++) {
2358                BrokerPlugin plugin = plugins[i];
2359                broker = plugin.installPlugin(broker);
2360            }
2361        }
2362        return broker;
2363    }
2364
2365    protected PersistenceAdapter createPersistenceAdapter() throws IOException {
2366        if (isPersistent()) {
2367            PersistenceAdapterFactory fac = getPersistenceFactory();
2368            if (fac != null) {
2369                return fac.createPersistenceAdapter();
2370            } else {
2371                try {
2372                    String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter";
2373                    PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance();
2374                    File dir = new File(getBrokerDataDirectory(),"KahaDB");
2375                    adaptor.setDirectory(dir);
2376                    return adaptor;
2377                } catch (Throwable e) {
2378                    throw IOExceptionSupport.create(e);
2379                }
2380            }
2381        } else {
2382            return new MemoryPersistenceAdapter();
2383        }
2384    }
2385
2386    protected ObjectName createBrokerObjectName() throws MalformedObjectNameException  {
2387        return BrokerMBeanSupport.createBrokerObjectName(getManagementContext().getJmxDomainName(), getBrokerName());
2388    }
2389
2390    protected TransportConnector createTransportConnector(URI brokerURI) throws Exception {
2391        TransportServer transport = TransportFactorySupport.bind(this, brokerURI);
2392        return new TransportConnector(transport);
2393    }
2394
2395    /**
2396     * Extracts the port from the options
2397     */
2398    protected Object getPort(Map<?,?> options) {
2399        Object port = options.get("port");
2400        if (port == null) {
2401            port = DEFAULT_PORT;
2402            LOG.warn("No port specified so defaulting to: {}", port);
2403        }
2404        return port;
2405    }
2406
2407    protected void addShutdownHook() {
2408        if (useShutdownHook) {
2409            shutdownHook = new Thread("ActiveMQ ShutdownHook") {
2410                @Override
2411                public void run() {
2412                    containerShutdown();
2413                }
2414            };
2415            Runtime.getRuntime().addShutdownHook(shutdownHook);
2416        }
2417    }
2418
2419    protected void removeShutdownHook() {
2420        if (shutdownHook != null) {
2421            try {
2422                Runtime.getRuntime().removeShutdownHook(shutdownHook);
2423            } catch (Exception e) {
2424                LOG.debug("Caught exception, must be shutting down. This exception is ignored.", e);
2425            }
2426        }
2427    }
2428
2429    /**
2430     * Sets hooks to be executed when broker shut down
2431     *
2432     * @org.apache.xbean.Property
2433     */
2434    public void setShutdownHooks(List<Runnable> hooks) throws Exception {
2435        for (Runnable hook : hooks) {
2436            addShutdownHook(hook);
2437        }
2438    }
2439
2440    /**
2441     * Causes a clean shutdown of the container when the VM is being shut down
2442     */
2443    protected void containerShutdown() {
2444        try {
2445            stop();
2446        } catch (IOException e) {
2447            Throwable linkedException = e.getCause();
2448            if (linkedException != null) {
2449                logError("Failed to shut down: " + e + ". Reason: " + linkedException, linkedException);
2450            } else {
2451                logError("Failed to shut down: " + e, e);
2452            }
2453            if (!useLoggingForShutdownErrors) {
2454                e.printStackTrace(System.err);
2455            }
2456        } catch (Exception e) {
2457            logError("Failed to shut down: " + e, e);
2458        }
2459    }
2460
2461    protected void logError(String message, Throwable e) {
2462        if (useLoggingForShutdownErrors) {
2463            LOG.error("Failed to shut down: " + e);
2464        } else {
2465            System.err.println("Failed to shut down: " + e);
2466        }
2467    }
2468
2469    /**
2470     * Starts any configured destinations on startup
2471     */
2472    protected void startDestinations() throws Exception {
2473        if (destinations != null) {
2474            ConnectionContext adminConnectionContext = getAdminConnectionContext();
2475            for (int i = 0; i < destinations.length; i++) {
2476                ActiveMQDestination destination = destinations[i];
2477                getBroker().addDestination(adminConnectionContext, destination,true);
2478            }
2479        }
2480        if (isUseVirtualTopics()) {
2481            startVirtualConsumerDestinations();
2482        }
2483    }
2484
2485    /**
2486     * Returns the broker's administration connection context used for
2487     * configuring the broker at startup
2488     */
2489    public ConnectionContext getAdminConnectionContext() throws Exception {
2490        return BrokerSupport.getConnectionContext(getBroker());
2491    }
2492
2493    protected void startManagementContext() throws Exception {
2494        getManagementContext().setBrokerName(brokerName);
2495        getManagementContext().start();
2496        adminView = new BrokerView(this, null);
2497        ObjectName objectName = getBrokerObjectName();
2498        AnnotatedMBean.registerMBean(getManagementContext(), adminView, objectName);
2499    }
2500
2501    /**
2502     * Start all transport and network connections, proxies and bridges
2503     *
2504     * @throws Exception
2505     */
2506    public void startAllConnectors() throws Exception {
2507        Set<ActiveMQDestination> durableDestinations = getBroker().getDurableDestinations();
2508        List<TransportConnector> al = new ArrayList<TransportConnector>();
2509        for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) {
2510            TransportConnector connector = iter.next();
2511            al.add(startTransportConnector(connector));
2512        }
2513        if (al.size() > 0) {
2514            // let's clear the transportConnectors list and replace it with
2515            // the started transportConnector instances
2516            this.transportConnectors.clear();
2517            setTransportConnectors(al);
2518        }
2519        this.slave = false;
2520        URI uri = getVmConnectorURI();
2521        Map<String, String> map = new HashMap<String, String>(URISupport.parseParameters(uri));
2522        map.put("network", "true");
2523        map.put("async", "false");
2524        map.put("create","false");
2525        uri = URISupport.createURIWithQuery(uri, URISupport.createQueryString(map));
2526
2527        if (!stopped.get()) {
2528            ThreadPoolExecutor networkConnectorStartExecutor = null;
2529            if (isNetworkConnectorStartAsync()) {
2530                // spin up as many threads as needed
2531                networkConnectorStartExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
2532                    10, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
2533                    new ThreadFactory() {
2534                        int count=0;
2535                        @Override
2536                        public Thread newThread(Runnable runnable) {
2537                            Thread thread = new Thread(runnable, "NetworkConnector Start Thread-" +(count++));
2538                            thread.setDaemon(true);
2539                            return thread;
2540                        }
2541                    });
2542            }
2543
2544            for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) {
2545                final NetworkConnector connector = iter.next();
2546                connector.setLocalUri(uri);
2547                connector.setBrokerName(getBrokerName());
2548                connector.setDurableDestinations(durableDestinations);
2549                if (getDefaultSocketURIString() != null) {
2550                    connector.setBrokerURL(getDefaultSocketURIString());
2551                }
2552                if (networkConnectorStartExecutor != null) {
2553                    networkConnectorStartExecutor.execute(new Runnable() {
2554                        @Override
2555                        public void run() {
2556                            try {
2557                                LOG.info("Async start of {}", connector);
2558                                connector.start();
2559                            } catch(Exception e) {
2560                                LOG.error("Async start of network connector: {} failed", connector, e);
2561                            }
2562                        }
2563                    });
2564                } else {
2565                    connector.start();
2566                }
2567            }
2568            if (networkConnectorStartExecutor != null) {
2569                // executor done when enqueued tasks are complete
2570                ThreadPoolUtils.shutdown(networkConnectorStartExecutor);
2571            }
2572
2573            for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) {
2574                ProxyConnector connector = iter.next();
2575                connector.start();
2576            }
2577            for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) {
2578                JmsConnector connector = iter.next();
2579                connector.start();
2580            }
2581            for (Service service : services) {
2582                configureService(service);
2583                service.start();
2584            }
2585        }
2586    }
2587
2588    public TransportConnector startTransportConnector(TransportConnector connector) throws Exception {
2589        connector.setBrokerService(this);
2590        connector.setTaskRunnerFactory(getTaskRunnerFactory());
2591        MessageAuthorizationPolicy policy = getMessageAuthorizationPolicy();
2592        if (policy != null) {
2593            connector.setMessageAuthorizationPolicy(policy);
2594        }
2595        if (isUseJmx()) {
2596            connector = registerConnectorMBean(connector);
2597        }
2598        connector.getStatistics().setEnabled(enableStatistics);
2599        connector.start();
2600        return connector;
2601    }
2602
2603    /**
2604     * Perform any custom dependency injection
2605     */
2606    protected void configureServices(Object[] services) {
2607        for (Object service : services) {
2608            configureService(service);
2609        }
2610    }
2611
2612    /**
2613     * Perform any custom dependency injection
2614     */
2615    protected void configureService(Object service) {
2616        if (service instanceof BrokerServiceAware) {
2617            BrokerServiceAware serviceAware = (BrokerServiceAware) service;
2618            serviceAware.setBrokerService(this);
2619        }
2620    }
2621
2622    public void handleIOException(IOException exception) {
2623        if (ioExceptionHandler != null) {
2624            ioExceptionHandler.handle(exception);
2625         } else {
2626            LOG.info("No IOExceptionHandler registered, ignoring IO exception", exception);
2627         }
2628    }
2629
2630    protected void startVirtualConsumerDestinations() throws Exception {
2631        checkStartException();
2632        ConnectionContext adminConnectionContext = getAdminConnectionContext();
2633        Set<ActiveMQDestination> destinations = destinationFactory.getDestinations();
2634        DestinationFilter filter = getVirtualTopicConsumerDestinationFilter();
2635        if (!destinations.isEmpty()) {
2636            for (ActiveMQDestination destination : destinations) {
2637                if (filter.matches(destination) == true) {
2638                    broker.addDestination(adminConnectionContext, destination, false);
2639                }
2640            }
2641        }
2642    }
2643
2644    private DestinationFilter getVirtualTopicConsumerDestinationFilter() {
2645        // created at startup, so no sync needed
2646        if (virtualConsumerDestinationFilter == null) {
2647            Set <ActiveMQQueue> consumerDestinations = new HashSet<ActiveMQQueue>();
2648            if (destinationInterceptors != null) {
2649                for (DestinationInterceptor interceptor : destinationInterceptors) {
2650                    if (interceptor instanceof VirtualDestinationInterceptor) {
2651                        VirtualDestinationInterceptor virtualDestinationInterceptor = (VirtualDestinationInterceptor) interceptor;
2652                        for (VirtualDestination virtualDestination: virtualDestinationInterceptor.getVirtualDestinations()) {
2653                            if (virtualDestination instanceof VirtualTopic) {
2654                                consumerDestinations.add(new ActiveMQQueue(((VirtualTopic) virtualDestination).getPrefix() + DestinationFilter.ANY_DESCENDENT));
2655                            }
2656                        }
2657                    }
2658                }
2659            }
2660            ActiveMQQueue filter = new ActiveMQQueue();
2661            filter.setCompositeDestinations(consumerDestinations.toArray(new ActiveMQDestination[]{}));
2662            virtualConsumerDestinationFilter = DestinationFilter.parseFilter(filter);
2663        }
2664        return virtualConsumerDestinationFilter;
2665    }
2666
2667    protected synchronized ThreadPoolExecutor getExecutor() {
2668        if (this.executor == null) {
2669            this.executor = new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
2670
2671                private long i = 0;
2672
2673                @Override
2674                public Thread newThread(Runnable runnable) {
2675                    this.i++;
2676                    Thread thread = new Thread(runnable, "ActiveMQ BrokerService.worker." + this.i);
2677                    thread.setDaemon(true);
2678                    thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
2679                        @Override
2680                        public void uncaughtException(final Thread t, final Throwable e) {
2681                            LOG.error("Error in thread '{}'", t.getName(), e);
2682                        }
2683                    });
2684                    return thread;
2685                }
2686            }, new RejectedExecutionHandler() {
2687                @Override
2688                public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
2689                    try {
2690                        executor.getQueue().offer(r, 60, TimeUnit.SECONDS);
2691                    } catch (InterruptedException e) {
2692                        throw new RejectedExecutionException("Interrupted waiting for BrokerService.worker");
2693                    }
2694
2695                    throw new RejectedExecutionException("Timed Out while attempting to enqueue Task.");
2696                }
2697            });
2698        }
2699        return this.executor;
2700    }
2701
2702    public synchronized Scheduler getScheduler() {
2703        if (this.scheduler==null) {
2704            this.scheduler = new Scheduler("ActiveMQ Broker["+getBrokerName()+"] Scheduler");
2705            try {
2706                this.scheduler.start();
2707            } catch (Exception e) {
2708               LOG.error("Failed to start Scheduler", e);
2709            }
2710        }
2711        return this.scheduler;
2712    }
2713
2714    public Broker getRegionBroker() {
2715        return regionBroker;
2716    }
2717
2718    public void setRegionBroker(Broker regionBroker) {
2719        this.regionBroker = regionBroker;
2720    }
2721
2722    public void addShutdownHook(Runnable hook) {
2723        synchronized (shutdownHooks) {
2724            shutdownHooks.add(hook);
2725        }
2726    }
2727
2728    public void removeShutdownHook(Runnable hook) {
2729        synchronized (shutdownHooks) {
2730            shutdownHooks.remove(hook);
2731        }
2732    }
2733
2734    public boolean isSystemExitOnShutdown() {
2735        return systemExitOnShutdown;
2736    }
2737
2738    /**
2739     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2740     */
2741    public void setSystemExitOnShutdown(boolean systemExitOnShutdown) {
2742        this.systemExitOnShutdown = systemExitOnShutdown;
2743    }
2744
2745    public int getSystemExitOnShutdownExitCode() {
2746        return systemExitOnShutdownExitCode;
2747    }
2748
2749    public void setSystemExitOnShutdownExitCode(int systemExitOnShutdownExitCode) {
2750        this.systemExitOnShutdownExitCode = systemExitOnShutdownExitCode;
2751    }
2752
2753    public SslContext getSslContext() {
2754        return sslContext;
2755    }
2756
2757    public void setSslContext(SslContext sslContext) {
2758        this.sslContext = sslContext;
2759    }
2760
2761    public boolean isShutdownOnSlaveFailure() {
2762        return shutdownOnSlaveFailure;
2763    }
2764
2765    /**
2766     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2767     */
2768    public void setShutdownOnSlaveFailure(boolean shutdownOnSlaveFailure) {
2769        this.shutdownOnSlaveFailure = shutdownOnSlaveFailure;
2770    }
2771
2772    public boolean isWaitForSlave() {
2773        return waitForSlave;
2774    }
2775
2776    /**
2777     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2778     */
2779    public void setWaitForSlave(boolean waitForSlave) {
2780        this.waitForSlave = waitForSlave;
2781    }
2782
2783    public long getWaitForSlaveTimeout() {
2784        return this.waitForSlaveTimeout;
2785    }
2786
2787    public void setWaitForSlaveTimeout(long waitForSlaveTimeout) {
2788        this.waitForSlaveTimeout = waitForSlaveTimeout;
2789    }
2790
2791    /**
2792     * Get the passiveSlave
2793     * @return the passiveSlave
2794     */
2795    public boolean isPassiveSlave() {
2796        return this.passiveSlave;
2797    }
2798
2799    /**
2800     * Set the passiveSlave
2801     * @param passiveSlave the passiveSlave to set
2802     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2803     */
2804    public void setPassiveSlave(boolean passiveSlave) {
2805        this.passiveSlave = passiveSlave;
2806    }
2807
2808    /**
2809     * override the Default IOException handler, called when persistence adapter
2810     * has experiences File or JDBC I/O Exceptions
2811     *
2812     * @param ioExceptionHandler
2813     */
2814    public void setIoExceptionHandler(IOExceptionHandler ioExceptionHandler) {
2815        configureService(ioExceptionHandler);
2816        this.ioExceptionHandler = ioExceptionHandler;
2817    }
2818
2819    public IOExceptionHandler getIoExceptionHandler() {
2820        return ioExceptionHandler;
2821    }
2822
2823    /**
2824     * @return the schedulerSupport
2825     */
2826    public boolean isSchedulerSupport() {
2827        return this.schedulerSupport;
2828    }
2829
2830    /**
2831     * @param schedulerSupport the schedulerSupport to set
2832     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2833     */
2834    public void setSchedulerSupport(boolean schedulerSupport) {
2835        this.schedulerSupport = schedulerSupport;
2836    }
2837
2838    /**
2839     * @return the schedulerDirectory
2840     */
2841    public File getSchedulerDirectoryFile() {
2842        if (this.schedulerDirectoryFile == null) {
2843            this.schedulerDirectoryFile = new File(getBrokerDataDirectory(), "scheduler");
2844        }
2845        return schedulerDirectoryFile;
2846    }
2847
2848    /**
2849     * @param schedulerDirectory the schedulerDirectory to set
2850     */
2851    public void setSchedulerDirectoryFile(File schedulerDirectory) {
2852        this.schedulerDirectoryFile = schedulerDirectory;
2853    }
2854
2855    public void setSchedulerDirectory(String schedulerDirectory) {
2856        setSchedulerDirectoryFile(new File(schedulerDirectory));
2857    }
2858
2859    public int getSchedulePeriodForDestinationPurge() {
2860        return this.schedulePeriodForDestinationPurge;
2861    }
2862
2863    public void setSchedulePeriodForDestinationPurge(int schedulePeriodForDestinationPurge) {
2864        this.schedulePeriodForDestinationPurge = schedulePeriodForDestinationPurge;
2865    }
2866
2867    public int getMaxPurgedDestinationsPerSweep() {
2868        return this.maxPurgedDestinationsPerSweep;
2869    }
2870
2871    public void setMaxPurgedDestinationsPerSweep(int maxPurgedDestinationsPerSweep) {
2872        this.maxPurgedDestinationsPerSweep = maxPurgedDestinationsPerSweep;
2873    }
2874
2875    public BrokerContext getBrokerContext() {
2876        return brokerContext;
2877    }
2878
2879    public void setBrokerContext(BrokerContext brokerContext) {
2880        this.brokerContext = brokerContext;
2881    }
2882
2883    public void setBrokerId(String brokerId) {
2884        this.brokerId = new BrokerId(brokerId);
2885    }
2886
2887    public boolean isUseAuthenticatedPrincipalForJMSXUserID() {
2888        return useAuthenticatedPrincipalForJMSXUserID;
2889    }
2890
2891    public void setUseAuthenticatedPrincipalForJMSXUserID(boolean useAuthenticatedPrincipalForJMSXUserID) {
2892        this.useAuthenticatedPrincipalForJMSXUserID = useAuthenticatedPrincipalForJMSXUserID;
2893    }
2894
2895    /**
2896     * Should MBeans that support showing the Authenticated User Name information have this
2897     * value filled in or not.
2898     *
2899     * @return true if user names should be exposed in MBeans
2900     */
2901    public boolean isPopulateUserNameInMBeans() {
2902        return this.populateUserNameInMBeans;
2903    }
2904
2905    /**
2906     * Sets whether Authenticated User Name information is shown in MBeans that support this field.
2907     * @param value if MBeans should expose user name information.
2908     */
2909    public void setPopulateUserNameInMBeans(boolean value) {
2910        this.populateUserNameInMBeans = value;
2911    }
2912
2913    /**
2914     * Gets the time in Milliseconds that an invocation of an MBean method will wait before
2915     * failing.  The default value is to wait forever (zero).
2916     *
2917     * @return timeout in milliseconds before MBean calls fail, (default is 0 or no timeout).
2918     */
2919    public long getMbeanInvocationTimeout() {
2920        return mbeanInvocationTimeout;
2921    }
2922
2923    /**
2924     * Gets the time in Milliseconds that an invocation of an MBean method will wait before
2925     * failing. The default value is to wait forever (zero).
2926     *
2927     * @param mbeanInvocationTimeout
2928     *      timeout in milliseconds before MBean calls fail, (default is 0 or no timeout).
2929     */
2930    public void setMbeanInvocationTimeout(long mbeanInvocationTimeout) {
2931        this.mbeanInvocationTimeout = mbeanInvocationTimeout;
2932    }
2933
2934    public boolean isNetworkConnectorStartAsync() {
2935        return networkConnectorStartAsync;
2936    }
2937
2938    public void setNetworkConnectorStartAsync(boolean networkConnectorStartAsync) {
2939        this.networkConnectorStartAsync = networkConnectorStartAsync;
2940    }
2941
2942    public boolean isAllowTempAutoCreationOnSend() {
2943        return allowTempAutoCreationOnSend;
2944    }
2945
2946    /**
2947     * enable if temp destinations need to be propagated through a network when
2948     * advisorySupport==false. This is used in conjunction with the policy
2949     * gcInactiveDestinations for matching temps so they can get removed
2950     * when inactive
2951     *
2952     * @param allowTempAutoCreationOnSend
2953     */
2954    public void setAllowTempAutoCreationOnSend(boolean allowTempAutoCreationOnSend) {
2955        this.allowTempAutoCreationOnSend = allowTempAutoCreationOnSend;
2956    }
2957
2958    public long getOfflineDurableSubscriberTimeout() {
2959        return offlineDurableSubscriberTimeout;
2960    }
2961
2962    public void setOfflineDurableSubscriberTimeout(long offlineDurableSubscriberTimeout) {
2963        this.offlineDurableSubscriberTimeout = offlineDurableSubscriberTimeout;
2964    }
2965
2966    public long getOfflineDurableSubscriberTaskSchedule() {
2967        return offlineDurableSubscriberTaskSchedule;
2968    }
2969
2970    public void setOfflineDurableSubscriberTaskSchedule(long offlineDurableSubscriberTaskSchedule) {
2971        this.offlineDurableSubscriberTaskSchedule = offlineDurableSubscriberTaskSchedule;
2972    }
2973
2974    public boolean shouldRecordVirtualDestination(ActiveMQDestination destination) {
2975        return isUseVirtualTopics() && destination.isQueue() &&
2976               getVirtualTopicConsumerDestinationFilter().matches(destination);
2977    }
2978
2979    synchronized public Throwable getStartException() {
2980        return startException;
2981    }
2982
2983    public boolean isStartAsync() {
2984        return startAsync;
2985    }
2986
2987    public void setStartAsync(boolean startAsync) {
2988        this.startAsync = startAsync;
2989    }
2990
2991    public boolean isSlave() {
2992        return this.slave;
2993    }
2994
2995    public boolean isStopping() {
2996        return this.stopping.get();
2997    }
2998
2999    /**
3000     * @return true if the broker allowed to restart on shutdown.
3001     */
3002    public boolean isRestartAllowed() {
3003        return restartAllowed;
3004    }
3005
3006    /**
3007     * Sets if the broker allowed to restart on shutdown.
3008     * @return
3009     */
3010    public void setRestartAllowed(boolean restartAllowed) {
3011        this.restartAllowed = restartAllowed;
3012    }
3013
3014    /**
3015     * A lifecycle manager of the BrokerService should
3016     * inspect this property after a broker shutdown has occurred
3017     * to find out if the broker needs to be re-created and started
3018     * again.
3019     *
3020     * @return true if the broker wants to be restarted after it shuts down.
3021     */
3022    public boolean isRestartRequested() {
3023        return restartRequested;
3024    }
3025
3026    public void requestRestart() {
3027        this.restartRequested = true;
3028    }
3029
3030    public int getStoreOpenWireVersion() {
3031        return storeOpenWireVersion;
3032    }
3033
3034    public void setStoreOpenWireVersion(int storeOpenWireVersion) {
3035        this.storeOpenWireVersion = storeOpenWireVersion;
3036    }
3037
3038    /**
3039     * @return the current number of connections on this Broker.
3040     */
3041    public int getCurrentConnections() {
3042        return this.currentConnections.get();
3043    }
3044
3045    /**
3046     * @return the total number of connections this broker has handled since startup.
3047     */
3048    public long getTotalConnections() {
3049        return this.totalConnections.get();
3050    }
3051
3052    public void incrementCurrentConnections() {
3053        this.currentConnections.incrementAndGet();
3054    }
3055
3056    public void decrementCurrentConnections() {
3057        this.currentConnections.decrementAndGet();
3058    }
3059
3060    public void incrementTotalConnections() {
3061        this.totalConnections.incrementAndGet();
3062    }
3063
3064    public boolean isRejectDurableConsumers() {
3065        return rejectDurableConsumers;
3066    }
3067
3068    public void setRejectDurableConsumers(boolean rejectDurableConsumers) {
3069        this.rejectDurableConsumers = rejectDurableConsumers;
3070    }
3071
3072    public void setRollbackOnlyOnAsyncException(boolean rollbackOnlyOnAsyncException) {
3073        this.rollbackOnlyOnAsyncException = rollbackOnlyOnAsyncException;
3074    }
3075
3076    public boolean isRollbackOnlyOnAsyncException() {
3077        return rollbackOnlyOnAsyncException;
3078    }
3079}