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