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 (ClassNotFoundException e) {
1791                throw new RuntimeException("Kahadb class PListStoreImpl not found. Add activemq-kahadb jar or set persistent to false on BrokerService.", e);
1792            } catch (Exception e) {
1793                throw new RuntimeException(e);
1794            }
1795        }
1796        return tempDataStore;
1797    }
1798
1799    /**
1800     * @param tempDataStore
1801     *            the tempDataStore to set
1802     */
1803    public void setTempDataStore(PListStore tempDataStore) {
1804        this.tempDataStore = tempDataStore;
1805        if (tempDataStore != null) {
1806            if (tmpDataDirectory == null) {
1807                tmpDataDirectory = tempDataStore.getDirectory();
1808            } else if (tempDataStore.getDirectory() == null) {
1809                tempDataStore.setDirectory(tmpDataDirectory);
1810            }
1811        }
1812        configureService(tempDataStore);
1813    }
1814
1815    public int getPersistenceThreadPriority() {
1816        return persistenceThreadPriority;
1817    }
1818
1819    public void setPersistenceThreadPriority(int persistenceThreadPriority) {
1820        this.persistenceThreadPriority = persistenceThreadPriority;
1821    }
1822
1823    /**
1824     * @return the useLocalHostBrokerName
1825     */
1826    public boolean isUseLocalHostBrokerName() {
1827        return this.useLocalHostBrokerName;
1828    }
1829
1830    /**
1831     * @param useLocalHostBrokerName
1832     *            the useLocalHostBrokerName to set
1833     */
1834    public void setUseLocalHostBrokerName(boolean useLocalHostBrokerName) {
1835        this.useLocalHostBrokerName = useLocalHostBrokerName;
1836        if (useLocalHostBrokerName && !started.get() && brokerName == null || brokerName == DEFAULT_BROKER_NAME) {
1837            brokerName = LOCAL_HOST_NAME;
1838        }
1839    }
1840
1841    /**
1842     * Looks up and lazily creates if necessary the destination for the given
1843     * JMS name
1844     */
1845    public Destination getDestination(ActiveMQDestination destination) throws Exception {
1846        return getBroker().addDestination(getAdminConnectionContext(), destination,false);
1847    }
1848
1849    public void removeDestination(ActiveMQDestination destination) throws Exception {
1850        getBroker().removeDestination(getAdminConnectionContext(), destination, 0);
1851    }
1852
1853    public int getProducerSystemUsagePortion() {
1854        return producerSystemUsagePortion;
1855    }
1856
1857    public void setProducerSystemUsagePortion(int producerSystemUsagePortion) {
1858        this.producerSystemUsagePortion = producerSystemUsagePortion;
1859    }
1860
1861    public int getConsumerSystemUsagePortion() {
1862        return consumerSystemUsagePortion;
1863    }
1864
1865    public void setConsumerSystemUsagePortion(int consumerSystemUsagePortion) {
1866        this.consumerSystemUsagePortion = consumerSystemUsagePortion;
1867    }
1868
1869    public boolean isSplitSystemUsageForProducersConsumers() {
1870        return splitSystemUsageForProducersConsumers;
1871    }
1872
1873    public void setSplitSystemUsageForProducersConsumers(boolean splitSystemUsageForProducersConsumers) {
1874        this.splitSystemUsageForProducersConsumers = splitSystemUsageForProducersConsumers;
1875    }
1876
1877    public boolean isMonitorConnectionSplits() {
1878        return monitorConnectionSplits;
1879    }
1880
1881    public void setMonitorConnectionSplits(boolean monitorConnectionSplits) {
1882        this.monitorConnectionSplits = monitorConnectionSplits;
1883    }
1884
1885    public int getTaskRunnerPriority() {
1886        return taskRunnerPriority;
1887    }
1888
1889    public void setTaskRunnerPriority(int taskRunnerPriority) {
1890        this.taskRunnerPriority = taskRunnerPriority;
1891    }
1892
1893    public boolean isDedicatedTaskRunner() {
1894        return dedicatedTaskRunner;
1895    }
1896
1897    public void setDedicatedTaskRunner(boolean dedicatedTaskRunner) {
1898        this.dedicatedTaskRunner = dedicatedTaskRunner;
1899    }
1900
1901    public boolean isCacheTempDestinations() {
1902        return cacheTempDestinations;
1903    }
1904
1905    public void setCacheTempDestinations(boolean cacheTempDestinations) {
1906        this.cacheTempDestinations = cacheTempDestinations;
1907    }
1908
1909    public int getTimeBeforePurgeTempDestinations() {
1910        return timeBeforePurgeTempDestinations;
1911    }
1912
1913    public void setTimeBeforePurgeTempDestinations(int timeBeforePurgeTempDestinations) {
1914        this.timeBeforePurgeTempDestinations = timeBeforePurgeTempDestinations;
1915    }
1916
1917    public boolean isUseTempMirroredQueues() {
1918        return useTempMirroredQueues;
1919    }
1920
1921    public void setUseTempMirroredQueues(boolean useTempMirroredQueues) {
1922        this.useTempMirroredQueues = useTempMirroredQueues;
1923    }
1924
1925    public synchronized JobSchedulerStore getJobSchedulerStore() {
1926
1927        // If support is off don't allow any scheduler even is user configured their own.
1928        if (!isSchedulerSupport()) {
1929            return null;
1930        }
1931
1932        // If the user configured their own we use it even if persistence is disabled since
1933        // we don't know anything about their implementation.
1934        if (jobSchedulerStore == null) {
1935
1936            if (!isPersistent()) {
1937                this.jobSchedulerStore = new InMemoryJobSchedulerStore();
1938                configureService(jobSchedulerStore);
1939                return this.jobSchedulerStore;
1940            }
1941
1942            try {
1943                PersistenceAdapter pa = getPersistenceAdapter();
1944                if (pa != null) {
1945                    this.jobSchedulerStore = pa.createJobSchedulerStore();
1946                    jobSchedulerStore.setDirectory(getSchedulerDirectoryFile());
1947                    configureService(jobSchedulerStore);
1948                    return this.jobSchedulerStore;
1949                }
1950            } catch (IOException e) {
1951                throw new RuntimeException(e);
1952            } catch (UnsupportedOperationException ex) {
1953                // It's ok if the store doesn't implement a scheduler.
1954            } catch (Exception e) {
1955                throw new RuntimeException(e);
1956            }
1957
1958            try {
1959                PersistenceAdapter pa = getPersistenceAdapter();
1960                if (pa != null && pa instanceof JobSchedulerStore) {
1961                    this.jobSchedulerStore = (JobSchedulerStore) pa;
1962                    configureService(jobSchedulerStore);
1963                    return this.jobSchedulerStore;
1964                }
1965            } catch (IOException e) {
1966                throw new RuntimeException(e);
1967            }
1968
1969            // Load the KahaDB store as a last resort, this only works if KahaDB is
1970            // included at runtime, otherwise this will fail.  User should disable
1971            // scheduler support if this fails.
1972            try {
1973                String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter";
1974                PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance();
1975                jobSchedulerStore = adaptor.createJobSchedulerStore();
1976                jobSchedulerStore.setDirectory(getSchedulerDirectoryFile());
1977                configureService(jobSchedulerStore);
1978                LOG.info("JobScheduler using directory: {}", getSchedulerDirectoryFile());
1979            } catch (Exception e) {
1980                throw new RuntimeException(e);
1981            }
1982        }
1983        return jobSchedulerStore;
1984    }
1985
1986    public void setJobSchedulerStore(JobSchedulerStore jobSchedulerStore) {
1987        this.jobSchedulerStore = jobSchedulerStore;
1988        configureService(jobSchedulerStore);
1989    }
1990
1991    //
1992    // Implementation methods
1993    // -------------------------------------------------------------------------
1994    /**
1995     * Handles any lazy-creation helper properties which are added to make
1996     * things easier to configure inside environments such as Spring
1997     *
1998     * @throws Exception
1999     */
2000    protected void processHelperProperties() throws Exception {
2001        if (transportConnectorURIs != null) {
2002            for (int i = 0; i < transportConnectorURIs.length; i++) {
2003                String uri = transportConnectorURIs[i];
2004                addConnector(uri);
2005            }
2006        }
2007        if (networkConnectorURIs != null) {
2008            for (int i = 0; i < networkConnectorURIs.length; i++) {
2009                String uri = networkConnectorURIs[i];
2010                addNetworkConnector(uri);
2011            }
2012        }
2013        if (jmsBridgeConnectors != null) {
2014            for (int i = 0; i < jmsBridgeConnectors.length; i++) {
2015                addJmsConnector(jmsBridgeConnectors[i]);
2016            }
2017        }
2018    }
2019
2020    /**
2021     * Check that the store usage limit is not greater than max usable
2022     * space and adjust if it is
2023     */
2024    protected void checkStoreUsageLimits() throws Exception {
2025        final SystemUsage usage = getSystemUsage();
2026
2027        if (getPersistenceAdapter() != null) {
2028            PersistenceAdapter adapter = getPersistenceAdapter();
2029            checkUsageLimit(adapter.getDirectory(), usage.getStoreUsage(), usage.getStoreUsage().getPercentLimit());
2030
2031            long maxJournalFileSize = 0;
2032            long storeLimit = usage.getStoreUsage().getLimit();
2033
2034            if (adapter instanceof JournaledStore) {
2035                maxJournalFileSize = ((JournaledStore) adapter).getJournalMaxFileLength();
2036            }
2037
2038            if (storeLimit > 0 && storeLimit < maxJournalFileSize) {
2039                LOG.error("Store limit is " + storeLimit / (1024 * 1024) +
2040                          " mb, whilst the max journal file size for the store is: " +
2041                          maxJournalFileSize / (1024 * 1024) + " mb, " +
2042                          "the store will not accept any data when used.");
2043
2044            }
2045        }
2046    }
2047
2048    /**
2049     * Check that temporary usage limit is not greater than max usable
2050     * space and adjust if it is
2051     */
2052    protected void checkTmpStoreUsageLimits() throws Exception {
2053        final SystemUsage usage = getSystemUsage();
2054
2055        File tmpDir = getTmpDataDirectory();
2056
2057        if (tmpDir != null) {
2058            checkUsageLimit(tmpDir, usage.getTempUsage(), usage.getTempUsage().getPercentLimit());
2059
2060            if (isPersistent()) {
2061                long maxJournalFileSize;
2062
2063                PListStore store = usage.getTempUsage().getStore();
2064                if (store != null && store instanceof JournaledStore) {
2065                    maxJournalFileSize = ((JournaledStore) store).getJournalMaxFileLength();
2066                } else {
2067                    maxJournalFileSize = DEFAULT_MAX_FILE_LENGTH;
2068                }
2069                long storeLimit = usage.getTempUsage().getLimit();
2070
2071                if (storeLimit > 0 && storeLimit < maxJournalFileSize) {
2072                    LOG.error("Temporary Store limit is " + storeLimit / (1024 * 1024) +
2073                              " mb, whilst the max journal file size for the temporary store is: " +
2074                              maxJournalFileSize / (1024 * 1024) + " mb, " +
2075                              "the temp store will not accept any data when used.");
2076                }
2077            }
2078        }
2079    }
2080
2081    protected void checkUsageLimit(File dir, PercentLimitUsage<?> storeUsage, int percentLimit) throws ConfigurationException {
2082        if (dir != null) {
2083            dir = StoreUtil.findParentDirectory(dir);
2084            String storeName = storeUsage instanceof StoreUsage ? "Store" : "Temporary Store";
2085            long storeLimit = storeUsage.getLimit();
2086            long storeCurrent = storeUsage.getUsage();
2087            long totalSpace = storeUsage.getTotal() > 0 ? storeUsage.getTotal() : dir.getTotalSpace();
2088            long totalUsableSpace = (storeUsage.getTotal() > 0 ? storeUsage.getTotal() : dir.getUsableSpace()) + storeCurrent;
2089            if (totalUsableSpace < 0 || totalSpace < 0) {
2090                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";
2091                LOG.error(message);
2092                throw new ConfigurationException(message);
2093            }
2094            //compute byte value of the percent limit
2095            long bytePercentLimit = totalSpace * percentLimit / 100;
2096            int oneMeg = 1024 * 1024;
2097
2098            //Check if the store limit is less than the percent Limit that was set and also
2099            //the usable space...this means we can grow the store larger
2100            //Changes in partition size (total space) as well as changes in usable space should
2101            //be detected here
2102            if (diskUsageCheckRegrowThreshold > -1 && percentLimit > 0
2103                    && storeUsage.getTotal() == 0
2104                    && storeLimit < bytePercentLimit && storeLimit < totalUsableSpace){
2105
2106                // set the limit to be bytePercentLimit or usableSpace if
2107                // usableSpace is less than the percentLimit
2108                long newLimit = bytePercentLimit > totalUsableSpace ? totalUsableSpace : bytePercentLimit;
2109
2110                //To prevent changing too often, check threshold
2111                if (newLimit - storeLimit >= diskUsageCheckRegrowThreshold) {
2112                    LOG.info("Usable disk space has been increased, attempting to regrow " + storeName + " limit to "
2113                            + percentLimit + "% of the partition size.");
2114                    storeUsage.setLimit(newLimit);
2115                    LOG.info(storeName + " limit has been increased to " + newLimit * 100 / totalSpace
2116                            + "% (" + newLimit / oneMeg + " mb) of the partition size.");
2117                }
2118
2119            //check if the limit is too large for the amount of usable space
2120            } else if (storeLimit > totalUsableSpace) {
2121                final String message = storeName + " limit is " +  storeLimit / oneMeg
2122                        + " mb (current store usage is " + storeCurrent / oneMeg
2123                        + " mb). The data directory: " + dir.getAbsolutePath()
2124                        + " only has " + totalUsableSpace / oneMeg
2125                        + " mb of usable space.";
2126
2127                if (!isAdjustUsageLimits()) {
2128                    LOG.error(message);
2129                    throw new ConfigurationException(message);
2130                }
2131
2132                if (percentLimit > 0) {
2133                    LOG.warn(storeName + " limit has been set to "
2134                            + percentLimit + "% (" + bytePercentLimit / oneMeg + " mb)"
2135                            + " of the partition size but there is not enough usable space."
2136                            + " The current store limit (which may have been adjusted by a"
2137                            + " previous usage limit check) is set to (" + storeLimit / oneMeg + " mb)"
2138                            + " but only " + totalUsableSpace * 100 / totalSpace + "% (" + totalUsableSpace / oneMeg + " mb)"
2139                            + " is available - resetting limit");
2140                } else {
2141                    LOG.warn(message + " - resetting to maximum available disk space: " +
2142                            totalUsableSpace / oneMeg + " mb");
2143                }
2144                storeUsage.setLimit(totalUsableSpace);
2145            }
2146        }
2147    }
2148
2149    /**
2150     * Schedules a periodic task based on schedulePeriodForDiskLimitCheck to
2151     * update store and temporary store limits if the amount of available space
2152     * plus current store size is less than the existin configured limit
2153     */
2154    protected void scheduleDiskUsageLimitsCheck() throws IOException {
2155        if (schedulePeriodForDiskUsageCheck > 0 &&
2156                (getPersistenceAdapter() != null || getTmpDataDirectory() != null)) {
2157            Runnable diskLimitCheckTask = new Runnable() {
2158                @Override
2159                public void run() {
2160                    try {
2161                        checkStoreUsageLimits();
2162                    } catch (Exception e) {
2163                        LOG.error("Failed to check persistent disk usage limits", e);
2164                    }
2165
2166                    try {
2167                        checkTmpStoreUsageLimits();
2168                    } catch (Exception e) {
2169                        LOG.error("Failed to check temporary store usage limits", e);
2170                    }
2171                }
2172            };
2173            scheduler.executePeriodically(diskLimitCheckTask, schedulePeriodForDiskUsageCheck);
2174        }
2175    }
2176
2177    protected void checkMemorySystemUsageLimits() throws Exception {
2178        final SystemUsage usage = getSystemUsage();
2179        long memLimit = usage.getMemoryUsage().getLimit();
2180        long jvmLimit = Runtime.getRuntime().maxMemory();
2181
2182        if (memLimit > jvmLimit) {
2183            final String message = "Memory Usage for the Broker (" + memLimit / (1024 * 1024)
2184                    + "mb) is more than the maximum available for the JVM: " + jvmLimit / (1024 * 1024);
2185
2186            if (adjustUsageLimits) {
2187                usage.getMemoryUsage().setPercentOfJvmHeap(70);
2188                LOG.warn(message + " mb - resetting to 70% of maximum available: " + (usage.getMemoryUsage().getLimit() / (1024 * 1024)) + " mb");
2189            } else {
2190                LOG.error(message);
2191                throw new ConfigurationException(message);
2192            }
2193        }
2194    }
2195
2196    protected void checkStoreSystemUsageLimits() throws Exception {
2197        final SystemUsage usage = getSystemUsage();
2198
2199        //Check the persistent store and temp store limits if they exist
2200        //and schedule a periodic check to update disk limits if
2201        //schedulePeriodForDiskLimitCheck is set
2202        checkStoreUsageLimits();
2203        checkTmpStoreUsageLimits();
2204        scheduleDiskUsageLimitsCheck();
2205
2206        if (getJobSchedulerStore() != null) {
2207            JobSchedulerStore scheduler = getJobSchedulerStore();
2208            File schedulerDir = scheduler.getDirectory();
2209            if (schedulerDir != null) {
2210
2211                String schedulerDirPath = schedulerDir.getAbsolutePath();
2212                if (!schedulerDir.isAbsolute()) {
2213                    schedulerDir = new File(schedulerDirPath);
2214                }
2215
2216                while (schedulerDir != null && !schedulerDir.isDirectory()) {
2217                    schedulerDir = schedulerDir.getParentFile();
2218                }
2219                long schedulerLimit = usage.getJobSchedulerUsage().getLimit();
2220                long dirFreeSpace = schedulerDir.getUsableSpace();
2221                if (schedulerLimit > dirFreeSpace) {
2222                    LOG.warn("Job Scheduler Store limit is " + schedulerLimit / (1024 * 1024) +
2223                             " mb, whilst the data directory: " + schedulerDir.getAbsolutePath() +
2224                             " only has " + dirFreeSpace / (1024 * 1024) + " mb of usable space - resetting to " +
2225                            dirFreeSpace / (1024 * 1024) + " mb.");
2226                    usage.getJobSchedulerUsage().setLimit(dirFreeSpace);
2227                }
2228            }
2229        }
2230    }
2231
2232    public void stopAllConnectors(ServiceStopper stopper) {
2233        for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) {
2234            NetworkConnector connector = iter.next();
2235            unregisterNetworkConnectorMBean(connector);
2236            stopper.stop(connector);
2237        }
2238        for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) {
2239            ProxyConnector connector = iter.next();
2240            stopper.stop(connector);
2241        }
2242        for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) {
2243            JmsConnector connector = iter.next();
2244            stopper.stop(connector);
2245        }
2246        for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) {
2247            TransportConnector connector = iter.next();
2248            try {
2249                unregisterConnectorMBean(connector);
2250            } catch (IOException e) {
2251            }
2252            stopper.stop(connector);
2253        }
2254    }
2255
2256    protected TransportConnector registerConnectorMBean(TransportConnector connector) throws IOException {
2257        try {
2258            ObjectName objectName = createConnectorObjectName(connector);
2259            connector = connector.asManagedConnector(getManagementContext(), objectName);
2260            ConnectorViewMBean view = new ConnectorView(connector);
2261            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2262            return connector;
2263        } catch (Throwable e) {
2264            throw IOExceptionSupport.create("Transport Connector could not be registered in JMX: " + e, e);
2265        }
2266    }
2267
2268    protected void unregisterConnectorMBean(TransportConnector connector) throws IOException {
2269        if (isUseJmx()) {
2270            try {
2271                ObjectName objectName = createConnectorObjectName(connector);
2272                getManagementContext().unregisterMBean(objectName);
2273            } catch (Throwable e) {
2274                throw IOExceptionSupport.create(
2275                        "Transport Connector could not be unregistered in JMX: " + e.getMessage(), e);
2276            }
2277        }
2278    }
2279
2280    protected PersistenceAdapter registerPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException {
2281        return adaptor;
2282    }
2283
2284    protected void unregisterPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException {
2285        if (isUseJmx()) {}
2286    }
2287
2288    private ObjectName createConnectorObjectName(TransportConnector connector) throws MalformedObjectNameException {
2289        return BrokerMBeanSupport.createConnectorName(getBrokerObjectName(), "clientConnectors", connector.getName());
2290    }
2291
2292    public void registerNetworkConnectorMBean(NetworkConnector connector) throws IOException {
2293        NetworkConnectorViewMBean view = new NetworkConnectorView(connector);
2294        try {
2295            ObjectName objectName = createNetworkConnectorObjectName(connector);
2296            connector.setObjectName(objectName);
2297            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2298        } catch (Throwable e) {
2299            throw IOExceptionSupport.create("Network Connector could not be registered in JMX: " + e.getMessage(), e);
2300        }
2301    }
2302
2303    public ObjectName createNetworkConnectorObjectName(NetworkConnector connector) throws MalformedObjectNameException {
2304        return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "networkConnectors", connector.getName());
2305    }
2306
2307    public ObjectName createDuplexNetworkConnectorObjectName(String transport) throws MalformedObjectNameException {
2308        return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "duplexNetworkConnectors", transport);
2309    }
2310
2311    protected void unregisterNetworkConnectorMBean(NetworkConnector connector) {
2312        if (isUseJmx()) {
2313            try {
2314                ObjectName objectName = createNetworkConnectorObjectName(connector);
2315                getManagementContext().unregisterMBean(objectName);
2316            } catch (Exception e) {
2317                LOG.warn("Network Connector could not be unregistered from JMX due " + e.getMessage() + ". This exception is ignored.", e);
2318            }
2319        }
2320    }
2321
2322    protected void registerProxyConnectorMBean(ProxyConnector connector) throws IOException {
2323        ProxyConnectorView view = new ProxyConnectorView(connector);
2324        try {
2325            ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "proxyConnectors", connector.getName());
2326            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2327        } catch (Throwable e) {
2328            throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e);
2329        }
2330    }
2331
2332    protected void registerJmsConnectorMBean(JmsConnector connector) throws IOException {
2333        JmsConnectorView view = new JmsConnectorView(connector);
2334        try {
2335            ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "jmsConnectors", connector.getName());
2336            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2337        } catch (Throwable e) {
2338            throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e);
2339        }
2340    }
2341
2342    /**
2343     * Factory method to create a new broker
2344     *
2345     * @throws Exception
2346     */
2347    protected Broker createBroker() throws Exception {
2348        regionBroker = createRegionBroker();
2349        Broker broker = addInterceptors(regionBroker);
2350        // Add a filter that will stop access to the broker once stopped
2351        broker = new MutableBrokerFilter(broker) {
2352            Broker old;
2353
2354            @Override
2355            public void stop() throws Exception {
2356                old = this.next.getAndSet(new ErrorBroker("Broker has been stopped: " + this) {
2357                    // Just ignore additional stop actions.
2358                    @Override
2359                    public void stop() throws Exception {
2360                    }
2361                });
2362                old.stop();
2363            }
2364
2365            @Override
2366            public void start() throws Exception {
2367                if (forceStart && old != null) {
2368                    this.next.set(old);
2369                }
2370                getNext().start();
2371            }
2372        };
2373        return broker;
2374    }
2375
2376    /**
2377     * Factory method to create the core region broker onto which interceptors
2378     * are added
2379     *
2380     * @throws Exception
2381     */
2382    protected Broker createRegionBroker() throws Exception {
2383        if (destinationInterceptors == null) {
2384            destinationInterceptors = createDefaultDestinationInterceptor();
2385        }
2386        configureServices(destinationInterceptors);
2387        DestinationInterceptor destinationInterceptor = new CompositeDestinationInterceptor(destinationInterceptors);
2388        if (destinationFactory == null) {
2389            destinationFactory = new DestinationFactoryImpl(this, getTaskRunnerFactory(), getPersistenceAdapter());
2390        }
2391        return createRegionBroker(destinationInterceptor);
2392    }
2393
2394    protected Broker createRegionBroker(DestinationInterceptor destinationInterceptor) throws IOException {
2395        RegionBroker regionBroker;
2396        if (isUseJmx()) {
2397            try {
2398                regionBroker = new ManagedRegionBroker(this, getManagementContext(), getBrokerObjectName(),
2399                    getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory, destinationInterceptor,getScheduler(),getExecutor());
2400            } catch(MalformedObjectNameException me){
2401                LOG.warn("Cannot create ManagedRegionBroker due " + me.getMessage(), me);
2402                throw new IOException(me);
2403            }
2404        } else {
2405            regionBroker = new RegionBroker(this, getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory,
2406                    destinationInterceptor,getScheduler(),getExecutor());
2407        }
2408        destinationFactory.setRegionBroker(regionBroker);
2409        regionBroker.setKeepDurableSubsActive(keepDurableSubsActive);
2410        regionBroker.setBrokerName(getBrokerName());
2411        regionBroker.getDestinationStatistics().setEnabled(enableStatistics);
2412        regionBroker.setAllowTempAutoCreationOnSend(isAllowTempAutoCreationOnSend());
2413        if (brokerId != null) {
2414            regionBroker.setBrokerId(brokerId);
2415        }
2416        return regionBroker;
2417    }
2418
2419    /**
2420     * Create the default destination interceptor
2421     */
2422    protected DestinationInterceptor[] createDefaultDestinationInterceptor() {
2423        List<DestinationInterceptor> answer = new ArrayList<>();
2424        if (isUseVirtualTopics()) {
2425            VirtualDestinationInterceptor interceptor = new VirtualDestinationInterceptor();
2426            VirtualTopic virtualTopic = new VirtualTopic();
2427            virtualTopic.setName("VirtualTopic.>");
2428            VirtualDestination[] virtualDestinations = { virtualTopic };
2429            interceptor.setVirtualDestinations(virtualDestinations);
2430            answer.add(interceptor);
2431        }
2432        if (isUseMirroredQueues()) {
2433            MirroredQueue interceptor = new MirroredQueue();
2434            answer.add(interceptor);
2435        }
2436        DestinationInterceptor[] array = new DestinationInterceptor[answer.size()];
2437        answer.toArray(array);
2438        return array;
2439    }
2440
2441    /**
2442     * Strategy method to add interceptors to the broker
2443     *
2444     * @throws IOException
2445     */
2446    protected Broker addInterceptors(Broker broker) throws Exception {
2447        if (isSchedulerSupport()) {
2448            SchedulerBroker sb = new SchedulerBroker(this, broker, getJobSchedulerStore());
2449            if (isUseJmx()) {
2450                JobSchedulerViewMBean view = new JobSchedulerView(sb.getJobScheduler());
2451                try {
2452                    ObjectName objectName = BrokerMBeanSupport.createJobSchedulerServiceName(getBrokerObjectName());
2453                    AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2454                    this.adminView.setJMSJobScheduler(objectName);
2455                } catch (Throwable e) {
2456                    throw IOExceptionSupport.create("JobScheduler could not be registered in JMX: "
2457                            + e.getMessage(), e);
2458                }
2459            }
2460            broker = sb;
2461        }
2462        if (isUseJmx()) {
2463            HealthViewMBean statusView = new HealthView((ManagedRegionBroker)getRegionBroker());
2464            try {
2465                ObjectName objectName = BrokerMBeanSupport.createHealthServiceName(getBrokerObjectName());
2466                AnnotatedMBean.registerMBean(getManagementContext(), statusView, objectName);
2467            } catch (Throwable e) {
2468                throw IOExceptionSupport.create("Status MBean could not be registered in JMX: "
2469                        + e.getMessage(), e);
2470            }
2471        }
2472        if (isAdvisorySupport()) {
2473            broker = new AdvisoryBroker(broker);
2474        }
2475        broker = new CompositeDestinationBroker(broker);
2476        broker = new TransactionBroker(broker, getPersistenceAdapter().createTransactionStore());
2477        if (isPopulateJMSXUserID()) {
2478            UserIDBroker userIDBroker = new UserIDBroker(broker);
2479            userIDBroker.setUseAuthenticatePrincipal(isUseAuthenticatedPrincipalForJMSXUserID());
2480            broker = userIDBroker;
2481        }
2482        if (isMonitorConnectionSplits()) {
2483            broker = new ConnectionSplitBroker(broker);
2484        }
2485        if (plugins != null) {
2486            for (int i = 0; i < plugins.length; i++) {
2487                BrokerPlugin plugin = plugins[i];
2488                broker = plugin.installPlugin(broker);
2489            }
2490        }
2491        return broker;
2492    }
2493
2494    protected PersistenceAdapter createPersistenceAdapter() throws IOException {
2495        if (isPersistent()) {
2496            PersistenceAdapterFactory fac = getPersistenceFactory();
2497            if (fac != null) {
2498                return fac.createPersistenceAdapter();
2499            } else {
2500                try {
2501                    String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter";
2502                    PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance();
2503                    File dir = new File(getBrokerDataDirectory(),"KahaDB");
2504                    adaptor.setDirectory(dir);
2505                    return adaptor;
2506                } catch (Throwable e) {
2507                    throw IOExceptionSupport.create(e);
2508                }
2509            }
2510        } else {
2511            return new MemoryPersistenceAdapter();
2512        }
2513    }
2514
2515    protected ObjectName createBrokerObjectName() throws MalformedObjectNameException  {
2516        return BrokerMBeanSupport.createBrokerObjectName(getManagementContext().getJmxDomainName(), getBrokerName());
2517    }
2518
2519    protected TransportConnector createTransportConnector(URI brokerURI) throws Exception {
2520        TransportServer transport = TransportFactorySupport.bind(this, brokerURI);
2521        return new TransportConnector(transport);
2522    }
2523
2524    /**
2525     * Extracts the port from the options
2526     */
2527    protected Object getPort(Map<?,?> options) {
2528        Object port = options.get("port");
2529        if (port == null) {
2530            port = DEFAULT_PORT;
2531            LOG.warn("No port specified so defaulting to: {}", port);
2532        }
2533        return port;
2534    }
2535
2536    protected void addShutdownHook() {
2537        if (useShutdownHook) {
2538            shutdownHook = new Thread("ActiveMQ ShutdownHook") {
2539                @Override
2540                public void run() {
2541                    containerShutdown();
2542                }
2543            };
2544            Runtime.getRuntime().addShutdownHook(shutdownHook);
2545        }
2546    }
2547
2548    protected void removeShutdownHook() {
2549        if (shutdownHook != null) {
2550            try {
2551                Runtime.getRuntime().removeShutdownHook(shutdownHook);
2552            } catch (Exception e) {
2553                LOG.debug("Caught exception, must be shutting down. This exception is ignored.", e);
2554            }
2555        }
2556    }
2557
2558    /**
2559     * Sets hooks to be executed when broker shut down
2560     *
2561     * @org.apache.xbean.Property
2562     */
2563    public void setShutdownHooks(List<Runnable> hooks) throws Exception {
2564        for (Runnable hook : hooks) {
2565            addShutdownHook(hook);
2566        }
2567    }
2568
2569    /**
2570     * Causes a clean shutdown of the container when the VM is being shut down
2571     */
2572    protected void containerShutdown() {
2573        try {
2574            stop();
2575        } catch (IOException e) {
2576            Throwable linkedException = e.getCause();
2577            if (linkedException != null) {
2578                logError("Failed to shut down: " + e + ". Reason: " + linkedException, linkedException);
2579            } else {
2580                logError("Failed to shut down: " + e, e);
2581            }
2582            if (!useLoggingForShutdownErrors) {
2583                e.printStackTrace(System.err);
2584            }
2585        } catch (Exception e) {
2586            logError("Failed to shut down: " + e, e);
2587        }
2588    }
2589
2590    protected void logError(String message, Throwable e) {
2591        if (useLoggingForShutdownErrors) {
2592            LOG.error("Failed to shut down: " + e);
2593        } else {
2594            System.err.println("Failed to shut down: " + e);
2595        }
2596    }
2597
2598    /**
2599     * Starts any configured destinations on startup
2600     */
2601    protected void startDestinations() throws Exception {
2602        if (destinations != null) {
2603            ConnectionContext adminConnectionContext = getAdminConnectionContext();
2604            for (int i = 0; i < destinations.length; i++) {
2605                ActiveMQDestination destination = destinations[i];
2606                getBroker().addDestination(adminConnectionContext, destination,true);
2607            }
2608        }
2609        if (isUseVirtualTopics()) {
2610            startVirtualConsumerDestinations();
2611        }
2612    }
2613
2614    /**
2615     * Returns the broker's administration connection context used for
2616     * configuring the broker at startup
2617     */
2618    public ConnectionContext getAdminConnectionContext() throws Exception {
2619        return BrokerSupport.getConnectionContext(getBroker());
2620    }
2621
2622    protected void startManagementContext() throws Exception {
2623        getManagementContext().setBrokerName(brokerName);
2624        getManagementContext().start();
2625        adminView = new BrokerView(this, null);
2626        ObjectName objectName = getBrokerObjectName();
2627        AnnotatedMBean.registerMBean(getManagementContext(), adminView, objectName);
2628    }
2629
2630    /**
2631     * Start all transport and network connections, proxies and bridges
2632     *
2633     * @throws Exception
2634     */
2635    public void startAllConnectors() throws Exception {
2636        final Set<ActiveMQDestination> durableDestinations = getBroker().getDurableDestinations();
2637        List<TransportConnector> al = new ArrayList<>();
2638        for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) {
2639            TransportConnector connector = iter.next();
2640            al.add(startTransportConnector(connector));
2641        }
2642        if (al.size() > 0) {
2643            // let's clear the transportConnectors list and replace it with
2644            // the started transportConnector instances
2645            this.transportConnectors.clear();
2646            setTransportConnectors(al);
2647        }
2648        this.slave = false;
2649        if (!stopped.get()) {
2650            ThreadPoolExecutor networkConnectorStartExecutor = null;
2651            if (isNetworkConnectorStartAsync()) {
2652                // spin up as many threads as needed
2653                networkConnectorStartExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
2654                    10, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
2655                    new ThreadFactory() {
2656                        int count=0;
2657                        @Override
2658                        public Thread newThread(Runnable runnable) {
2659                            Thread thread = new Thread(runnable, "NetworkConnector Start Thread-" +(count++));
2660                            thread.setDaemon(true);
2661                            return thread;
2662                        }
2663                    });
2664            }
2665
2666            for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) {
2667                final NetworkConnector connector = iter.next();
2668                connector.setLocalUri(getVmConnectorURI());
2669                startNetworkConnector(connector, durableDestinations, networkConnectorStartExecutor);
2670            }
2671            if (networkConnectorStartExecutor != null) {
2672                // executor done when enqueued tasks are complete
2673                ThreadPoolUtils.shutdown(networkConnectorStartExecutor);
2674            }
2675
2676            for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) {
2677                ProxyConnector connector = iter.next();
2678                connector.start();
2679            }
2680            for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) {
2681                JmsConnector connector = iter.next();
2682                connector.start();
2683            }
2684            for (Service service : services) {
2685                configureService(service);
2686                service.start();
2687            }
2688        }
2689    }
2690
2691    public void startNetworkConnector(final NetworkConnector connector,
2692            final ThreadPoolExecutor networkConnectorStartExecutor) throws Exception {
2693        startNetworkConnector(connector, getBroker().getDurableDestinations(), networkConnectorStartExecutor);
2694    }
2695
2696    public void startNetworkConnector(final NetworkConnector connector,
2697            final Set<ActiveMQDestination> durableDestinations,
2698            final ThreadPoolExecutor networkConnectorStartExecutor) throws Exception {
2699        connector.setBrokerName(getBrokerName());
2700        //set the durable destinations to match the broker if not set on the connector
2701        if (connector.getDurableDestinations() == null) {
2702            connector.setDurableDestinations(durableDestinations);
2703        }
2704        String defaultSocketURI = getDefaultSocketURIString();
2705        if (defaultSocketURI != null) {
2706            connector.setBrokerURL(defaultSocketURI);
2707        }
2708        //If using the runtime plugin to start a network connector then the mbean needs
2709        //to be added, under normal start it will already exist so check for InstanceNotFoundException
2710        if (isUseJmx()) {
2711            ObjectName networkMbean = createNetworkConnectorObjectName(connector);
2712            try {
2713                getManagementContext().getObjectInstance(networkMbean);
2714            } catch (InstanceNotFoundException e) {
2715                LOG.debug("Network connector MBean {} not found, registering", networkMbean);
2716                registerNetworkConnectorMBean(connector);
2717            }
2718        }
2719        if (networkConnectorStartExecutor != null) {
2720            networkConnectorStartExecutor.execute(new Runnable() {
2721                @Override
2722                public void run() {
2723                    try {
2724                        LOG.info("Async start of {}", connector);
2725                        connector.start();
2726                    } catch(Exception e) {
2727                        LOG.error("Async start of network connector: {} failed", connector, e);
2728                    }
2729                }
2730            });
2731        } else {
2732            connector.start();
2733        }
2734    }
2735
2736    public TransportConnector startTransportConnector(TransportConnector connector) throws Exception {
2737        connector.setBrokerService(this);
2738        connector.setTaskRunnerFactory(getTaskRunnerFactory());
2739        MessageAuthorizationPolicy policy = getMessageAuthorizationPolicy();
2740        if (policy != null) {
2741            connector.setMessageAuthorizationPolicy(policy);
2742        }
2743        if (isUseJmx()) {
2744            connector = registerConnectorMBean(connector);
2745        }
2746        connector.getStatistics().setEnabled(enableStatistics);
2747        connector.start();
2748        return connector;
2749    }
2750
2751    /**
2752     * Perform any custom dependency injection
2753     */
2754    protected void configureServices(Object[] services) {
2755        for (Object service : services) {
2756            configureService(service);
2757        }
2758    }
2759
2760    /**
2761     * Perform any custom dependency injection
2762     */
2763    protected void configureService(Object service) {
2764        if (service instanceof BrokerServiceAware) {
2765            BrokerServiceAware serviceAware = (BrokerServiceAware) service;
2766            serviceAware.setBrokerService(this);
2767        }
2768    }
2769
2770    public void handleIOException(IOException exception) {
2771        if (ioExceptionHandler != null) {
2772            ioExceptionHandler.handle(exception);
2773         } else {
2774            LOG.info("No IOExceptionHandler registered, ignoring IO exception", exception);
2775         }
2776    }
2777
2778    protected void startVirtualConsumerDestinations() throws Exception {
2779        checkStartException();
2780        ConnectionContext adminConnectionContext = getAdminConnectionContext();
2781        Set<ActiveMQDestination> destinations = destinationFactory.getDestinations();
2782        DestinationFilter filter = getVirtualTopicConsumerDestinationFilter();
2783        if (!destinations.isEmpty()) {
2784            for (ActiveMQDestination destination : destinations) {
2785                if (filter.matches(destination) == true) {
2786                    broker.addDestination(adminConnectionContext, destination, false);
2787                }
2788            }
2789        }
2790    }
2791
2792    private DestinationFilter getVirtualTopicConsumerDestinationFilter() {
2793        // created at startup, so no sync needed
2794        if (virtualConsumerDestinationFilter == null) {
2795            Set <ActiveMQQueue> consumerDestinations = new HashSet<>();
2796            if (destinationInterceptors != null) {
2797                for (DestinationInterceptor interceptor : destinationInterceptors) {
2798                    if (interceptor instanceof VirtualDestinationInterceptor) {
2799                        VirtualDestinationInterceptor virtualDestinationInterceptor = (VirtualDestinationInterceptor) interceptor;
2800                        for (VirtualDestination virtualDestination: virtualDestinationInterceptor.getVirtualDestinations()) {
2801                            if (virtualDestination instanceof VirtualTopic) {
2802                                consumerDestinations.add(new ActiveMQQueue(((VirtualTopic) virtualDestination).getPrefix() + DestinationFilter.ANY_DESCENDENT));
2803                            }
2804                            if (isUseVirtualDestSubs()) {
2805                                try {
2806                                    broker.virtualDestinationAdded(getAdminConnectionContext(), virtualDestination);
2807                                    LOG.debug("Adding virtual destination: {}", virtualDestination);
2808                                } catch (Exception e) {
2809                                    LOG.warn("Could not fire virtual destination consumer advisory", e);
2810                                }
2811                            }
2812                        }
2813                    }
2814                }
2815            }
2816            ActiveMQQueue filter = new ActiveMQQueue();
2817            filter.setCompositeDestinations(consumerDestinations.toArray(new ActiveMQDestination[]{}));
2818            virtualConsumerDestinationFilter = DestinationFilter.parseFilter(filter);
2819        }
2820        return virtualConsumerDestinationFilter;
2821    }
2822
2823    protected synchronized ThreadPoolExecutor getExecutor() {
2824        if (this.executor == null) {
2825            this.executor = new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
2826
2827                private long i = 0;
2828
2829                @Override
2830                public Thread newThread(Runnable runnable) {
2831                    this.i++;
2832                    Thread thread = new Thread(runnable, "ActiveMQ BrokerService.worker." + this.i);
2833                    thread.setDaemon(true);
2834                    thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
2835                        @Override
2836                        public void uncaughtException(final Thread t, final Throwable e) {
2837                            LOG.error("Error in thread '{}'", t.getName(), e);
2838                        }
2839                    });
2840                    return thread;
2841                }
2842            }, new RejectedExecutionHandler() {
2843                @Override
2844                public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
2845                    try {
2846                        executor.getQueue().offer(r, 60, TimeUnit.SECONDS);
2847                    } catch (InterruptedException e) {
2848                        throw new RejectedExecutionException("Interrupted waiting for BrokerService.worker");
2849                    }
2850
2851                    throw new RejectedExecutionException("Timed Out while attempting to enqueue Task.");
2852                }
2853            });
2854        }
2855        return this.executor;
2856    }
2857
2858    public synchronized Scheduler getScheduler() {
2859        if (this.scheduler==null) {
2860            this.scheduler = new Scheduler("ActiveMQ Broker["+getBrokerName()+"] Scheduler");
2861            try {
2862                this.scheduler.start();
2863            } catch (Exception e) {
2864               LOG.error("Failed to start Scheduler", e);
2865            }
2866        }
2867        return this.scheduler;
2868    }
2869
2870    public Broker getRegionBroker() {
2871        return regionBroker;
2872    }
2873
2874    public void setRegionBroker(Broker regionBroker) {
2875        this.regionBroker = regionBroker;
2876    }
2877
2878    public final void removePreShutdownHook(final Runnable hook) {
2879        preShutdownHooks.remove(hook);
2880    }
2881
2882    public void addShutdownHook(Runnable hook) {
2883        synchronized (shutdownHooks) {
2884            shutdownHooks.add(hook);
2885        }
2886    }
2887
2888    public void removeShutdownHook(Runnable hook) {
2889        synchronized (shutdownHooks) {
2890            shutdownHooks.remove(hook);
2891        }
2892    }
2893
2894    public boolean isSystemExitOnShutdown() {
2895        return systemExitOnShutdown;
2896    }
2897
2898    /**
2899     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2900     */
2901    public void setSystemExitOnShutdown(boolean systemExitOnShutdown) {
2902        this.systemExitOnShutdown = systemExitOnShutdown;
2903    }
2904
2905    public int getSystemExitOnShutdownExitCode() {
2906        return systemExitOnShutdownExitCode;
2907    }
2908
2909    public void setSystemExitOnShutdownExitCode(int systemExitOnShutdownExitCode) {
2910        this.systemExitOnShutdownExitCode = systemExitOnShutdownExitCode;
2911    }
2912
2913    public SslContext getSslContext() {
2914        return sslContext;
2915    }
2916
2917    public void setSslContext(SslContext sslContext) {
2918        this.sslContext = sslContext;
2919    }
2920
2921    public boolean isShutdownOnSlaveFailure() {
2922        return shutdownOnSlaveFailure;
2923    }
2924
2925    /**
2926     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2927     */
2928    public void setShutdownOnSlaveFailure(boolean shutdownOnSlaveFailure) {
2929        this.shutdownOnSlaveFailure = shutdownOnSlaveFailure;
2930    }
2931
2932    public boolean isWaitForSlave() {
2933        return waitForSlave;
2934    }
2935
2936    /**
2937     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2938     */
2939    public void setWaitForSlave(boolean waitForSlave) {
2940        this.waitForSlave = waitForSlave;
2941    }
2942
2943    public long getWaitForSlaveTimeout() {
2944        return this.waitForSlaveTimeout;
2945    }
2946
2947    public void setWaitForSlaveTimeout(long waitForSlaveTimeout) {
2948        this.waitForSlaveTimeout = waitForSlaveTimeout;
2949    }
2950
2951    /**
2952     * Get the passiveSlave
2953     * @return the passiveSlave
2954     */
2955    public boolean isPassiveSlave() {
2956        return this.passiveSlave;
2957    }
2958
2959    /**
2960     * Set the passiveSlave
2961     * @param passiveSlave the passiveSlave to set
2962     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2963     */
2964    public void setPassiveSlave(boolean passiveSlave) {
2965        this.passiveSlave = passiveSlave;
2966    }
2967
2968    /**
2969     * override the Default IOException handler, called when persistence adapter
2970     * has experiences File or JDBC I/O Exceptions
2971     *
2972     * @param ioExceptionHandler
2973     */
2974    public void setIoExceptionHandler(IOExceptionHandler ioExceptionHandler) {
2975        configureService(ioExceptionHandler);
2976        this.ioExceptionHandler = ioExceptionHandler;
2977    }
2978
2979    public IOExceptionHandler getIoExceptionHandler() {
2980        return ioExceptionHandler;
2981    }
2982
2983    /**
2984     * @return the schedulerSupport
2985     */
2986    public boolean isSchedulerSupport() {
2987        return this.schedulerSupport;
2988    }
2989
2990    /**
2991     * @param schedulerSupport the schedulerSupport to set
2992     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2993     */
2994    public void setSchedulerSupport(boolean schedulerSupport) {
2995        this.schedulerSupport = schedulerSupport;
2996    }
2997
2998    /**
2999     * @return the schedulerDirectory
3000     */
3001    public File getSchedulerDirectoryFile() {
3002        if (this.schedulerDirectoryFile == null) {
3003            this.schedulerDirectoryFile = new File(getBrokerDataDirectory(), "scheduler");
3004        }
3005        return schedulerDirectoryFile;
3006    }
3007
3008    /**
3009     * @param schedulerDirectory the schedulerDirectory to set
3010     */
3011    public void setSchedulerDirectoryFile(File schedulerDirectory) {
3012        this.schedulerDirectoryFile = schedulerDirectory;
3013    }
3014
3015    public void setSchedulerDirectory(String schedulerDirectory) {
3016        setSchedulerDirectoryFile(new File(schedulerDirectory));
3017    }
3018
3019    public int getSchedulePeriodForDestinationPurge() {
3020        return this.schedulePeriodForDestinationPurge;
3021    }
3022
3023    public void setSchedulePeriodForDestinationPurge(int schedulePeriodForDestinationPurge) {
3024        this.schedulePeriodForDestinationPurge = schedulePeriodForDestinationPurge;
3025    }
3026
3027    /**
3028     * @param schedulePeriodForDiskUsageCheck
3029     */
3030    public void setSchedulePeriodForDiskUsageCheck(
3031            int schedulePeriodForDiskUsageCheck) {
3032        this.schedulePeriodForDiskUsageCheck = schedulePeriodForDiskUsageCheck;
3033    }
3034
3035    public int getDiskUsageCheckRegrowThreshold() {
3036        return diskUsageCheckRegrowThreshold;
3037    }
3038
3039    /**
3040     * @param diskUsageCheckRegrowThreshold
3041     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.MemoryPropertyEditor"
3042     */
3043    public void setDiskUsageCheckRegrowThreshold(int diskUsageCheckRegrowThreshold) {
3044        this.diskUsageCheckRegrowThreshold = diskUsageCheckRegrowThreshold;
3045    }
3046
3047    public int getMaxPurgedDestinationsPerSweep() {
3048        return this.maxPurgedDestinationsPerSweep;
3049    }
3050
3051    public void setMaxPurgedDestinationsPerSweep(int maxPurgedDestinationsPerSweep) {
3052        this.maxPurgedDestinationsPerSweep = maxPurgedDestinationsPerSweep;
3053    }
3054
3055    public BrokerContext getBrokerContext() {
3056        return brokerContext;
3057    }
3058
3059    public void setBrokerContext(BrokerContext brokerContext) {
3060        this.brokerContext = brokerContext;
3061    }
3062
3063    public void setBrokerId(String brokerId) {
3064        this.brokerId = new BrokerId(brokerId);
3065    }
3066
3067    public boolean isUseAuthenticatedPrincipalForJMSXUserID() {
3068        return useAuthenticatedPrincipalForJMSXUserID;
3069    }
3070
3071    public void setUseAuthenticatedPrincipalForJMSXUserID(boolean useAuthenticatedPrincipalForJMSXUserID) {
3072        this.useAuthenticatedPrincipalForJMSXUserID = useAuthenticatedPrincipalForJMSXUserID;
3073    }
3074
3075    /**
3076     * Should MBeans that support showing the Authenticated User Name information have this
3077     * value filled in or not.
3078     *
3079     * @return true if user names should be exposed in MBeans
3080     */
3081    public boolean isPopulateUserNameInMBeans() {
3082        return this.populateUserNameInMBeans;
3083    }
3084
3085    /**
3086     * Sets whether Authenticated User Name information is shown in MBeans that support this field.
3087     * @param value if MBeans should expose user name information.
3088     */
3089    public void setPopulateUserNameInMBeans(boolean value) {
3090        this.populateUserNameInMBeans = value;
3091    }
3092
3093    /**
3094     * Gets the time in Milliseconds that an invocation of an MBean method will wait before
3095     * failing.  The default value is to wait forever (zero).
3096     *
3097     * @return timeout in milliseconds before MBean calls fail, (default is 0 or no timeout).
3098     */
3099    public long getMbeanInvocationTimeout() {
3100        return mbeanInvocationTimeout;
3101    }
3102
3103    /**
3104     * Gets the time in Milliseconds that an invocation of an MBean method will wait before
3105     * failing. The default value is to wait forever (zero).
3106     *
3107     * @param mbeanInvocationTimeout
3108     *      timeout in milliseconds before MBean calls fail, (default is 0 or no timeout).
3109     */
3110    public void setMbeanInvocationTimeout(long mbeanInvocationTimeout) {
3111        this.mbeanInvocationTimeout = mbeanInvocationTimeout;
3112    }
3113
3114    public boolean isNetworkConnectorStartAsync() {
3115        return networkConnectorStartAsync;
3116    }
3117
3118    public void setNetworkConnectorStartAsync(boolean networkConnectorStartAsync) {
3119        this.networkConnectorStartAsync = networkConnectorStartAsync;
3120    }
3121
3122    public boolean isAllowTempAutoCreationOnSend() {
3123        return allowTempAutoCreationOnSend;
3124    }
3125
3126    /**
3127     * enable if temp destinations need to be propagated through a network when
3128     * advisorySupport==false. This is used in conjunction with the policy
3129     * gcInactiveDestinations for matching temps so they can get removed
3130     * when inactive
3131     *
3132     * @param allowTempAutoCreationOnSend
3133     */
3134    public void setAllowTempAutoCreationOnSend(boolean allowTempAutoCreationOnSend) {
3135        this.allowTempAutoCreationOnSend = allowTempAutoCreationOnSend;
3136    }
3137
3138    public long getOfflineDurableSubscriberTimeout() {
3139        return offlineDurableSubscriberTimeout;
3140    }
3141
3142    public void setOfflineDurableSubscriberTimeout(long offlineDurableSubscriberTimeout) {
3143        this.offlineDurableSubscriberTimeout = offlineDurableSubscriberTimeout;
3144    }
3145
3146    public long getOfflineDurableSubscriberTaskSchedule() {
3147        return offlineDurableSubscriberTaskSchedule;
3148    }
3149
3150    public void setOfflineDurableSubscriberTaskSchedule(long offlineDurableSubscriberTaskSchedule) {
3151        this.offlineDurableSubscriberTaskSchedule = offlineDurableSubscriberTaskSchedule;
3152    }
3153
3154    public boolean shouldRecordVirtualDestination(ActiveMQDestination destination) {
3155        return isUseVirtualTopics() && destination.isQueue() &&
3156               getVirtualTopicConsumerDestinationFilter().matches(destination);
3157    }
3158
3159    synchronized public Throwable getStartException() {
3160        return startException;
3161    }
3162
3163    public boolean isStartAsync() {
3164        return startAsync;
3165    }
3166
3167    public void setStartAsync(boolean startAsync) {
3168        this.startAsync = startAsync;
3169    }
3170
3171    public boolean isSlave() {
3172        return this.slave;
3173    }
3174
3175    public boolean isStopping() {
3176        return this.stopping.get();
3177    }
3178
3179    /**
3180     * @return true if the broker allowed to restart on shutdown.
3181     */
3182    public boolean isRestartAllowed() {
3183        return restartAllowed;
3184    }
3185
3186    /**
3187     * Sets if the broker allowed to restart on shutdown.
3188     */
3189    public void setRestartAllowed(boolean restartAllowed) {
3190        this.restartAllowed = restartAllowed;
3191    }
3192
3193    /**
3194     * A lifecycle manager of the BrokerService should
3195     * inspect this property after a broker shutdown has occurred
3196     * to find out if the broker needs to be re-created and started
3197     * again.
3198     *
3199     * @return true if the broker wants to be restarted after it shuts down.
3200     */
3201    public boolean isRestartRequested() {
3202        return restartRequested;
3203    }
3204
3205    public void requestRestart() {
3206        this.restartRequested = true;
3207    }
3208
3209    public int getStoreOpenWireVersion() {
3210        return storeOpenWireVersion;
3211    }
3212
3213    public void setStoreOpenWireVersion(int storeOpenWireVersion) {
3214        this.storeOpenWireVersion = storeOpenWireVersion;
3215    }
3216
3217    /**
3218     * @return the current number of connections on this Broker.
3219     */
3220    public int getCurrentConnections() {
3221        return this.currentConnections.get();
3222    }
3223
3224    /**
3225     * @return the total number of connections this broker has handled since startup.
3226     */
3227    public long getTotalConnections() {
3228        return this.totalConnections.get();
3229    }
3230
3231    public void incrementCurrentConnections() {
3232        this.currentConnections.incrementAndGet();
3233    }
3234
3235    public void decrementCurrentConnections() {
3236        this.currentConnections.decrementAndGet();
3237    }
3238
3239    public void incrementTotalConnections() {
3240        this.totalConnections.incrementAndGet();
3241    }
3242
3243    public boolean isRejectDurableConsumers() {
3244        return rejectDurableConsumers;
3245    }
3246
3247    public void setRejectDurableConsumers(boolean rejectDurableConsumers) {
3248        this.rejectDurableConsumers = rejectDurableConsumers;
3249    }
3250
3251    public boolean isUseVirtualDestSubs() {
3252        return useVirtualDestSubs;
3253    }
3254
3255    public void setUseVirtualDestSubs(
3256            boolean useVirtualDestSubs) {
3257        this.useVirtualDestSubs = useVirtualDestSubs;
3258    }
3259
3260    public boolean isUseVirtualDestSubsOnCreation() {
3261        return useVirtualDestSubsOnCreation;
3262    }
3263
3264    public void setUseVirtualDestSubsOnCreation(
3265            boolean useVirtualDestSubsOnCreation) {
3266        this.useVirtualDestSubsOnCreation = useVirtualDestSubsOnCreation;
3267    }
3268
3269    public boolean isAdjustUsageLimits() {
3270        return adjustUsageLimits;
3271    }
3272
3273    public void setAdjustUsageLimits(boolean adjustUsageLimits) {
3274        this.adjustUsageLimits = adjustUsageLimits;
3275    }
3276
3277    public void setRollbackOnlyOnAsyncException(boolean rollbackOnlyOnAsyncException) {
3278        this.rollbackOnlyOnAsyncException = rollbackOnlyOnAsyncException;
3279    }
3280
3281    public boolean isRollbackOnlyOnAsyncException() {
3282        return rollbackOnlyOnAsyncException;
3283    }
3284}