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