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