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