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