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