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