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", new Object[]{ 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", new Object[]{ 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", new Object[]{ 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 {}", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId, getUptime()});
903        }
904        LOG.info("Apache ActiveMQ {} ({}, {}) is shutdown", new Object[]{ 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: {}", new Object[]{
967                    connectorName, queueName, timeout, pollInterval
968            });
969            TransportConnector connector;
970            for (int i = 0; i < transportConnectors.size(); i++) {
971                connector = transportConnectors.get(i);
972                if (connector != null && connector.getName() != null && connector.getName().matches(connectorName)) {
973                    connector.stop();
974                }
975            }
976            long start = System.currentTimeMillis();
977            while (System.currentTimeMillis() - start < timeout * 1000) {
978                // check quesize until it gets zero
979                if (checkQueueSize(queueName)) {
980                    stop();
981                    break;
982                } else {
983                    Thread.sleep(pollInterval * 1000);
984                }
985            }
986            if (stopped.get()) {
987                LOG.info("Successfully stop the broker.");
988            } else {
989                LOG.info("There is still pending message on the queue. Please check and stop the broker manually.");
990            }
991        }
992    }
993
994    /**
995     * A helper method to block the caller thread until the broker has been
996     * stopped
997     */
998    public void waitUntilStopped() {
999        while (isStarted() && !stopped.get()) {
1000            try {
1001                stoppedLatch.await();
1002            } catch (InterruptedException e) {
1003                // ignore
1004            }
1005        }
1006    }
1007
1008    public boolean isStopped() {
1009        return stopped.get();
1010    }
1011
1012    /**
1013     * A helper method to block the caller thread until the broker has fully started
1014     * @return boolean true if wait succeeded false if broker was not started or was stopped
1015     */
1016    public boolean waitUntilStarted() {
1017        return waitUntilStarted(DEFAULT_START_TIMEOUT);
1018    }
1019
1020    /**
1021     * A helper method to block the caller thread until the broker has fully started
1022     *
1023     * @param timeout
1024     *        the amount of time to wait before giving up and returning false.
1025     *
1026     * @return boolean true if wait succeeded false if broker was not started or was stopped
1027     */
1028    public boolean waitUntilStarted(long timeout) {
1029        boolean waitSucceeded = isStarted();
1030        long expiration = Math.max(0, timeout + System.currentTimeMillis());
1031        while (!isStarted() && !stopped.get() && !waitSucceeded && expiration > System.currentTimeMillis()) {
1032            try {
1033                if (getStartException() != null) {
1034                    return waitSucceeded;
1035                }
1036                waitSucceeded = startedLatch.await(100L, TimeUnit.MILLISECONDS);
1037            } catch (InterruptedException ignore) {
1038            }
1039        }
1040        return waitSucceeded;
1041    }
1042
1043    // Properties
1044    // -------------------------------------------------------------------------
1045    /**
1046     * Returns the message broker
1047     */
1048    public Broker getBroker() throws Exception {
1049        if (broker == null) {
1050            checkStartException();
1051            broker = createBroker();
1052        }
1053        return broker;
1054    }
1055
1056    /**
1057     * Returns the administration view of the broker; used to create and destroy
1058     * resources such as queues and topics. Note this method returns null if JMX
1059     * is disabled.
1060     */
1061    public BrokerView getAdminView() throws Exception {
1062        if (adminView == null) {
1063            // force lazy creation
1064            getBroker();
1065        }
1066        return adminView;
1067    }
1068
1069    public void setAdminView(BrokerView adminView) {
1070        this.adminView = adminView;
1071    }
1072
1073    public String getBrokerName() {
1074        return brokerName;
1075    }
1076
1077    /**
1078     * Sets the name of this broker; which must be unique in the network
1079     *
1080     * @param brokerName
1081     */
1082    private static final String brokerNameReplacedCharsRegExp = "[^a-zA-Z0-9\\.\\_\\-\\:]";
1083    public void setBrokerName(String brokerName) {
1084        if (brokerName == null) {
1085            throw new NullPointerException("The broker name cannot be null");
1086        }
1087        String str = brokerName.replaceAll(brokerNameReplacedCharsRegExp, "_");
1088        if (!str.equals(brokerName)) {
1089            LOG.error("Broker Name: {} contained illegal characters matching regExp: {} - replaced with {}", brokerName, brokerNameReplacedCharsRegExp, str);
1090        }
1091        this.brokerName = str.trim();
1092    }
1093
1094    public PersistenceAdapterFactory getPersistenceFactory() {
1095        return persistenceFactory;
1096    }
1097
1098    public File getDataDirectoryFile() {
1099        if (dataDirectoryFile == null) {
1100            dataDirectoryFile = new File(IOHelper.getDefaultDataDirectory());
1101        }
1102        return dataDirectoryFile;
1103    }
1104
1105    public File getBrokerDataDirectory() {
1106        String brokerDir = getBrokerName();
1107        return new File(getDataDirectoryFile(), brokerDir);
1108    }
1109
1110    /**
1111     * Sets the directory in which the data files will be stored by default for
1112     * the JDBC and Journal persistence adaptors.
1113     *
1114     * @param dataDirectory
1115     *            the directory to store data files
1116     */
1117    public void setDataDirectory(String dataDirectory) {
1118        setDataDirectoryFile(new File(dataDirectory));
1119    }
1120
1121    /**
1122     * Sets the directory in which the data files will be stored by default for
1123     * the JDBC and Journal persistence adaptors.
1124     *
1125     * @param dataDirectoryFile
1126     *            the directory to store data files
1127     */
1128    public void setDataDirectoryFile(File dataDirectoryFile) {
1129        this.dataDirectoryFile = dataDirectoryFile;
1130    }
1131
1132    /**
1133     * @return the tmpDataDirectory
1134     */
1135    public File getTmpDataDirectory() {
1136        if (tmpDataDirectory == null) {
1137            tmpDataDirectory = new File(getBrokerDataDirectory(), "tmp_storage");
1138        }
1139        return tmpDataDirectory;
1140    }
1141
1142    /**
1143     * @param tmpDataDirectory
1144     *            the tmpDataDirectory to set
1145     */
1146    public void setTmpDataDirectory(File tmpDataDirectory) {
1147        this.tmpDataDirectory = tmpDataDirectory;
1148    }
1149
1150    public void setPersistenceFactory(PersistenceAdapterFactory persistenceFactory) {
1151        this.persistenceFactory = persistenceFactory;
1152    }
1153
1154    public void setDestinationFactory(DestinationFactory destinationFactory) {
1155        this.destinationFactory = destinationFactory;
1156    }
1157
1158    public boolean isPersistent() {
1159        return persistent;
1160    }
1161
1162    /**
1163     * Sets whether or not persistence is enabled or disabled.
1164     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
1165     */
1166    public void setPersistent(boolean persistent) {
1167        this.persistent = persistent;
1168    }
1169
1170    public boolean isPopulateJMSXUserID() {
1171        return populateJMSXUserID;
1172    }
1173
1174    /**
1175     * Sets whether or not the broker should populate the JMSXUserID header.
1176     */
1177    public void setPopulateJMSXUserID(boolean populateJMSXUserID) {
1178        this.populateJMSXUserID = populateJMSXUserID;
1179    }
1180
1181    public SystemUsage getSystemUsage() {
1182        try {
1183            if (systemUsage == null) {
1184
1185                systemUsage = new SystemUsage("Main", getPersistenceAdapter(), getTempDataStore(), getJobSchedulerStore());
1186                systemUsage.setExecutor(getExecutor());
1187                systemUsage.getMemoryUsage().setLimit(1024L * 1024 * 1024 * 1); // 1 GB
1188                systemUsage.getTempUsage().setLimit(1024L * 1024 * 1024 * 50); // 50 GB
1189                systemUsage.getStoreUsage().setLimit(1024L * 1024 * 1024 * 100); // 100 GB
1190                systemUsage.getJobSchedulerUsage().setLimit(1024L * 1024 * 1024 * 50); // 50 GB
1191                addService(this.systemUsage);
1192            }
1193            return systemUsage;
1194        } catch (IOException e) {
1195            LOG.error("Cannot create SystemUsage", e);
1196            throw new RuntimeException("Fatally failed to create SystemUsage" + e.getMessage(), e);
1197        }
1198    }
1199
1200    public void setSystemUsage(SystemUsage memoryManager) {
1201        if (this.systemUsage != null) {
1202            removeService(this.systemUsage);
1203        }
1204        this.systemUsage = memoryManager;
1205        if (this.systemUsage.getExecutor()==null) {
1206            this.systemUsage.setExecutor(getExecutor());
1207        }
1208        addService(this.systemUsage);
1209    }
1210
1211    /**
1212     * @return the consumerUsageManager
1213     * @throws IOException
1214     */
1215    public SystemUsage getConsumerSystemUsage() throws IOException {
1216        if (this.consumerSystemUsage == null) {
1217            if (splitSystemUsageForProducersConsumers) {
1218                this.consumerSystemUsage = new SystemUsage(getSystemUsage(), "Consumer");
1219                float portion = consumerSystemUsagePortion / 100f;
1220                this.consumerSystemUsage.getMemoryUsage().setUsagePortion(portion);
1221                addService(this.consumerSystemUsage);
1222            } else {
1223                consumerSystemUsage = getSystemUsage();
1224            }
1225        }
1226        return this.consumerSystemUsage;
1227    }
1228
1229    /**
1230     * @param consumerSystemUsage
1231     *            the storeSystemUsage to set
1232     */
1233    public void setConsumerSystemUsage(SystemUsage consumerSystemUsage) {
1234        if (this.consumerSystemUsage != null) {
1235            removeService(this.consumerSystemUsage);
1236        }
1237        this.consumerSystemUsage = consumerSystemUsage;
1238        addService(this.consumerSystemUsage);
1239    }
1240
1241    /**
1242     * @return the producerUsageManager
1243     * @throws IOException
1244     */
1245    public SystemUsage getProducerSystemUsage() throws IOException {
1246        if (producerSystemUsage == null) {
1247            if (splitSystemUsageForProducersConsumers) {
1248                producerSystemUsage = new SystemUsage(getSystemUsage(), "Producer");
1249                float portion = producerSystemUsagePortion / 100f;
1250                producerSystemUsage.getMemoryUsage().setUsagePortion(portion);
1251                addService(producerSystemUsage);
1252            } else {
1253                producerSystemUsage = getSystemUsage();
1254            }
1255        }
1256        return producerSystemUsage;
1257    }
1258
1259    /**
1260     * @param producerUsageManager
1261     *            the producerUsageManager to set
1262     */
1263    public void setProducerSystemUsage(SystemUsage producerUsageManager) {
1264        if (this.producerSystemUsage != null) {
1265            removeService(this.producerSystemUsage);
1266        }
1267        this.producerSystemUsage = producerUsageManager;
1268        addService(this.producerSystemUsage);
1269    }
1270
1271    public synchronized PersistenceAdapter getPersistenceAdapter() throws IOException {
1272        if (persistenceAdapter == null && !hasStartException()) {
1273            persistenceAdapter = createPersistenceAdapter();
1274            configureService(persistenceAdapter);
1275            this.persistenceAdapter = registerPersistenceAdapterMBean(persistenceAdapter);
1276        }
1277        return persistenceAdapter;
1278    }
1279
1280    /**
1281     * Sets the persistence adaptor implementation to use for this broker
1282     *
1283     * @throws IOException
1284     */
1285    public void setPersistenceAdapter(PersistenceAdapter persistenceAdapter) throws IOException {
1286        if (!isPersistent() && ! (persistenceAdapter instanceof MemoryPersistenceAdapter)) {
1287            LOG.warn("persistent=\"false\", ignoring configured persistenceAdapter: {}", persistenceAdapter);
1288            return;
1289        }
1290        this.persistenceAdapter = persistenceAdapter;
1291        configureService(this.persistenceAdapter);
1292        this.persistenceAdapter = registerPersistenceAdapterMBean(persistenceAdapter);
1293    }
1294
1295    public TaskRunnerFactory getTaskRunnerFactory() {
1296        if (this.taskRunnerFactory == null) {
1297            this.taskRunnerFactory = new TaskRunnerFactory("ActiveMQ BrokerService["+getBrokerName()+"] Task", getTaskRunnerPriority(), true, 1000,
1298                    isDedicatedTaskRunner());
1299            this.taskRunnerFactory.setThreadClassLoader(this.getClass().getClassLoader());
1300        }
1301        return this.taskRunnerFactory;
1302    }
1303
1304    public void setTaskRunnerFactory(TaskRunnerFactory taskRunnerFactory) {
1305        this.taskRunnerFactory = taskRunnerFactory;
1306    }
1307
1308    public TaskRunnerFactory getPersistenceTaskRunnerFactory() {
1309        if (taskRunnerFactory == null) {
1310            persistenceTaskRunnerFactory = new TaskRunnerFactory("Persistence Adaptor Task", persistenceThreadPriority,
1311                    true, 1000, isDedicatedTaskRunner());
1312        }
1313        return persistenceTaskRunnerFactory;
1314    }
1315
1316    public void setPersistenceTaskRunnerFactory(TaskRunnerFactory persistenceTaskRunnerFactory) {
1317        this.persistenceTaskRunnerFactory = persistenceTaskRunnerFactory;
1318    }
1319
1320    public boolean isUseJmx() {
1321        return useJmx;
1322    }
1323
1324    public boolean isEnableStatistics() {
1325        return enableStatistics;
1326    }
1327
1328    /**
1329     * Sets whether or not the Broker's services enable statistics or not.
1330     */
1331    public void setEnableStatistics(boolean enableStatistics) {
1332        this.enableStatistics = enableStatistics;
1333    }
1334
1335    /**
1336     * Sets whether or not the Broker's services should be exposed into JMX or
1337     * not.
1338     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
1339     */
1340    public void setUseJmx(boolean useJmx) {
1341        this.useJmx = useJmx;
1342    }
1343
1344    public ObjectName getBrokerObjectName() throws MalformedObjectNameException {
1345        if (brokerObjectName == null) {
1346            brokerObjectName = createBrokerObjectName();
1347        }
1348        return brokerObjectName;
1349    }
1350
1351    /**
1352     * Sets the JMX ObjectName for this broker
1353     */
1354    public void setBrokerObjectName(ObjectName brokerObjectName) {
1355        this.brokerObjectName = brokerObjectName;
1356    }
1357
1358    public ManagementContext getManagementContext() {
1359        if (managementContext == null) {
1360            checkStartException();
1361            managementContext = new ManagementContext();
1362        }
1363        return managementContext;
1364    }
1365
1366    synchronized private void checkStartException() {
1367        if (startException != null) {
1368            throw new BrokerStoppedException(startException);
1369        }
1370    }
1371
1372    synchronized private boolean hasStartException() {
1373        return startException != null;
1374    }
1375
1376    synchronized private void setStartException(Throwable t) {
1377        startException = t;
1378    }
1379
1380    public void setManagementContext(ManagementContext managementContext) {
1381        this.managementContext = managementContext;
1382    }
1383
1384    public NetworkConnector getNetworkConnectorByName(String connectorName) {
1385        for (NetworkConnector connector : networkConnectors) {
1386            if (connector.getName().equals(connectorName)) {
1387                return connector;
1388            }
1389        }
1390        return null;
1391    }
1392
1393    public String[] getNetworkConnectorURIs() {
1394        return networkConnectorURIs;
1395    }
1396
1397    public void setNetworkConnectorURIs(String[] networkConnectorURIs) {
1398        this.networkConnectorURIs = networkConnectorURIs;
1399    }
1400
1401    public TransportConnector getConnectorByName(String connectorName) {
1402        for (TransportConnector connector : transportConnectors) {
1403            if (connector.getName().equals(connectorName)) {
1404                return connector;
1405            }
1406        }
1407        return null;
1408    }
1409
1410    public Map<String, String> getTransportConnectorURIsAsMap() {
1411        Map<String, String> answer = new HashMap<>();
1412        for (TransportConnector connector : transportConnectors) {
1413            try {
1414                URI uri = connector.getConnectUri();
1415                if (uri != null) {
1416                    String scheme = uri.getScheme();
1417                    if (scheme != null) {
1418                        answer.put(scheme.toLowerCase(Locale.ENGLISH), uri.toString());
1419                    }
1420                }
1421            } catch (Exception e) {
1422                LOG.debug("Failed to read URI to build transportURIsAsMap", e);
1423            }
1424        }
1425        return answer;
1426    }
1427
1428    public ProducerBrokerExchange getProducerBrokerExchange(ProducerInfo producerInfo){
1429        ProducerBrokerExchange result = null;
1430
1431        for (TransportConnector connector : transportConnectors) {
1432            for (TransportConnection tc: connector.getConnections()){
1433                result = tc.getProducerBrokerExchangeIfExists(producerInfo);
1434                if (result !=null){
1435                    return result;
1436                }
1437            }
1438        }
1439        return result;
1440    }
1441
1442    public String[] getTransportConnectorURIs() {
1443        return transportConnectorURIs;
1444    }
1445
1446    public void setTransportConnectorURIs(String[] transportConnectorURIs) {
1447        this.transportConnectorURIs = transportConnectorURIs;
1448    }
1449
1450    /**
1451     * @return Returns the jmsBridgeConnectors.
1452     */
1453    public JmsConnector[] getJmsBridgeConnectors() {
1454        return jmsBridgeConnectors;
1455    }
1456
1457    /**
1458     * @param jmsConnectors
1459     *            The jmsBridgeConnectors to set.
1460     */
1461    public void setJmsBridgeConnectors(JmsConnector[] jmsConnectors) {
1462        this.jmsBridgeConnectors = jmsConnectors;
1463    }
1464
1465    public Service[] getServices() {
1466        return services.toArray(new Service[0]);
1467    }
1468
1469    /**
1470     * Sets the services associated with this broker.
1471     */
1472    public void setServices(Service[] services) {
1473        this.services.clear();
1474        if (services != null) {
1475            for (int i = 0; i < services.length; i++) {
1476                this.services.add(services[i]);
1477            }
1478        }
1479    }
1480
1481    /**
1482     * Adds a new service so that it will be started as part of the broker
1483     * lifecycle
1484     */
1485    public void addService(Service service) {
1486        services.add(service);
1487    }
1488
1489    public void removeService(Service service) {
1490        services.remove(service);
1491    }
1492
1493    public boolean isUseLoggingForShutdownErrors() {
1494        return useLoggingForShutdownErrors;
1495    }
1496
1497    /**
1498     * Sets whether or not we should use commons-logging when reporting errors
1499     * when shutting down the broker
1500     */
1501    public void setUseLoggingForShutdownErrors(boolean useLoggingForShutdownErrors) {
1502        this.useLoggingForShutdownErrors = useLoggingForShutdownErrors;
1503    }
1504
1505    public boolean isUseShutdownHook() {
1506        return useShutdownHook;
1507    }
1508
1509    /**
1510     * Sets whether or not we should use a shutdown handler to close down the
1511     * broker cleanly if the JVM is terminated. It is recommended you leave this
1512     * enabled.
1513     */
1514    public void setUseShutdownHook(boolean useShutdownHook) {
1515        this.useShutdownHook = useShutdownHook;
1516    }
1517
1518    public boolean isAdvisorySupport() {
1519        return advisorySupport;
1520    }
1521
1522    /**
1523     * Allows the support of advisory messages to be disabled for performance
1524     * reasons.
1525     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
1526     */
1527    public void setAdvisorySupport(boolean advisorySupport) {
1528        this.advisorySupport = advisorySupport;
1529    }
1530
1531    public boolean isAnonymousProducerAdvisorySupport() {
1532        return anonymousProducerAdvisorySupport;
1533    }
1534
1535    public void setAnonymousProducerAdvisorySupport(boolean anonymousProducerAdvisorySupport) {
1536        this.anonymousProducerAdvisorySupport = anonymousProducerAdvisorySupport;
1537    }
1538
1539    public List<TransportConnector> getTransportConnectors() {
1540        return new ArrayList<>(transportConnectors);
1541    }
1542
1543    /**
1544     * Sets the transport connectors which this broker will listen on for new
1545     * clients
1546     *
1547     * @org.apache.xbean.Property
1548     *                            nestedType="org.apache.activemq.broker.TransportConnector"
1549     */
1550    public void setTransportConnectors(List<TransportConnector> transportConnectors) throws Exception {
1551        for (TransportConnector connector : transportConnectors) {
1552            addConnector(connector);
1553        }
1554    }
1555
1556    public TransportConnector getTransportConnectorByName(String name){
1557        for (TransportConnector transportConnector : transportConnectors){
1558           if (name.equals(transportConnector.getName())){
1559               return transportConnector;
1560           }
1561        }
1562        return null;
1563    }
1564
1565    public TransportConnector getTransportConnectorByScheme(String scheme){
1566        for (TransportConnector transportConnector : transportConnectors){
1567            if (scheme.equals(transportConnector.getUri().getScheme())){
1568                return transportConnector;
1569            }
1570        }
1571        return null;
1572    }
1573
1574    public List<NetworkConnector> getNetworkConnectors() {
1575        return new ArrayList<>(networkConnectors);
1576    }
1577
1578    public List<ProxyConnector> getProxyConnectors() {
1579        return new ArrayList<>(proxyConnectors);
1580    }
1581
1582    /**
1583     * Sets the network connectors which this broker will use to connect to
1584     * other brokers in a federated network
1585     *
1586     * @org.apache.xbean.Property
1587     *                            nestedType="org.apache.activemq.network.NetworkConnector"
1588     */
1589    public void setNetworkConnectors(List<?> networkConnectors) throws Exception {
1590        for (Object connector : networkConnectors) {
1591            addNetworkConnector((NetworkConnector) connector);
1592        }
1593    }
1594
1595    /**
1596     * Sets the network connectors which this broker will use to connect to
1597     * other brokers in a federated network
1598     */
1599    public void setProxyConnectors(List<?> proxyConnectors) throws Exception {
1600        for (Object connector : proxyConnectors) {
1601            addProxyConnector((ProxyConnector) connector);
1602        }
1603    }
1604
1605    public PolicyMap getDestinationPolicy() {
1606        return destinationPolicy;
1607    }
1608
1609    /**
1610     * Sets the destination specific policies available either for exact
1611     * destinations or for wildcard areas of destinations.
1612     */
1613    public void setDestinationPolicy(PolicyMap policyMap) {
1614        this.destinationPolicy = policyMap;
1615    }
1616
1617    public BrokerPlugin[] getPlugins() {
1618        return plugins;
1619    }
1620
1621    /**
1622     * Sets a number of broker plugins to install such as for security
1623     * authentication or authorization
1624     */
1625    public void setPlugins(BrokerPlugin[] plugins) {
1626        this.plugins = plugins;
1627    }
1628
1629    public MessageAuthorizationPolicy getMessageAuthorizationPolicy() {
1630        return messageAuthorizationPolicy;
1631    }
1632
1633    /**
1634     * Sets the policy used to decide if the current connection is authorized to
1635     * consume a given message
1636     */
1637    public void setMessageAuthorizationPolicy(MessageAuthorizationPolicy messageAuthorizationPolicy) {
1638        this.messageAuthorizationPolicy = messageAuthorizationPolicy;
1639    }
1640
1641    /**
1642     * Delete all messages from the persistent store
1643     *
1644     * @throws IOException
1645     */
1646    public void deleteAllMessages() throws IOException {
1647        getPersistenceAdapter().deleteAllMessages();
1648    }
1649
1650    public boolean isDeleteAllMessagesOnStartup() {
1651        return deleteAllMessagesOnStartup;
1652    }
1653
1654    /**
1655     * Sets whether or not all messages are deleted on startup - mostly only
1656     * useful for testing.
1657     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
1658     */
1659    public void setDeleteAllMessagesOnStartup(boolean deletePersistentMessagesOnStartup) {
1660        this.deleteAllMessagesOnStartup = deletePersistentMessagesOnStartup;
1661    }
1662
1663    public URI getVmConnectorURI() {
1664        if (vmConnectorURI == null) {
1665            try {
1666                vmConnectorURI = new URI("vm://" + getBrokerName());
1667            } catch (URISyntaxException e) {
1668                LOG.error("Badly formed URI from {}", getBrokerName(), e);
1669            }
1670        }
1671        return vmConnectorURI;
1672    }
1673
1674    public void setVmConnectorURI(URI vmConnectorURI) {
1675        this.vmConnectorURI = vmConnectorURI;
1676    }
1677
1678    public String getDefaultSocketURIString() {
1679        if (started.get()) {
1680            if (this.defaultSocketURIString == null) {
1681                for (TransportConnector tc:this.transportConnectors) {
1682                    String result = null;
1683                    try {
1684                        result = tc.getPublishableConnectString();
1685                    } catch (Exception e) {
1686                      LOG.warn("Failed to get the ConnectURI for {}", tc, e);
1687                    }
1688                    if (result != null) {
1689                        // find first publishable uri
1690                        if (tc.isUpdateClusterClients() || tc.isRebalanceClusterClients()) {
1691                            this.defaultSocketURIString = result;
1692                            break;
1693                        } else {
1694                        // or use the first defined
1695                            if (this.defaultSocketURIString == null) {
1696                                this.defaultSocketURIString = result;
1697                            }
1698                        }
1699                    }
1700                }
1701
1702            }
1703            return this.defaultSocketURIString;
1704        }
1705       return null;
1706    }
1707
1708    /**
1709     * @return Returns the shutdownOnMasterFailure.
1710     */
1711    public boolean isShutdownOnMasterFailure() {
1712        return shutdownOnMasterFailure;
1713    }
1714
1715    /**
1716     * @param shutdownOnMasterFailure
1717     *            The shutdownOnMasterFailure to set.
1718     */
1719    public void setShutdownOnMasterFailure(boolean shutdownOnMasterFailure) {
1720        this.shutdownOnMasterFailure = shutdownOnMasterFailure;
1721    }
1722
1723    public boolean isKeepDurableSubsActive() {
1724        return keepDurableSubsActive;
1725    }
1726
1727    public void setKeepDurableSubsActive(boolean keepDurableSubsActive) {
1728        this.keepDurableSubsActive = keepDurableSubsActive;
1729    }
1730
1731    public boolean isUseVirtualTopics() {
1732        return useVirtualTopics;
1733    }
1734
1735    /**
1736     * Sets whether or not <a
1737     * href="http://activemq.apache.org/virtual-destinations.html">Virtual
1738     * Topics</a> should be supported by default if they have not been
1739     * explicitly configured.
1740     */
1741    public void setUseVirtualTopics(boolean useVirtualTopics) {
1742        this.useVirtualTopics = useVirtualTopics;
1743    }
1744
1745    public DestinationInterceptor[] getDestinationInterceptors() {
1746        return destinationInterceptors;
1747    }
1748
1749    public boolean isUseMirroredQueues() {
1750        return useMirroredQueues;
1751    }
1752
1753    /**
1754     * Sets whether or not <a
1755     * href="http://activemq.apache.org/mirrored-queues.html">Mirrored
1756     * Queues</a> should be supported by default if they have not been
1757     * explicitly configured.
1758     */
1759    public void setUseMirroredQueues(boolean useMirroredQueues) {
1760        this.useMirroredQueues = useMirroredQueues;
1761    }
1762
1763    /**
1764     * Sets the destination interceptors to use
1765     */
1766    public void setDestinationInterceptors(DestinationInterceptor[] destinationInterceptors) {
1767        this.destinationInterceptors = destinationInterceptors;
1768    }
1769
1770    public ActiveMQDestination[] getDestinations() {
1771        return destinations;
1772    }
1773
1774    /**
1775     * Sets the destinations which should be loaded/created on startup
1776     */
1777    public void setDestinations(ActiveMQDestination[] destinations) {
1778        this.destinations = destinations;
1779    }
1780
1781    /**
1782     * @return the tempDataStore
1783     */
1784    public synchronized PListStore getTempDataStore() {
1785        if (tempDataStore == null) {
1786            if (!isPersistent()) {
1787                return null;
1788            }
1789
1790            try {
1791                PersistenceAdapter pa = getPersistenceAdapter();
1792                if( pa!=null && pa instanceof PListStore) {
1793                    return (PListStore) pa;
1794                }
1795            } catch (IOException e) {
1796                throw new RuntimeException(e);
1797            }
1798
1799            try {
1800                String clazz = "org.apache.activemq.store.kahadb.plist.PListStoreImpl";
1801                this.tempDataStore = (PListStore) getClass().getClassLoader().loadClass(clazz).newInstance();
1802                this.tempDataStore.setDirectory(getTmpDataDirectory());
1803                configureService(tempDataStore);
1804            } catch (ClassNotFoundException e) {
1805                throw new RuntimeException("Kahadb class PListStoreImpl not found. Add activemq-kahadb jar or set persistent to false on BrokerService.", e);
1806            } catch (Exception e) {
1807                throw new RuntimeException(e);
1808            }
1809        }
1810        return tempDataStore;
1811    }
1812
1813    /**
1814     * @param tempDataStore
1815     *            the tempDataStore to set
1816     */
1817    public void setTempDataStore(PListStore tempDataStore) {
1818        this.tempDataStore = tempDataStore;
1819        if (tempDataStore != null) {
1820            if (tmpDataDirectory == null) {
1821                tmpDataDirectory = tempDataStore.getDirectory();
1822            } else if (tempDataStore.getDirectory() == null) {
1823                tempDataStore.setDirectory(tmpDataDirectory);
1824            }
1825        }
1826        configureService(tempDataStore);
1827    }
1828
1829    public int getPersistenceThreadPriority() {
1830        return persistenceThreadPriority;
1831    }
1832
1833    public void setPersistenceThreadPriority(int persistenceThreadPriority) {
1834        this.persistenceThreadPriority = persistenceThreadPriority;
1835    }
1836
1837    /**
1838     * @return the useLocalHostBrokerName
1839     */
1840    public boolean isUseLocalHostBrokerName() {
1841        return this.useLocalHostBrokerName;
1842    }
1843
1844    /**
1845     * @param useLocalHostBrokerName
1846     *            the useLocalHostBrokerName to set
1847     */
1848    public void setUseLocalHostBrokerName(boolean useLocalHostBrokerName) {
1849        this.useLocalHostBrokerName = useLocalHostBrokerName;
1850        if (useLocalHostBrokerName && !started.get() && brokerName == null || brokerName == DEFAULT_BROKER_NAME) {
1851            brokerName = LOCAL_HOST_NAME;
1852        }
1853    }
1854
1855    /**
1856     * Looks up and lazily creates if necessary the destination for the given
1857     * JMS name
1858     */
1859    public Destination getDestination(ActiveMQDestination destination) throws Exception {
1860        return getBroker().addDestination(getAdminConnectionContext(), destination,false);
1861    }
1862
1863    public void removeDestination(ActiveMQDestination destination) throws Exception {
1864        getBroker().removeDestination(getAdminConnectionContext(), destination, 0);
1865    }
1866
1867    public int getProducerSystemUsagePortion() {
1868        return producerSystemUsagePortion;
1869    }
1870
1871    public void setProducerSystemUsagePortion(int producerSystemUsagePortion) {
1872        this.producerSystemUsagePortion = producerSystemUsagePortion;
1873    }
1874
1875    public int getConsumerSystemUsagePortion() {
1876        return consumerSystemUsagePortion;
1877    }
1878
1879    public void setConsumerSystemUsagePortion(int consumerSystemUsagePortion) {
1880        this.consumerSystemUsagePortion = consumerSystemUsagePortion;
1881    }
1882
1883    public boolean isSplitSystemUsageForProducersConsumers() {
1884        return splitSystemUsageForProducersConsumers;
1885    }
1886
1887    public void setSplitSystemUsageForProducersConsumers(boolean splitSystemUsageForProducersConsumers) {
1888        this.splitSystemUsageForProducersConsumers = splitSystemUsageForProducersConsumers;
1889    }
1890
1891    public boolean isMonitorConnectionSplits() {
1892        return monitorConnectionSplits;
1893    }
1894
1895    public void setMonitorConnectionSplits(boolean monitorConnectionSplits) {
1896        this.monitorConnectionSplits = monitorConnectionSplits;
1897    }
1898
1899    public int getTaskRunnerPriority() {
1900        return taskRunnerPriority;
1901    }
1902
1903    public void setTaskRunnerPriority(int taskRunnerPriority) {
1904        this.taskRunnerPriority = taskRunnerPriority;
1905    }
1906
1907    public boolean isDedicatedTaskRunner() {
1908        return dedicatedTaskRunner;
1909    }
1910
1911    public void setDedicatedTaskRunner(boolean dedicatedTaskRunner) {
1912        this.dedicatedTaskRunner = dedicatedTaskRunner;
1913    }
1914
1915    public boolean isCacheTempDestinations() {
1916        return cacheTempDestinations;
1917    }
1918
1919    public void setCacheTempDestinations(boolean cacheTempDestinations) {
1920        this.cacheTempDestinations = cacheTempDestinations;
1921    }
1922
1923    public int getTimeBeforePurgeTempDestinations() {
1924        return timeBeforePurgeTempDestinations;
1925    }
1926
1927    public void setTimeBeforePurgeTempDestinations(int timeBeforePurgeTempDestinations) {
1928        this.timeBeforePurgeTempDestinations = timeBeforePurgeTempDestinations;
1929    }
1930
1931    public boolean isUseTempMirroredQueues() {
1932        return useTempMirroredQueues;
1933    }
1934
1935    public void setUseTempMirroredQueues(boolean useTempMirroredQueues) {
1936        this.useTempMirroredQueues = useTempMirroredQueues;
1937    }
1938
1939    public synchronized JobSchedulerStore getJobSchedulerStore() {
1940
1941        // If support is off don't allow any scheduler even is user configured their own.
1942        if (!isSchedulerSupport()) {
1943            return null;
1944        }
1945
1946        // If the user configured their own we use it even if persistence is disabled since
1947        // we don't know anything about their implementation.
1948        if (jobSchedulerStore == null) {
1949
1950            if (!isPersistent()) {
1951                this.jobSchedulerStore = new InMemoryJobSchedulerStore();
1952                configureService(jobSchedulerStore);
1953                return this.jobSchedulerStore;
1954            }
1955
1956            try {
1957                PersistenceAdapter pa = getPersistenceAdapter();
1958                if (pa != null) {
1959                    this.jobSchedulerStore = pa.createJobSchedulerStore();
1960                    jobSchedulerStore.setDirectory(getSchedulerDirectoryFile());
1961                    configureService(jobSchedulerStore);
1962                    return this.jobSchedulerStore;
1963                }
1964            } catch (IOException e) {
1965                throw new RuntimeException(e);
1966            } catch (UnsupportedOperationException ex) {
1967                // It's ok if the store doesn't implement a scheduler.
1968            } catch (Exception e) {
1969                throw new RuntimeException(e);
1970            }
1971
1972            try {
1973                PersistenceAdapter pa = getPersistenceAdapter();
1974                if (pa != null && pa instanceof JobSchedulerStore) {
1975                    this.jobSchedulerStore = (JobSchedulerStore) pa;
1976                    configureService(jobSchedulerStore);
1977                    return this.jobSchedulerStore;
1978                }
1979            } catch (IOException e) {
1980                throw new RuntimeException(e);
1981            }
1982
1983            // Load the KahaDB store as a last resort, this only works if KahaDB is
1984            // included at runtime, otherwise this will fail.  User should disable
1985            // scheduler support if this fails.
1986            try {
1987                String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter";
1988                PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance();
1989                jobSchedulerStore = adaptor.createJobSchedulerStore();
1990                jobSchedulerStore.setDirectory(getSchedulerDirectoryFile());
1991                configureService(jobSchedulerStore);
1992                LOG.info("JobScheduler using directory: {}", getSchedulerDirectoryFile());
1993            } catch (Exception e) {
1994                throw new RuntimeException(e);
1995            }
1996        }
1997        return jobSchedulerStore;
1998    }
1999
2000    public void setJobSchedulerStore(JobSchedulerStore jobSchedulerStore) {
2001        this.jobSchedulerStore = jobSchedulerStore;
2002        configureService(jobSchedulerStore);
2003    }
2004
2005    //
2006    // Implementation methods
2007    // -------------------------------------------------------------------------
2008    /**
2009     * Handles any lazy-creation helper properties which are added to make
2010     * things easier to configure inside environments such as Spring
2011     *
2012     * @throws Exception
2013     */
2014    protected void processHelperProperties() throws Exception {
2015        if (transportConnectorURIs != null) {
2016            for (int i = 0; i < transportConnectorURIs.length; i++) {
2017                String uri = transportConnectorURIs[i];
2018                addConnector(uri);
2019            }
2020        }
2021        if (networkConnectorURIs != null) {
2022            for (int i = 0; i < networkConnectorURIs.length; i++) {
2023                String uri = networkConnectorURIs[i];
2024                addNetworkConnector(uri);
2025            }
2026        }
2027        if (jmsBridgeConnectors != null) {
2028            for (int i = 0; i < jmsBridgeConnectors.length; i++) {
2029                addJmsConnector(jmsBridgeConnectors[i]);
2030            }
2031        }
2032    }
2033
2034    /**
2035     * Check that the store usage limit is not greater than max usable
2036     * space and adjust if it is
2037     */
2038    protected void checkStoreUsageLimits() throws Exception {
2039        final SystemUsage usage = getSystemUsage();
2040
2041        if (getPersistenceAdapter() != null) {
2042            PersistenceAdapter adapter = getPersistenceAdapter();
2043            checkUsageLimit(adapter.getDirectory(), usage.getStoreUsage(), usage.getStoreUsage().getPercentLimit());
2044
2045            long maxJournalFileSize = 0;
2046            long storeLimit = usage.getStoreUsage().getLimit();
2047
2048            if (adapter instanceof JournaledStore) {
2049                maxJournalFileSize = ((JournaledStore) adapter).getJournalMaxFileLength();
2050            }
2051
2052            if (storeLimit > 0 && storeLimit < maxJournalFileSize) {
2053                LOG.error("Store limit is " + storeLimit / (1024 * 1024) +
2054                          " mb, whilst the max journal file size for the store is: " +
2055                          maxJournalFileSize / (1024 * 1024) + " mb, " +
2056                          "the store will not accept any data when used.");
2057
2058            }
2059        }
2060    }
2061
2062    /**
2063     * Check that temporary usage limit is not greater than max usable
2064     * space and adjust if it is
2065     */
2066    protected void checkTmpStoreUsageLimits() throws Exception {
2067        final SystemUsage usage = getSystemUsage();
2068
2069        File tmpDir = getTmpDataDirectory();
2070
2071        if (tmpDir != null) {
2072            checkUsageLimit(tmpDir, usage.getTempUsage(), usage.getTempUsage().getPercentLimit());
2073
2074            if (isPersistent()) {
2075                long maxJournalFileSize;
2076
2077                PListStore store = usage.getTempUsage().getStore();
2078                if (store != null && store instanceof JournaledStore) {
2079                    maxJournalFileSize = ((JournaledStore) store).getJournalMaxFileLength();
2080                } else {
2081                    maxJournalFileSize = DEFAULT_MAX_FILE_LENGTH;
2082                }
2083                long storeLimit = usage.getTempUsage().getLimit();
2084
2085                if (storeLimit > 0 && storeLimit < maxJournalFileSize) {
2086                    LOG.error("Temporary Store limit is " + storeLimit / (1024 * 1024) +
2087                              " mb, whilst the max journal file size for the temporary store is: " +
2088                              maxJournalFileSize / (1024 * 1024) + " mb, " +
2089                              "the temp store will not accept any data when used.");
2090                }
2091            }
2092        }
2093    }
2094
2095    protected void checkUsageLimit(File dir, PercentLimitUsage<?> storeUsage, int percentLimit) throws ConfigurationException {
2096        if (dir != null) {
2097            dir = StoreUtil.findParentDirectory(dir);
2098            String storeName = storeUsage instanceof StoreUsage ? "Store" : "Temporary Store";
2099            long storeLimit = storeUsage.getLimit();
2100            long storeCurrent = storeUsage.getUsage();
2101            long totalSpace = storeUsage.getTotal() > 0 ? storeUsage.getTotal() : dir.getTotalSpace();
2102            long totalUsableSpace = (storeUsage.getTotal() > 0 ? storeUsage.getTotal() : dir.getUsableSpace()) + storeCurrent;
2103            if (totalUsableSpace < 0 || totalSpace < 0) {
2104                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";
2105                LOG.error(message);
2106                throw new ConfigurationException(message);
2107            }
2108            //compute byte value of the percent limit
2109            long bytePercentLimit = totalSpace * percentLimit / 100;
2110            int oneMeg = 1024 * 1024;
2111
2112            //Check if the store limit is less than the percent Limit that was set and also
2113            //the usable space...this means we can grow the store larger
2114            //Changes in partition size (total space) as well as changes in usable space should
2115            //be detected here
2116            if (diskUsageCheckRegrowThreshold > -1 && percentLimit > 0
2117                    && storeUsage.getTotal() == 0
2118                    && storeLimit < bytePercentLimit && storeLimit < totalUsableSpace){
2119
2120                // set the limit to be bytePercentLimit or usableSpace if
2121                // usableSpace is less than the percentLimit
2122                long newLimit = bytePercentLimit > totalUsableSpace ? totalUsableSpace : bytePercentLimit;
2123
2124                //To prevent changing too often, check threshold
2125                if (newLimit - storeLimit >= diskUsageCheckRegrowThreshold) {
2126                    LOG.info("Usable disk space has been increased, attempting to regrow " + storeName + " limit to "
2127                            + percentLimit + "% of the partition size.");
2128                    storeUsage.setLimit(newLimit);
2129                    LOG.info(storeName + " limit has been increased to " + newLimit * 100 / totalSpace
2130                            + "% (" + newLimit / oneMeg + " mb) of the partition size.");
2131                }
2132
2133            //check if the limit is too large for the amount of usable space
2134            } else if (storeLimit > totalUsableSpace) {
2135                final String message = storeName + " limit is " +  storeLimit / oneMeg
2136                        + " mb (current store usage is " + storeCurrent / oneMeg
2137                        + " mb). The data directory: " + dir.getAbsolutePath()
2138                        + " only has " + totalUsableSpace / oneMeg
2139                        + " mb of usable space.";
2140
2141                if (!isAdjustUsageLimits()) {
2142                    LOG.error(message);
2143                    throw new ConfigurationException(message);
2144                }
2145
2146                if (percentLimit > 0) {
2147                    LOG.warn(storeName + " limit has been set to "
2148                            + percentLimit + "% (" + bytePercentLimit / oneMeg + " mb)"
2149                            + " of the partition size but there is not enough usable space."
2150                            + " The current store limit (which may have been adjusted by a"
2151                            + " previous usage limit check) is set to (" + storeLimit / oneMeg + " mb)"
2152                            + " but only " + totalUsableSpace * 100 / totalSpace + "% (" + totalUsableSpace / oneMeg + " mb)"
2153                            + " is available - resetting limit");
2154                } else {
2155                    LOG.warn(message + " - resetting to maximum available disk space: " +
2156                            totalUsableSpace / oneMeg + " mb");
2157                }
2158                storeUsage.setLimit(totalUsableSpace);
2159            }
2160        }
2161    }
2162
2163    /**
2164     * Schedules a periodic task based on schedulePeriodForDiskLimitCheck to
2165     * update store and temporary store limits if the amount of available space
2166     * plus current store size is less than the existing configured limit
2167     */
2168    protected void scheduleDiskUsageLimitsCheck() throws IOException {
2169        if (schedulePeriodForDiskUsageCheck > 0 &&
2170                (getPersistenceAdapter() != null || getTmpDataDirectory() != null)) {
2171            Runnable diskLimitCheckTask = new Runnable() {
2172                @Override
2173                public void run() {
2174                    try {
2175                        checkStoreUsageLimits();
2176                    } catch (Exception e) {
2177                        LOG.error("Failed to check persistent disk usage limits", e);
2178                    }
2179
2180                    try {
2181                        checkTmpStoreUsageLimits();
2182                    } catch (Exception e) {
2183                        LOG.error("Failed to check temporary store usage limits", e);
2184                    }
2185                }
2186            };
2187            scheduler.executePeriodically(diskLimitCheckTask, schedulePeriodForDiskUsageCheck);
2188        }
2189    }
2190
2191    protected void checkMemorySystemUsageLimits() throws Exception {
2192        final SystemUsage usage = getSystemUsage();
2193        long memLimit = usage.getMemoryUsage().getLimit();
2194        long jvmLimit = Runtime.getRuntime().maxMemory();
2195
2196        if (memLimit > jvmLimit) {
2197            final String message = "Memory Usage for the Broker (" + memLimit / (1024 * 1024)
2198                    + "mb) is more than the maximum available for the JVM: " + jvmLimit / (1024 * 1024);
2199
2200            if (adjustUsageLimits) {
2201                usage.getMemoryUsage().setPercentOfJvmHeap(70);
2202                LOG.warn(message + " mb - resetting to 70% of maximum available: " + (usage.getMemoryUsage().getLimit() / (1024 * 1024)) + " mb");
2203            } else {
2204                LOG.error(message);
2205                throw new ConfigurationException(message);
2206            }
2207        }
2208    }
2209
2210    protected void checkStoreSystemUsageLimits() throws Exception {
2211        final SystemUsage usage = getSystemUsage();
2212
2213        //Check the persistent store and temp store limits if they exist
2214        //and schedule a periodic check to update disk limits if
2215        //schedulePeriodForDiskLimitCheck is set
2216        checkStoreUsageLimits();
2217        checkTmpStoreUsageLimits();
2218        scheduleDiskUsageLimitsCheck();
2219
2220        if (getJobSchedulerStore() != null) {
2221            JobSchedulerStore scheduler = getJobSchedulerStore();
2222            File schedulerDir = scheduler.getDirectory();
2223            if (schedulerDir != null) {
2224
2225                String schedulerDirPath = schedulerDir.getAbsolutePath();
2226                if (!schedulerDir.isAbsolute()) {
2227                    schedulerDir = new File(schedulerDirPath);
2228                }
2229
2230                while (schedulerDir != null && !schedulerDir.isDirectory()) {
2231                    schedulerDir = schedulerDir.getParentFile();
2232                }
2233                long schedulerLimit = usage.getJobSchedulerUsage().getLimit();
2234                long dirFreeSpace = schedulerDir.getUsableSpace();
2235                if (schedulerLimit > dirFreeSpace) {
2236                    LOG.warn("Job Scheduler Store limit is " + schedulerLimit / (1024 * 1024) +
2237                             " mb, whilst the data directory: " + schedulerDir.getAbsolutePath() +
2238                             " only has " + dirFreeSpace / (1024 * 1024) + " mb of usable space - resetting to " +
2239                            dirFreeSpace / (1024 * 1024) + " mb.");
2240                    usage.getJobSchedulerUsage().setLimit(dirFreeSpace);
2241                }
2242            }
2243        }
2244    }
2245
2246    public void stopAllConnectors(ServiceStopper stopper) {
2247        for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) {
2248            NetworkConnector connector = iter.next();
2249            unregisterNetworkConnectorMBean(connector);
2250            stopper.stop(connector);
2251        }
2252        for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) {
2253            ProxyConnector connector = iter.next();
2254            stopper.stop(connector);
2255        }
2256        for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) {
2257            JmsConnector connector = iter.next();
2258            stopper.stop(connector);
2259        }
2260        for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) {
2261            TransportConnector connector = iter.next();
2262            try {
2263                unregisterConnectorMBean(connector);
2264            } catch (IOException e) {
2265            }
2266            stopper.stop(connector);
2267        }
2268    }
2269
2270    protected TransportConnector registerConnectorMBean(TransportConnector connector) throws IOException {
2271        try {
2272            ObjectName objectName = createConnectorObjectName(connector);
2273            connector = connector.asManagedConnector(getManagementContext(), objectName);
2274            ConnectorViewMBean view = new ConnectorView(connector);
2275            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2276            return connector;
2277        } catch (Throwable e) {
2278            throw IOExceptionSupport.create("Transport Connector could not be registered in JMX: " + e, e);
2279        }
2280    }
2281
2282    protected void unregisterConnectorMBean(TransportConnector connector) throws IOException {
2283        if (isUseJmx()) {
2284            try {
2285                ObjectName objectName = createConnectorObjectName(connector);
2286                getManagementContext().unregisterMBean(objectName);
2287            } catch (Throwable e) {
2288                throw IOExceptionSupport.create(
2289                        "Transport Connector could not be unregistered in JMX: " + e.getMessage(), e);
2290            }
2291        }
2292    }
2293
2294    protected PersistenceAdapter registerPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException {
2295        return adaptor;
2296    }
2297
2298    protected void unregisterPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException {
2299        if (isUseJmx()) {}
2300    }
2301
2302    private ObjectName createConnectorObjectName(TransportConnector connector) throws MalformedObjectNameException {
2303        return BrokerMBeanSupport.createConnectorName(getBrokerObjectName(), "clientConnectors", connector.getName());
2304    }
2305
2306    public void registerNetworkConnectorMBean(NetworkConnector connector) throws IOException {
2307        NetworkConnectorViewMBean view = new NetworkConnectorView(connector);
2308        try {
2309            ObjectName objectName = createNetworkConnectorObjectName(connector);
2310            connector.setObjectName(objectName);
2311            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2312        } catch (Throwable e) {
2313            throw IOExceptionSupport.create("Network Connector could not be registered in JMX: " + e.getMessage(), e);
2314        }
2315    }
2316
2317    public ObjectName createNetworkConnectorObjectName(NetworkConnector connector) throws MalformedObjectNameException {
2318        return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "networkConnectors", connector.getName());
2319    }
2320
2321    public ObjectName createDuplexNetworkConnectorObjectName(String transport) throws MalformedObjectNameException {
2322        return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "duplexNetworkConnectors", transport);
2323    }
2324
2325    protected void unregisterNetworkConnectorMBean(NetworkConnector connector) {
2326        if (isUseJmx()) {
2327            try {
2328                ObjectName objectName = createNetworkConnectorObjectName(connector);
2329                getManagementContext().unregisterMBean(objectName);
2330            } catch (Exception e) {
2331                LOG.warn("Network Connector could not be unregistered from JMX due " + e.getMessage() + ". This exception is ignored.", e);
2332            }
2333        }
2334    }
2335
2336    protected void registerProxyConnectorMBean(ProxyConnector connector) throws IOException {
2337        ProxyConnectorView view = new ProxyConnectorView(connector);
2338        try {
2339            ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "proxyConnectors", connector.getName());
2340            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2341        } catch (Throwable e) {
2342            throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e);
2343        }
2344    }
2345
2346    protected void registerJmsConnectorMBean(JmsConnector connector) throws IOException {
2347        JmsConnectorView view = new JmsConnectorView(connector);
2348        try {
2349            ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "jmsConnectors", connector.getName());
2350            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2351        } catch (Throwable e) {
2352            throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e);
2353        }
2354    }
2355
2356    /**
2357     * Factory method to create a new broker
2358     *
2359     * @throws Exception
2360     */
2361    protected Broker createBroker() throws Exception {
2362        regionBroker = createRegionBroker();
2363        Broker broker = addInterceptors(regionBroker);
2364        // Add a filter that will stop access to the broker once stopped
2365        broker = new MutableBrokerFilter(broker) {
2366            Broker old;
2367
2368            @Override
2369            public void stop() throws Exception {
2370                old = this.next.getAndSet(new ErrorBroker("Broker has been stopped: " + this) {
2371                    // Just ignore additional stop actions.
2372                    @Override
2373                    public void stop() throws Exception {
2374                    }
2375                });
2376                old.stop();
2377            }
2378
2379            @Override
2380            public void start() throws Exception {
2381                if (forceStart && old != null) {
2382                    this.next.set(old);
2383                }
2384                getNext().start();
2385            }
2386        };
2387        return broker;
2388    }
2389
2390    /**
2391     * Factory method to create the core region broker onto which interceptors
2392     * are added
2393     *
2394     * @throws Exception
2395     */
2396    protected Broker createRegionBroker() throws Exception {
2397        if (destinationInterceptors == null) {
2398            destinationInterceptors = createDefaultDestinationInterceptor();
2399        }
2400        configureServices(destinationInterceptors);
2401        DestinationInterceptor destinationInterceptor = new CompositeDestinationInterceptor(destinationInterceptors);
2402        if (destinationFactory == null) {
2403            destinationFactory = new DestinationFactoryImpl(this, getTaskRunnerFactory(), getPersistenceAdapter());
2404        }
2405        return createRegionBroker(destinationInterceptor);
2406    }
2407
2408    protected Broker createRegionBroker(DestinationInterceptor destinationInterceptor) throws IOException {
2409        RegionBroker regionBroker;
2410        if (isUseJmx()) {
2411            try {
2412                regionBroker = new ManagedRegionBroker(this, getManagementContext(), getBrokerObjectName(),
2413                    getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory, destinationInterceptor,getScheduler(),getExecutor());
2414            } catch(MalformedObjectNameException me){
2415                LOG.warn("Cannot create ManagedRegionBroker due " + me.getMessage(), me);
2416                throw new IOException(me);
2417            }
2418        } else {
2419            regionBroker = new RegionBroker(this, getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory,
2420                    destinationInterceptor,getScheduler(),getExecutor());
2421        }
2422        destinationFactory.setRegionBroker(regionBroker);
2423        regionBroker.setKeepDurableSubsActive(keepDurableSubsActive);
2424        regionBroker.setBrokerName(getBrokerName());
2425        regionBroker.getDestinationStatistics().setEnabled(enableStatistics);
2426        regionBroker.setAllowTempAutoCreationOnSend(isAllowTempAutoCreationOnSend());
2427        if (brokerId != null) {
2428            regionBroker.setBrokerId(brokerId);
2429        }
2430        return regionBroker;
2431    }
2432
2433    /**
2434     * Create the default destination interceptor
2435     */
2436    protected DestinationInterceptor[] createDefaultDestinationInterceptor() {
2437        List<DestinationInterceptor> answer = new ArrayList<>();
2438        if (isUseVirtualTopics()) {
2439            VirtualDestinationInterceptor interceptor = new VirtualDestinationInterceptor();
2440            VirtualTopic virtualTopic = new VirtualTopic();
2441            virtualTopic.setName("VirtualTopic.>");
2442            VirtualDestination[] virtualDestinations = { virtualTopic };
2443            interceptor.setVirtualDestinations(virtualDestinations);
2444            answer.add(interceptor);
2445        }
2446        if (isUseMirroredQueues()) {
2447            MirroredQueue interceptor = new MirroredQueue();
2448            answer.add(interceptor);
2449        }
2450        DestinationInterceptor[] array = new DestinationInterceptor[answer.size()];
2451        answer.toArray(array);
2452        return array;
2453    }
2454
2455    /**
2456     * Strategy method to add interceptors to the broker
2457     *
2458     * @throws IOException
2459     */
2460    protected Broker addInterceptors(Broker broker) throws Exception {
2461        if (isSchedulerSupport()) {
2462            SchedulerBroker sb = new SchedulerBroker(this, broker, getJobSchedulerStore());
2463            if (isUseJmx()) {
2464                JobSchedulerViewMBean view = new JobSchedulerView(sb.getJobScheduler());
2465                try {
2466                    ObjectName objectName = BrokerMBeanSupport.createJobSchedulerServiceName(getBrokerObjectName());
2467                    AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2468                    this.adminView.setJMSJobScheduler(objectName);
2469                } catch (Throwable e) {
2470                    throw IOExceptionSupport.create("JobScheduler could not be registered in JMX: "
2471                            + e.getMessage(), e);
2472                }
2473            }
2474            broker = sb;
2475        }
2476        if (isUseJmx()) {
2477            HealthViewMBean statusView = new HealthView((ManagedRegionBroker)getRegionBroker());
2478            try {
2479                ObjectName objectName = BrokerMBeanSupport.createHealthServiceName(getBrokerObjectName());
2480                AnnotatedMBean.registerMBean(getManagementContext(), statusView, objectName);
2481            } catch (Throwable e) {
2482                throw IOExceptionSupport.create("Status MBean could not be registered in JMX: "
2483                        + e.getMessage(), e);
2484            }
2485        }
2486        if (isAdvisorySupport()) {
2487            broker = new AdvisoryBroker(broker);
2488        }
2489        broker = new CompositeDestinationBroker(broker);
2490        broker = new TransactionBroker(broker, getPersistenceAdapter().createTransactionStore());
2491        if (isPopulateJMSXUserID()) {
2492            UserIDBroker userIDBroker = new UserIDBroker(broker);
2493            userIDBroker.setUseAuthenticatePrincipal(isUseAuthenticatedPrincipalForJMSXUserID());
2494            broker = userIDBroker;
2495        }
2496        if (isMonitorConnectionSplits()) {
2497            broker = new ConnectionSplitBroker(broker);
2498        }
2499        if (plugins != null) {
2500            for (int i = 0; i < plugins.length; i++) {
2501                BrokerPlugin plugin = plugins[i];
2502                broker = plugin.installPlugin(broker);
2503            }
2504        }
2505        return broker;
2506    }
2507
2508    protected PersistenceAdapter createPersistenceAdapter() throws IOException {
2509        if (isPersistent()) {
2510            PersistenceAdapterFactory fac = getPersistenceFactory();
2511            if (fac != null) {
2512                return fac.createPersistenceAdapter();
2513            } else {
2514                try {
2515                    String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter";
2516                    PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance();
2517                    File dir = new File(getBrokerDataDirectory(),"KahaDB");
2518                    adaptor.setDirectory(dir);
2519                    return adaptor;
2520                } catch (Throwable e) {
2521                    throw IOExceptionSupport.create(e);
2522                }
2523            }
2524        } else {
2525            return new MemoryPersistenceAdapter();
2526        }
2527    }
2528
2529    protected ObjectName createBrokerObjectName() throws MalformedObjectNameException  {
2530        return BrokerMBeanSupport.createBrokerObjectName(getManagementContext().getJmxDomainName(), getBrokerName());
2531    }
2532
2533    protected TransportConnector createTransportConnector(URI brokerURI) throws Exception {
2534        TransportServer transport = TransportFactorySupport.bind(this, brokerURI);
2535        return new TransportConnector(transport);
2536    }
2537
2538    /**
2539     * Extracts the port from the options
2540     */
2541    protected Object getPort(Map<?,?> options) {
2542        Object port = options.get("port");
2543        if (port == null) {
2544            port = DEFAULT_PORT;
2545            LOG.warn("No port specified so defaulting to: {}", port);
2546        }
2547        return port;
2548    }
2549
2550    protected void addShutdownHook() {
2551        if (useShutdownHook) {
2552            shutdownHook = new Thread("ActiveMQ ShutdownHook") {
2553                @Override
2554                public void run() {
2555                    containerShutdown();
2556                }
2557            };
2558            Runtime.getRuntime().addShutdownHook(shutdownHook);
2559        }
2560    }
2561
2562    protected void removeShutdownHook() {
2563        if (shutdownHook != null) {
2564            try {
2565                Runtime.getRuntime().removeShutdownHook(shutdownHook);
2566            } catch (Exception e) {
2567                LOG.debug("Caught exception, must be shutting down. This exception is ignored.", e);
2568            }
2569        }
2570    }
2571
2572    /**
2573     * Sets hooks to be executed when broker shut down
2574     *
2575     * @org.apache.xbean.Property
2576     */
2577    public void setShutdownHooks(List<Runnable> hooks) throws Exception {
2578        for (Runnable hook : hooks) {
2579            addShutdownHook(hook);
2580        }
2581    }
2582
2583    /**
2584     * Causes a clean shutdown of the container when the VM is being shut down
2585     */
2586    protected void containerShutdown() {
2587        try {
2588            stop();
2589        } catch (IOException e) {
2590            Throwable linkedException = e.getCause();
2591            if (linkedException != null) {
2592                logError("Failed to shut down: " + e + ". Reason: " + linkedException, linkedException);
2593            } else {
2594                logError("Failed to shut down: " + e, e);
2595            }
2596            if (!useLoggingForShutdownErrors) {
2597                e.printStackTrace(System.err);
2598            }
2599        } catch (Exception e) {
2600            logError("Failed to shut down: " + e, e);
2601        }
2602    }
2603
2604    protected void logError(String message, Throwable e) {
2605        if (useLoggingForShutdownErrors) {
2606            LOG.error("Failed to shut down: " + e);
2607        } else {
2608            System.err.println("Failed to shut down: " + e);
2609        }
2610    }
2611
2612    /**
2613     * Starts any configured destinations on startup
2614     */
2615    protected void startDestinations() throws Exception {
2616        if (destinations != null) {
2617            ConnectionContext adminConnectionContext = getAdminConnectionContext();
2618            for (int i = 0; i < destinations.length; i++) {
2619                ActiveMQDestination destination = destinations[i];
2620                getBroker().addDestination(adminConnectionContext, destination,true);
2621            }
2622        }
2623        if (isUseVirtualTopics()) {
2624            startVirtualConsumerDestinations();
2625        }
2626    }
2627
2628    /**
2629     * Returns the broker's administration connection context used for
2630     * configuring the broker at startup
2631     */
2632    public ConnectionContext getAdminConnectionContext() throws Exception {
2633        return BrokerSupport.getConnectionContext(getBroker());
2634    }
2635
2636    protected void startManagementContext() throws Exception {
2637        getManagementContext().setBrokerName(brokerName);
2638        getManagementContext().start();
2639        adminView = new BrokerView(this, null);
2640        ObjectName objectName = getBrokerObjectName();
2641        AnnotatedMBean.registerMBean(getManagementContext(), adminView, objectName);
2642    }
2643
2644    /**
2645     * Start all transport and network connections, proxies and bridges
2646     *
2647     * @throws Exception
2648     */
2649    public void startAllConnectors() throws Exception {
2650        final Set<ActiveMQDestination> durableDestinations = getBroker().getDurableDestinations();
2651        List<TransportConnector> al = new ArrayList<>();
2652        for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) {
2653            TransportConnector connector = iter.next();
2654            al.add(startTransportConnector(connector));
2655        }
2656        if (al.size() > 0) {
2657            // let's clear the transportConnectors list and replace it with
2658            // the started transportConnector instances
2659            this.transportConnectors.clear();
2660            setTransportConnectors(al);
2661        }
2662        this.slave = false;
2663        if (!stopped.get()) {
2664            ThreadPoolExecutor networkConnectorStartExecutor = null;
2665            if (isNetworkConnectorStartAsync()) {
2666                // spin up as many threads as needed
2667                networkConnectorStartExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
2668                    10, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
2669                    new ThreadFactory() {
2670                        int count=0;
2671                        @Override
2672                        public Thread newThread(Runnable runnable) {
2673                            Thread thread = new Thread(runnable, "NetworkConnector Start Thread-" +(count++));
2674                            thread.setDaemon(true);
2675                            return thread;
2676                        }
2677                    });
2678            }
2679
2680            for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) {
2681                final NetworkConnector connector = iter.next();
2682                connector.setLocalUri(getVmConnectorURI());
2683                startNetworkConnector(connector, durableDestinations, networkConnectorStartExecutor);
2684            }
2685            if (networkConnectorStartExecutor != null) {
2686                // executor done when enqueued tasks are complete
2687                ThreadPoolUtils.shutdown(networkConnectorStartExecutor);
2688            }
2689
2690            for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) {
2691                ProxyConnector connector = iter.next();
2692                connector.start();
2693            }
2694            for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) {
2695                JmsConnector connector = iter.next();
2696                connector.start();
2697            }
2698            for (Service service : services) {
2699                configureService(service);
2700                service.start();
2701            }
2702        }
2703    }
2704
2705    public void startNetworkConnector(final NetworkConnector connector,
2706            final ThreadPoolExecutor networkConnectorStartExecutor) throws Exception {
2707        startNetworkConnector(connector, getBroker().getDurableDestinations(), networkConnectorStartExecutor);
2708    }
2709
2710    public void startNetworkConnector(final NetworkConnector connector,
2711            final Set<ActiveMQDestination> durableDestinations,
2712            final ThreadPoolExecutor networkConnectorStartExecutor) throws Exception {
2713        connector.setBrokerName(getBrokerName());
2714        //set the durable destinations to match the broker if not set on the connector
2715        if (connector.getDurableDestinations() == null) {
2716            connector.setDurableDestinations(durableDestinations);
2717        }
2718        String defaultSocketURI = getDefaultSocketURIString();
2719        if (defaultSocketURI != null) {
2720            connector.setBrokerURL(defaultSocketURI);
2721        }
2722        //If using the runtime plugin to start a network connector then the mbean needs
2723        //to be added, under normal start it will already exist so check for InstanceNotFoundException
2724        if (isUseJmx()) {
2725            ObjectName networkMbean = createNetworkConnectorObjectName(connector);
2726            try {
2727                getManagementContext().getObjectInstance(networkMbean);
2728            } catch (InstanceNotFoundException e) {
2729                LOG.debug("Network connector MBean {} not found, registering", networkMbean);
2730                registerNetworkConnectorMBean(connector);
2731            }
2732        }
2733        if (networkConnectorStartExecutor != null) {
2734            networkConnectorStartExecutor.execute(new Runnable() {
2735                @Override
2736                public void run() {
2737                    try {
2738                        LOG.info("Async start of {}", connector);
2739                        connector.start();
2740                    } catch(Exception e) {
2741                        LOG.error("Async start of network connector: {} failed", connector, e);
2742                    }
2743                }
2744            });
2745        } else {
2746            connector.start();
2747        }
2748    }
2749
2750    public TransportConnector startTransportConnector(TransportConnector connector) throws Exception {
2751        connector.setBrokerService(this);
2752        connector.setTaskRunnerFactory(getTaskRunnerFactory());
2753        MessageAuthorizationPolicy policy = getMessageAuthorizationPolicy();
2754        if (policy != null) {
2755            connector.setMessageAuthorizationPolicy(policy);
2756        }
2757        if (isUseJmx()) {
2758            connector = registerConnectorMBean(connector);
2759        }
2760        connector.getStatistics().setEnabled(enableStatistics);
2761        connector.start();
2762        return connector;
2763    }
2764
2765    /**
2766     * Perform any custom dependency injection
2767     */
2768    protected void configureServices(Object[] services) {
2769        for (Object service : services) {
2770            configureService(service);
2771        }
2772    }
2773
2774    /**
2775     * Perform any custom dependency injection
2776     */
2777    protected void configureService(Object service) {
2778        if (service instanceof BrokerServiceAware) {
2779            BrokerServiceAware serviceAware = (BrokerServiceAware) service;
2780            serviceAware.setBrokerService(this);
2781        }
2782    }
2783
2784    public void handleIOException(IOException exception) {
2785        if (ioExceptionHandler != null) {
2786            ioExceptionHandler.handle(exception);
2787         } else {
2788            LOG.info("No IOExceptionHandler registered, ignoring IO exception", exception);
2789         }
2790    }
2791
2792    protected void startVirtualConsumerDestinations() throws Exception {
2793        checkStartException();
2794        ConnectionContext adminConnectionContext = getAdminConnectionContext();
2795        Set<ActiveMQDestination> destinations = destinationFactory.getDestinations();
2796        DestinationFilter filter = getVirtualTopicConsumerDestinationFilter();
2797        if (!destinations.isEmpty()) {
2798            for (ActiveMQDestination destination : destinations) {
2799                if (filter.matches(destination) == true) {
2800                    broker.addDestination(adminConnectionContext, destination, false);
2801                }
2802            }
2803        }
2804    }
2805
2806    private DestinationFilter getVirtualTopicConsumerDestinationFilter() {
2807        // created at startup, so no sync needed
2808        if (virtualConsumerDestinationFilter == null) {
2809            Set <ActiveMQQueue> consumerDestinations = new HashSet<>();
2810            if (destinationInterceptors != null) {
2811                for (DestinationInterceptor interceptor : destinationInterceptors) {
2812                    if (interceptor instanceof VirtualDestinationInterceptor) {
2813                        VirtualDestinationInterceptor virtualDestinationInterceptor = (VirtualDestinationInterceptor) interceptor;
2814                        for (VirtualDestination virtualDestination: virtualDestinationInterceptor.getVirtualDestinations()) {
2815                            if (virtualDestination instanceof VirtualTopic) {
2816                                consumerDestinations.add(new ActiveMQQueue(((VirtualTopic) virtualDestination).getPrefix() + DestinationFilter.ANY_DESCENDENT));
2817                            }
2818                            if (isUseVirtualDestSubs()) {
2819                                try {
2820                                    broker.virtualDestinationAdded(getAdminConnectionContext(), virtualDestination);
2821                                    LOG.debug("Adding virtual destination: {}", virtualDestination);
2822                                } catch (Exception e) {
2823                                    LOG.warn("Could not fire virtual destination consumer advisory", e);
2824                                }
2825                            }
2826                        }
2827                    }
2828                }
2829            }
2830            ActiveMQQueue filter = new ActiveMQQueue();
2831            filter.setCompositeDestinations(consumerDestinations.toArray(new ActiveMQDestination[]{}));
2832            virtualConsumerDestinationFilter = DestinationFilter.parseFilter(filter);
2833        }
2834        return virtualConsumerDestinationFilter;
2835    }
2836
2837    protected synchronized ThreadPoolExecutor getExecutor() {
2838        if (this.executor == null) {
2839            this.executor = new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
2840
2841                private long i = 0;
2842
2843                @Override
2844                public Thread newThread(Runnable runnable) {
2845                    this.i++;
2846                    Thread thread = new Thread(runnable, "ActiveMQ BrokerService.worker." + this.i);
2847                    thread.setDaemon(true);
2848                    thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
2849                        @Override
2850                        public void uncaughtException(final Thread t, final Throwable e) {
2851                            LOG.error("Error in thread '{}'", t.getName(), e);
2852                        }
2853                    });
2854                    return thread;
2855                }
2856            }, new RejectedExecutionHandler() {
2857                @Override
2858                public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
2859                    try {
2860                        executor.getQueue().offer(r, 60, TimeUnit.SECONDS);
2861                    } catch (InterruptedException e) {
2862                        throw new RejectedExecutionException("Interrupted waiting for BrokerService.worker");
2863                    }
2864
2865                    throw new RejectedExecutionException("Timed Out while attempting to enqueue Task.");
2866                }
2867            });
2868        }
2869        return this.executor;
2870    }
2871
2872    public synchronized Scheduler getScheduler() {
2873        if (this.scheduler==null) {
2874            this.scheduler = new Scheduler("ActiveMQ Broker["+getBrokerName()+"] Scheduler");
2875            try {
2876                this.scheduler.start();
2877            } catch (Exception e) {
2878               LOG.error("Failed to start Scheduler", e);
2879            }
2880        }
2881        return this.scheduler;
2882    }
2883
2884    public Broker getRegionBroker() {
2885        return regionBroker;
2886    }
2887
2888    public void setRegionBroker(Broker regionBroker) {
2889        this.regionBroker = regionBroker;
2890    }
2891
2892    public final void removePreShutdownHook(final Runnable hook) {
2893        preShutdownHooks.remove(hook);
2894    }
2895
2896    public void addShutdownHook(Runnable hook) {
2897        synchronized (shutdownHooks) {
2898            shutdownHooks.add(hook);
2899        }
2900    }
2901
2902    public void removeShutdownHook(Runnable hook) {
2903        synchronized (shutdownHooks) {
2904            shutdownHooks.remove(hook);
2905        }
2906    }
2907
2908    public boolean isSystemExitOnShutdown() {
2909        return systemExitOnShutdown;
2910    }
2911
2912    /**
2913     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2914     */
2915    public void setSystemExitOnShutdown(boolean systemExitOnShutdown) {
2916        this.systemExitOnShutdown = systemExitOnShutdown;
2917    }
2918
2919    public int getSystemExitOnShutdownExitCode() {
2920        return systemExitOnShutdownExitCode;
2921    }
2922
2923    public void setSystemExitOnShutdownExitCode(int systemExitOnShutdownExitCode) {
2924        this.systemExitOnShutdownExitCode = systemExitOnShutdownExitCode;
2925    }
2926
2927    public SslContext getSslContext() {
2928        return sslContext;
2929    }
2930
2931    public void setSslContext(SslContext sslContext) {
2932        this.sslContext = sslContext;
2933    }
2934
2935    public boolean isShutdownOnSlaveFailure() {
2936        return shutdownOnSlaveFailure;
2937    }
2938
2939    /**
2940     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2941     */
2942    public void setShutdownOnSlaveFailure(boolean shutdownOnSlaveFailure) {
2943        this.shutdownOnSlaveFailure = shutdownOnSlaveFailure;
2944    }
2945
2946    public boolean isWaitForSlave() {
2947        return waitForSlave;
2948    }
2949
2950    /**
2951     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2952     */
2953    public void setWaitForSlave(boolean waitForSlave) {
2954        this.waitForSlave = waitForSlave;
2955    }
2956
2957    public long getWaitForSlaveTimeout() {
2958        return this.waitForSlaveTimeout;
2959    }
2960
2961    public void setWaitForSlaveTimeout(long waitForSlaveTimeout) {
2962        this.waitForSlaveTimeout = waitForSlaveTimeout;
2963    }
2964
2965    /**
2966     * Get the passiveSlave
2967     * @return the passiveSlave
2968     */
2969    public boolean isPassiveSlave() {
2970        return this.passiveSlave;
2971    }
2972
2973    /**
2974     * Set the passiveSlave
2975     * @param passiveSlave the passiveSlave to set
2976     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2977     */
2978    public void setPassiveSlave(boolean passiveSlave) {
2979        this.passiveSlave = passiveSlave;
2980    }
2981
2982    /**
2983     * override the Default IOException handler, called when persistence adapter
2984     * has experiences File or JDBC I/O Exceptions
2985     *
2986     * @param ioExceptionHandler
2987     */
2988    public void setIoExceptionHandler(IOExceptionHandler ioExceptionHandler) {
2989        configureService(ioExceptionHandler);
2990        this.ioExceptionHandler = ioExceptionHandler;
2991    }
2992
2993    public IOExceptionHandler getIoExceptionHandler() {
2994        return ioExceptionHandler;
2995    }
2996
2997    /**
2998     * @return the schedulerSupport
2999     */
3000    public boolean isSchedulerSupport() {
3001        return this.schedulerSupport;
3002    }
3003
3004    /**
3005     * @param schedulerSupport the schedulerSupport to set
3006     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
3007     */
3008    public void setSchedulerSupport(boolean schedulerSupport) {
3009        this.schedulerSupport = schedulerSupport;
3010    }
3011
3012    /**
3013     * @return the schedulerDirectory
3014     */
3015    public File getSchedulerDirectoryFile() {
3016        if (this.schedulerDirectoryFile == null) {
3017            this.schedulerDirectoryFile = new File(getBrokerDataDirectory(), "scheduler");
3018        }
3019        return schedulerDirectoryFile;
3020    }
3021
3022    /**
3023     * @param schedulerDirectory the schedulerDirectory to set
3024     */
3025    public void setSchedulerDirectoryFile(File schedulerDirectory) {
3026        this.schedulerDirectoryFile = schedulerDirectory;
3027    }
3028
3029    public void setSchedulerDirectory(String schedulerDirectory) {
3030        setSchedulerDirectoryFile(new File(schedulerDirectory));
3031    }
3032
3033    public int getSchedulePeriodForDestinationPurge() {
3034        return this.schedulePeriodForDestinationPurge;
3035    }
3036
3037    public void setSchedulePeriodForDestinationPurge(int schedulePeriodForDestinationPurge) {
3038        this.schedulePeriodForDestinationPurge = schedulePeriodForDestinationPurge;
3039    }
3040
3041    /**
3042     * @param schedulePeriodForDiskUsageCheck
3043     */
3044    public void setSchedulePeriodForDiskUsageCheck(
3045            int schedulePeriodForDiskUsageCheck) {
3046        this.schedulePeriodForDiskUsageCheck = schedulePeriodForDiskUsageCheck;
3047    }
3048
3049    public int getDiskUsageCheckRegrowThreshold() {
3050        return diskUsageCheckRegrowThreshold;
3051    }
3052
3053    /**
3054     * @param diskUsageCheckRegrowThreshold
3055     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.MemoryPropertyEditor"
3056     */
3057    public void setDiskUsageCheckRegrowThreshold(int diskUsageCheckRegrowThreshold) {
3058        this.diskUsageCheckRegrowThreshold = diskUsageCheckRegrowThreshold;
3059    }
3060
3061    public int getMaxPurgedDestinationsPerSweep() {
3062        return this.maxPurgedDestinationsPerSweep;
3063    }
3064
3065    public void setMaxPurgedDestinationsPerSweep(int maxPurgedDestinationsPerSweep) {
3066        this.maxPurgedDestinationsPerSweep = maxPurgedDestinationsPerSweep;
3067    }
3068
3069    public BrokerContext getBrokerContext() {
3070        return brokerContext;
3071    }
3072
3073    public void setBrokerContext(BrokerContext brokerContext) {
3074        this.brokerContext = brokerContext;
3075    }
3076
3077    public void setBrokerId(String brokerId) {
3078        this.brokerId = new BrokerId(brokerId);
3079    }
3080
3081    public boolean isUseAuthenticatedPrincipalForJMSXUserID() {
3082        return useAuthenticatedPrincipalForJMSXUserID;
3083    }
3084
3085    public void setUseAuthenticatedPrincipalForJMSXUserID(boolean useAuthenticatedPrincipalForJMSXUserID) {
3086        this.useAuthenticatedPrincipalForJMSXUserID = useAuthenticatedPrincipalForJMSXUserID;
3087    }
3088
3089    /**
3090     * Should MBeans that support showing the Authenticated User Name information have this
3091     * value filled in or not.
3092     *
3093     * @return true if user names should be exposed in MBeans
3094     */
3095    public boolean isPopulateUserNameInMBeans() {
3096        return this.populateUserNameInMBeans;
3097    }
3098
3099    /**
3100     * Sets whether Authenticated User Name information is shown in MBeans that support this field.
3101     * @param value if MBeans should expose user name information.
3102     */
3103    public void setPopulateUserNameInMBeans(boolean value) {
3104        this.populateUserNameInMBeans = value;
3105    }
3106
3107    /**
3108     * Gets the time in Milliseconds that an invocation of an MBean method will wait before
3109     * failing.  The default value is to wait forever (zero).
3110     *
3111     * @return timeout in milliseconds before MBean calls fail, (default is 0 or no timeout).
3112     */
3113    public long getMbeanInvocationTimeout() {
3114        return mbeanInvocationTimeout;
3115    }
3116
3117    /**
3118     * Gets the time in Milliseconds that an invocation of an MBean method will wait before
3119     * failing. The default value is to wait forever (zero).
3120     *
3121     * @param mbeanInvocationTimeout
3122     *      timeout in milliseconds before MBean calls fail, (default is 0 or no timeout).
3123     */
3124    public void setMbeanInvocationTimeout(long mbeanInvocationTimeout) {
3125        this.mbeanInvocationTimeout = mbeanInvocationTimeout;
3126    }
3127
3128    public boolean isNetworkConnectorStartAsync() {
3129        return networkConnectorStartAsync;
3130    }
3131
3132    public void setNetworkConnectorStartAsync(boolean networkConnectorStartAsync) {
3133        this.networkConnectorStartAsync = networkConnectorStartAsync;
3134    }
3135
3136    public boolean isAllowTempAutoCreationOnSend() {
3137        return allowTempAutoCreationOnSend;
3138    }
3139
3140    /**
3141     * enable if temp destinations need to be propagated through a network when
3142     * advisorySupport==false. This is used in conjunction with the policy
3143     * gcInactiveDestinations for matching temps so they can get removed
3144     * when inactive
3145     *
3146     * @param allowTempAutoCreationOnSend
3147     */
3148    public void setAllowTempAutoCreationOnSend(boolean allowTempAutoCreationOnSend) {
3149        this.allowTempAutoCreationOnSend = allowTempAutoCreationOnSend;
3150    }
3151
3152    public long getOfflineDurableSubscriberTimeout() {
3153        return offlineDurableSubscriberTimeout;
3154    }
3155
3156    public void setOfflineDurableSubscriberTimeout(long offlineDurableSubscriberTimeout) {
3157        this.offlineDurableSubscriberTimeout = offlineDurableSubscriberTimeout;
3158    }
3159
3160    public long getOfflineDurableSubscriberTaskSchedule() {
3161        return offlineDurableSubscriberTaskSchedule;
3162    }
3163
3164    public void setOfflineDurableSubscriberTaskSchedule(long offlineDurableSubscriberTaskSchedule) {
3165        this.offlineDurableSubscriberTaskSchedule = offlineDurableSubscriberTaskSchedule;
3166    }
3167
3168    public boolean shouldRecordVirtualDestination(ActiveMQDestination destination) {
3169        return isUseVirtualTopics() && destination.isQueue() &&
3170               getVirtualTopicConsumerDestinationFilter().matches(destination);
3171    }
3172
3173    synchronized public Throwable getStartException() {
3174        return startException;
3175    }
3176
3177    public boolean isStartAsync() {
3178        return startAsync;
3179    }
3180
3181    public void setStartAsync(boolean startAsync) {
3182        this.startAsync = startAsync;
3183    }
3184
3185    public boolean isSlave() {
3186        return this.slave;
3187    }
3188
3189    public boolean isStopping() {
3190        return this.stopping.get();
3191    }
3192
3193    /**
3194     * @return true if the broker allowed to restart on shutdown.
3195     */
3196    public boolean isRestartAllowed() {
3197        return restartAllowed;
3198    }
3199
3200    /**
3201     * Sets if the broker allowed to restart on shutdown.
3202     */
3203    public void setRestartAllowed(boolean restartAllowed) {
3204        this.restartAllowed = restartAllowed;
3205    }
3206
3207    /**
3208     * A lifecycle manager of the BrokerService should
3209     * inspect this property after a broker shutdown has occurred
3210     * to find out if the broker needs to be re-created and started
3211     * again.
3212     *
3213     * @return true if the broker wants to be restarted after it shuts down.
3214     */
3215    public boolean isRestartRequested() {
3216        return restartRequested;
3217    }
3218
3219    public void requestRestart() {
3220        this.restartRequested = true;
3221    }
3222
3223    public int getStoreOpenWireVersion() {
3224        return storeOpenWireVersion;
3225    }
3226
3227    public void setStoreOpenWireVersion(int storeOpenWireVersion) {
3228        this.storeOpenWireVersion = storeOpenWireVersion;
3229    }
3230
3231    /**
3232     * @return the current number of connections on this Broker.
3233     */
3234    public int getCurrentConnections() {
3235        return this.currentConnections.get();
3236    }
3237
3238    /**
3239     * @return the total number of connections this broker has handled since startup.
3240     */
3241    public long getTotalConnections() {
3242        return this.totalConnections.get();
3243    }
3244
3245    public void incrementCurrentConnections() {
3246        this.currentConnections.incrementAndGet();
3247    }
3248
3249    public void decrementCurrentConnections() {
3250        this.currentConnections.decrementAndGet();
3251    }
3252
3253    public void incrementTotalConnections() {
3254        this.totalConnections.incrementAndGet();
3255    }
3256
3257    public boolean isRejectDurableConsumers() {
3258        return rejectDurableConsumers;
3259    }
3260
3261    public void setRejectDurableConsumers(boolean rejectDurableConsumers) {
3262        this.rejectDurableConsumers = rejectDurableConsumers;
3263    }
3264
3265    public boolean isUseVirtualDestSubs() {
3266        return useVirtualDestSubs;
3267    }
3268
3269    public void setUseVirtualDestSubs(
3270            boolean useVirtualDestSubs) {
3271        this.useVirtualDestSubs = useVirtualDestSubs;
3272    }
3273
3274    public boolean isUseVirtualDestSubsOnCreation() {
3275        return useVirtualDestSubsOnCreation;
3276    }
3277
3278    public void setUseVirtualDestSubsOnCreation(
3279            boolean useVirtualDestSubsOnCreation) {
3280        this.useVirtualDestSubsOnCreation = useVirtualDestSubsOnCreation;
3281    }
3282
3283    public boolean isAdjustUsageLimits() {
3284        return adjustUsageLimits;
3285    }
3286
3287    public void setAdjustUsageLimits(boolean adjustUsageLimits) {
3288        this.adjustUsageLimits = adjustUsageLimits;
3289    }
3290
3291    public void setRollbackOnlyOnAsyncException(boolean rollbackOnlyOnAsyncException) {
3292        this.rollbackOnlyOnAsyncException = rollbackOnlyOnAsyncException;
3293    }
3294
3295    public boolean isRollbackOnlyOnAsyncException() {
3296        return rollbackOnlyOnAsyncException;
3297    }
3298}