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