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 useVirtualTopics = true;
207    private boolean useMirroredQueues = false;
208    private boolean useTempMirroredQueues = true;
209    /**
210     * Whether or not virtual destination subscriptions should cause network demand
211     */
212    private boolean useVirtualDestSubs = false;
213    /**
214     * Whether or not the creation of destinations that match virtual destinations
215     * should cause network demand
216     */
217    private boolean useVirtualDestSubsOnCreation = false;
218    private BrokerId brokerId;
219    private volatile DestinationInterceptor[] destinationInterceptors;
220    private ActiveMQDestination[] destinations;
221    private PListStore tempDataStore;
222    private int persistenceThreadPriority = Thread.MAX_PRIORITY;
223    private boolean useLocalHostBrokerName;
224    private final CountDownLatch stoppedLatch = new CountDownLatch(1);
225    private final CountDownLatch startedLatch = new CountDownLatch(1);
226    private Broker regionBroker;
227    private int producerSystemUsagePortion = 60;
228    private int consumerSystemUsagePortion = 40;
229    private boolean splitSystemUsageForProducersConsumers;
230    private boolean monitorConnectionSplits = false;
231    private int taskRunnerPriority = Thread.NORM_PRIORITY;
232    private boolean dedicatedTaskRunner;
233    private boolean cacheTempDestinations = false;// useful for failover
234    private int timeBeforePurgeTempDestinations = 5000;
235    private final List<Runnable> shutdownHooks = new ArrayList<>();
236    private boolean systemExitOnShutdown;
237    private int systemExitOnShutdownExitCode;
238    private SslContext sslContext;
239    private boolean forceStart = false;
240    private IOExceptionHandler ioExceptionHandler;
241    private boolean schedulerSupport = false;
242    private int maxSchedulerRepeatAllowed = MAX_SCHEDULER_REPEAT_ALLOWED;
243    private File schedulerDirectoryFile;
244    private Scheduler scheduler;
245    private ThreadPoolExecutor executor;
246    private int schedulePeriodForDestinationPurge= 0;
247    private int maxPurgedDestinationsPerSweep = 0;
248    private int schedulePeriodForDiskUsageCheck = 0;
249    private int diskUsageCheckRegrowThreshold = -1;
250    private boolean adjustUsageLimits = true;
251    private BrokerContext brokerContext;
252    private boolean networkConnectorStartAsync = false;
253    private boolean allowTempAutoCreationOnSend;
254    private JobSchedulerStore jobSchedulerStore;
255    private final AtomicLong totalConnections = new AtomicLong();
256    private final AtomicInteger currentConnections = new AtomicInteger();
257
258    private long offlineDurableSubscriberTimeout = -1;
259    private long offlineDurableSubscriberTaskSchedule = 300000;
260    private DestinationFilter virtualConsumerDestinationFilter;
261
262    private final AtomicBoolean persistenceAdapterStarted = new AtomicBoolean(false);
263    private Throwable startException = null;
264    private boolean startAsync = false;
265    private Date startDate;
266    private boolean slave = true;
267
268    private boolean restartAllowed = true;
269    private boolean restartRequested = false;
270    private boolean rejectDurableConsumers = false;
271    private boolean rollbackOnlyOnAsyncException = true;
272
273    private int storeOpenWireVersion = OpenWireFormat.DEFAULT_STORE_VERSION;
274    private final List<Runnable> preShutdownHooks = new CopyOnWriteArrayList<>();
275
276    static {
277
278        try {
279            ClassLoader loader = BrokerService.class.getClassLoader();
280            Class<?> clazz = loader.loadClass("org.bouncycastle.jce.provider.BouncyCastleProvider");
281            Provider bouncycastle = (Provider) clazz.newInstance();
282            Integer bouncyCastlePosition = Integer.getInteger("org.apache.activemq.broker.BouncyCastlePosition");
283            int ret = 0;
284            if (bouncyCastlePosition != null) {
285                ret = Security.insertProviderAt(bouncycastle, bouncyCastlePosition);
286            } else {
287                ret = Security.addProvider(bouncycastle);
288            }
289            LOG.info("Loaded the Bouncy Castle security provider at position: " + ret);
290        } catch(Throwable e) {
291            // No BouncyCastle found so we use the default Java Security Provider
292        }
293
294        String localHostName = "localhost";
295        try {
296            localHostName =  InetAddressUtil.getLocalHostName();
297        } catch (UnknownHostException e) {
298            LOG.error("Failed to resolve localhost");
299        }
300        LOCAL_HOST_NAME = localHostName;
301
302        String version = null;
303        try(InputStream in = BrokerService.class.getResourceAsStream("/org/apache/activemq/version.txt")) {
304            if (in != null) {
305                try(InputStreamReader isr = new InputStreamReader(in);
306                    BufferedReader reader = new BufferedReader(isr)) {
307                    version = reader.readLine();
308                }
309            }
310        } catch (IOException ie) {
311            LOG.warn("Error reading broker version ", ie);
312        }
313        BROKER_VERSION = version;
314    }
315
316    @Override
317    public String toString() {
318        return "BrokerService[" + getBrokerName() + "]";
319    }
320
321    private String getBrokerVersion() {
322        String version = ActiveMQConnectionMetaData.PROVIDER_VERSION;
323        if (version == null) {
324            version = BROKER_VERSION;
325        }
326
327        return version;
328    }
329
330    /**
331     * Adds a new transport connector for the given bind address
332     *
333     * @return the newly created and added transport connector
334     * @throws Exception
335     */
336    public TransportConnector addConnector(String bindAddress) throws Exception {
337        return addConnector(new URI(bindAddress));
338    }
339
340    /**
341     * Adds a new transport connector for the given bind address
342     *
343     * @return the newly created and added transport connector
344     * @throws Exception
345     */
346    public TransportConnector addConnector(URI bindAddress) throws Exception {
347        return addConnector(createTransportConnector(bindAddress));
348    }
349
350    /**
351     * Adds a new transport connector for the given TransportServer transport
352     *
353     * @return the newly created and added transport connector
354     * @throws Exception
355     */
356    public TransportConnector addConnector(TransportServer transport) throws Exception {
357        return addConnector(new TransportConnector(transport));
358    }
359
360    /**
361     * Adds a new transport connector
362     *
363     * @return the transport connector
364     * @throws Exception
365     */
366    public TransportConnector addConnector(TransportConnector connector) throws Exception {
367        transportConnectors.add(connector);
368        return connector;
369    }
370
371    /**
372     * Stops and removes a transport connector from the broker.
373     *
374     * @param connector
375     * @return true if the connector has been previously added to the broker
376     * @throws Exception
377     */
378    public boolean removeConnector(TransportConnector connector) throws Exception {
379        boolean rc = transportConnectors.remove(connector);
380        if (rc) {
381            unregisterConnectorMBean(connector);
382        }
383        return rc;
384    }
385
386    /**
387     * Adds a new network connector using the given discovery address
388     *
389     * @return the newly created and added network connector
390     * @throws Exception
391     */
392    public NetworkConnector addNetworkConnector(String discoveryAddress) throws Exception {
393        return addNetworkConnector(new URI(discoveryAddress));
394    }
395
396    /**
397     * Adds a new proxy connector using the given bind address
398     *
399     * @return the newly created and added network connector
400     * @throws Exception
401     */
402    public ProxyConnector addProxyConnector(String bindAddress) throws Exception {
403        return addProxyConnector(new URI(bindAddress));
404    }
405
406    /**
407     * Adds a new network connector using the given discovery address
408     *
409     * @return the newly created and added network connector
410     * @throws Exception
411     */
412    public NetworkConnector addNetworkConnector(URI discoveryAddress) throws Exception {
413        NetworkConnector connector = new DiscoveryNetworkConnector(discoveryAddress);
414        return addNetworkConnector(connector);
415    }
416
417    /**
418     * Adds a new proxy connector using the given bind address
419     *
420     * @return the newly created and added network connector
421     * @throws Exception
422     */
423    public ProxyConnector addProxyConnector(URI bindAddress) throws Exception {
424        ProxyConnector connector = new ProxyConnector();
425        connector.setBind(bindAddress);
426        connector.setRemote(new URI("fanout:multicast://default"));
427        return addProxyConnector(connector);
428    }
429
430    /**
431     * Adds a new network connector to connect this broker to a federated
432     * network
433     */
434    public NetworkConnector addNetworkConnector(NetworkConnector connector) throws Exception {
435        connector.setBrokerService(this);
436        connector.setLocalUri(getVmConnectorURI());
437        // Set a connection filter so that the connector does not establish loop
438        // back connections.
439        connector.setConnectionFilter(new ConnectionFilter() {
440            @Override
441            public boolean connectTo(URI location) {
442                List<TransportConnector> transportConnectors = getTransportConnectors();
443                for (Iterator<TransportConnector> iter = transportConnectors.iterator(); iter.hasNext();) {
444                    try {
445                        TransportConnector tc = iter.next();
446                        if (location.equals(tc.getConnectUri())) {
447                            return false;
448                        }
449                    } catch (Throwable e) {
450                    }
451                }
452                return true;
453            }
454        });
455        networkConnectors.add(connector);
456        return connector;
457    }
458
459    /**
460     * Removes the given network connector without stopping it. The caller
461     * should call {@link NetworkConnector#stop()} to close the connector
462     */
463    public boolean removeNetworkConnector(NetworkConnector connector) {
464        boolean answer = networkConnectors.remove(connector);
465        if (answer) {
466            unregisterNetworkConnectorMBean(connector);
467        }
468        return answer;
469    }
470
471    public ProxyConnector addProxyConnector(ProxyConnector connector) throws Exception {
472        URI uri = getVmConnectorURI();
473        connector.setLocalUri(uri);
474        proxyConnectors.add(connector);
475        if (isUseJmx()) {
476            registerProxyConnectorMBean(connector);
477        }
478        return connector;
479    }
480
481    public JmsConnector addJmsConnector(JmsConnector connector) throws Exception {
482        connector.setBrokerService(this);
483        jmsConnectors.add(connector);
484        if (isUseJmx()) {
485            registerJmsConnectorMBean(connector);
486        }
487        return connector;
488    }
489
490    /**
491     * Adds a {@link Runnable} hook that will be invoked before the
492     * broker is stopped. This allows performing cleanup actions
493     * before the broker is stopped. The hook should not throw
494     * exceptions or block.
495     */
496    public final void addPreShutdownHook(final Runnable hook) {
497        preShutdownHooks.add(hook);
498    }
499
500    public JmsConnector removeJmsConnector(JmsConnector connector) {
501        if (jmsConnectors.remove(connector)) {
502            return connector;
503        }
504        return null;
505    }
506
507    public void masterFailed() {
508        if (shutdownOnMasterFailure) {
509            LOG.error("The Master has failed ... shutting down");
510            try {
511                stop();
512            } catch (Exception e) {
513                LOG.error("Failed to stop for master failure", e);
514            }
515        } else {
516            LOG.warn("Master Failed - starting all connectors");
517            try {
518                startAllConnectors();
519                broker.nowMasterBroker();
520            } catch (Exception e) {
521                LOG.error("Failed to startAllConnectors", e);
522            }
523        }
524    }
525
526    public String getUptime() {
527        long delta = getUptimeMillis();
528
529        if (delta == 0) {
530            return "not started";
531        }
532
533        return TimeUtils.printDuration(delta);
534    }
535
536    public long getUptimeMillis() {
537        if (startDate == null) {
538            return 0;
539        }
540
541        return new Date().getTime() - startDate.getTime();
542    }
543
544    public boolean isStarted() {
545        return started.get() && startedLatch.getCount() == 0;
546    }
547
548    /**
549     * Forces a start of the broker.
550     * By default a BrokerService instance that was
551     * previously stopped using BrokerService.stop() cannot be restarted
552     * using BrokerService.start().
553     * This method enforces a restart.
554     * It is not recommended to force a restart of the broker and will not work
555     * for most but some very trivial broker configurations.
556     * For restarting a broker instance we recommend to first call stop() on
557     * the old instance and then recreate a new BrokerService instance.
558     *
559     * @param force - if true enforces a restart.
560     * @throws Exception
561     */
562    public void start(boolean force) throws Exception {
563        forceStart = force;
564        stopped.set(false);
565        started.set(false);
566        start();
567    }
568
569    // Service interface
570    // -------------------------------------------------------------------------
571
572    protected boolean shouldAutostart() {
573        return true;
574    }
575
576    /**
577     * JSR-250 callback wrapper; converts checked exceptions to runtime exceptions
578     *
579     * delegates to autoStart, done to prevent backwards incompatible signature change
580     */
581    @PostConstruct
582    private void postConstruct() {
583        try {
584            autoStart();
585        } catch (Exception ex) {
586            throw new RuntimeException(ex);
587        }
588    }
589
590    /**
591     *
592     * @throws Exception
593     * @org. apache.xbean.InitMethod
594     */
595    public void autoStart() throws Exception {
596        if(shouldAutostart()) {
597            start();
598        }
599    }
600
601    @Override
602    public void start() throws Exception {
603        if (stopped.get() || !started.compareAndSet(false, true)) {
604            // lets just ignore redundant start() calls
605            // as its way too easy to not be completely sure if start() has been
606            // called or not with the gazillion of different configuration
607            // mechanisms
608            // throw new IllegalStateException("Already started.");
609            return;
610        }
611
612        setStartException(null);
613        stopping.set(false);
614        preShutdownHooksInvoked.set(false);
615        startDate = new Date();
616        MDC.put("activemq.broker", brokerName);
617
618        try {
619            checkMemorySystemUsageLimits();
620            if (systemExitOnShutdown && useShutdownHook) {
621                throw new ConfigurationException("'useShutdownHook' property cannot be be used with 'systemExitOnShutdown', please turn it off (useShutdownHook=false)");
622            }
623            processHelperProperties();
624            if (isUseJmx()) {
625                // need to remove MDC during starting JMX, as that would otherwise causes leaks, as spawned threads inheirt the MDC and
626                // we cannot cleanup clear that during shutdown of the broker.
627                MDC.remove("activemq.broker");
628                try {
629                    startManagementContext();
630                    for (NetworkConnector connector : getNetworkConnectors()) {
631                        registerNetworkConnectorMBean(connector);
632                    }
633                } finally {
634                    MDC.put("activemq.broker", brokerName);
635                }
636            }
637
638            // in jvm master slave, lets not publish over existing broker till we get the lock
639            final BrokerRegistry brokerRegistry = BrokerRegistry.getInstance();
640            if (brokerRegistry.lookup(getBrokerName()) == null) {
641                brokerRegistry.bind(getBrokerName(), BrokerService.this);
642            }
643            startPersistenceAdapter(startAsync);
644            startBroker(startAsync);
645            brokerRegistry.bind(getBrokerName(), BrokerService.this);
646        } catch (Exception e) {
647            LOG.error("Failed to start Apache ActiveMQ ({}, {})", getBrokerName(), brokerId, e);
648            try {
649                if (!stopped.get()) {
650                    stop();
651                }
652            } catch (Exception ex) {
653                LOG.warn("Failed to stop broker after failure in start. This exception will be ignored.", ex);
654            }
655            throw e;
656        } finally {
657            MDC.remove("activemq.broker");
658        }
659    }
660
661    private void startPersistenceAdapter(boolean async) throws Exception {
662        if (async) {
663            new Thread("Persistence Adapter Starting Thread") {
664                @Override
665                public void run() {
666                    try {
667                        doStartPersistenceAdapter();
668                    } catch (Throwable e) {
669                        setStartException(e);
670                    } finally {
671                        synchronized (persistenceAdapterStarted) {
672                            persistenceAdapterStarted.set(true);
673                            persistenceAdapterStarted.notifyAll();
674                        }
675                    }
676                }
677            }.start();
678        } else {
679            doStartPersistenceAdapter();
680        }
681    }
682
683    private void doStartPersistenceAdapter() throws Exception {
684        PersistenceAdapter persistenceAdapterToStart = getPersistenceAdapter();
685        if (persistenceAdapterToStart == null) {
686            checkStartException();
687            throw new ConfigurationException("Cannot start null persistence adapter");
688        }
689        persistenceAdapterToStart.setUsageManager(getProducerSystemUsage());
690        persistenceAdapterToStart.setBrokerName(getBrokerName());
691        LOG.info("Using Persistence Adapter: {}", persistenceAdapterToStart);
692        if (deleteAllMessagesOnStartup) {
693            deleteAllMessages();
694        }
695        persistenceAdapterToStart.start();
696
697        getTempDataStore();
698        if (tempDataStore != null) {
699            try {
700                // start after we have the store lock
701                tempDataStore.start();
702            } catch (Exception e) {
703                RuntimeException exception = new RuntimeException(
704                        "Failed to start temp data store: " + tempDataStore, e);
705                LOG.error(exception.getLocalizedMessage(), e);
706                throw exception;
707            }
708        }
709
710        getJobSchedulerStore();
711        if (jobSchedulerStore != null) {
712            try {
713                jobSchedulerStore.start();
714            } catch (Exception e) {
715                RuntimeException exception = new RuntimeException(
716                        "Failed to start job scheduler store: " + jobSchedulerStore, e);
717                LOG.error(exception.getLocalizedMessage(), e);
718                throw exception;
719            }
720        }
721    }
722
723    private void startBroker(boolean async) throws Exception {
724        if (async) {
725            new Thread("Broker Starting Thread") {
726                @Override
727                public void run() {
728                    try {
729                        synchronized (persistenceAdapterStarted) {
730                            if (!persistenceAdapterStarted.get()) {
731                                persistenceAdapterStarted.wait();
732                            }
733                        }
734                        doStartBroker();
735                    } catch (Throwable t) {
736                        setStartException(t);
737                    }
738                }
739            }.start();
740        } else {
741            doStartBroker();
742        }
743    }
744
745    private void doStartBroker() throws Exception {
746        checkStartException();
747        startDestinations();
748        addShutdownHook();
749
750        broker = getBroker();
751        brokerId = broker.getBrokerId();
752
753        // need to log this after creating the broker so we have its id and name
754        LOG.info("Apache ActiveMQ {} ({}, {}) is starting", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId });
755        broker.start();
756
757        if (isUseJmx()) {
758            if (getManagementContext().isCreateConnector() && !getManagementContext().isConnectorStarted()) {
759                // try to restart management context
760                // typical for slaves that use the same ports as master
761                managementContext.stop();
762                startManagementContext();
763            }
764            ManagedRegionBroker managedBroker = (ManagedRegionBroker) regionBroker;
765            managedBroker.setContextBroker(broker);
766            adminView.setBroker(managedBroker);
767        }
768
769        if (ioExceptionHandler == null) {
770            setIoExceptionHandler(new DefaultIOExceptionHandler());
771        }
772
773        if (isUseJmx() && Log4JConfigView.isLog4JAvailable()) {
774            ObjectName objectName = BrokerMBeanSupport.createLog4JConfigViewName(getBrokerObjectName().toString());
775            Log4JConfigView log4jConfigView = new Log4JConfigView();
776            AnnotatedMBean.registerMBean(getManagementContext(), log4jConfigView, objectName);
777        }
778
779        startAllConnectors();
780
781        LOG.info("Apache ActiveMQ {} ({}, {}) started", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId});
782        LOG.info("For help or more information please see: http://activemq.apache.org");
783
784        getBroker().brokerServiceStarted();
785        checkStoreSystemUsageLimits();
786        startedLatch.countDown();
787        getBroker().nowMasterBroker();
788    }
789
790    /**
791     * JSR-250 callback wrapper; converts checked exceptions to runtime exceptions
792     *
793     * delegates to stop, done to prevent backwards incompatible signature change
794     */
795    @PreDestroy
796    private void preDestroy () {
797        try {
798            stop();
799        } catch (Exception ex) {
800            throw new RuntimeException();
801        }
802    }
803
804    /**
805     *
806     * @throws Exception
807     * @org.apache .xbean.DestroyMethod
808     */
809    @Override
810    public void stop() throws Exception {
811        final ServiceStopper stopper = new ServiceStopper();
812
813        //The preShutdownHooks need to run before stopping.compareAndSet()
814        //so there is a separate AtomicBoolean so the hooks only run once
815        //We want to make sure the hooks are run before stop is initialized
816        //including setting the stopping variable - See AMQ-6706
817        if (preShutdownHooksInvoked.compareAndSet(false, true)) {
818            for (Runnable hook : preShutdownHooks) {
819                try {
820                    hook.run();
821                } catch (Throwable e) {
822                    stopper.onException(hook, e);
823                }
824            }
825        }
826
827        if (!stopping.compareAndSet(false, true)) {
828            LOG.trace("Broker already stopping/stopped");
829            return;
830        }
831
832        setStartException(new BrokerStoppedException("Stop invoked"));
833        MDC.put("activemq.broker", brokerName);
834
835        if (systemExitOnShutdown) {
836            new Thread() {
837                @Override
838                public void run() {
839                    System.exit(systemExitOnShutdownExitCode);
840                }
841            }.start();
842        }
843
844        LOG.info("Apache ActiveMQ {} ({}, {}) is shutting down", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId} );
845
846        removeShutdownHook();
847        if (this.scheduler != null) {
848            this.scheduler.stop();
849            this.scheduler = null;
850        }
851        if (services != null) {
852            for (Service service : services) {
853                stopper.stop(service);
854            }
855        }
856        stopAllConnectors(stopper);
857        this.slave = true;
858        // remove any VMTransports connected
859        // this has to be done after services are stopped,
860        // to avoid timing issue with discovery (spinning up a new instance)
861        BrokerRegistry.getInstance().unbind(getBrokerName());
862        VMTransportFactory.stopped(getBrokerName());
863        if (broker != null) {
864            stopper.stop(broker);
865            broker = null;
866        }
867
868        if (jobSchedulerStore != null) {
869            jobSchedulerStore.stop();
870            jobSchedulerStore = null;
871        }
872        if (tempDataStore != null) {
873            tempDataStore.stop();
874            tempDataStore = null;
875        }
876        try {
877            stopper.stop(getPersistenceAdapter());
878            persistenceAdapter = null;
879            if (isUseJmx()) {
880                stopper.stop(managementContext);
881                managementContext = null;
882            }
883            // Clear SelectorParser cache to free memory
884            SelectorParser.clearCache();
885        } finally {
886            started.set(false);
887            stopped.set(true);
888            stoppedLatch.countDown();
889        }
890
891        if (this.taskRunnerFactory != null) {
892            this.taskRunnerFactory.shutdown();
893            this.taskRunnerFactory = null;
894        }
895        if (this.executor != null) {
896            ThreadPoolUtils.shutdownNow(executor);
897            this.executor = null;
898        }
899
900        this.destinationInterceptors = null;
901        this.destinationFactory = null;
902
903        if (startDate != null) {
904            LOG.info("Apache ActiveMQ {} ({}, {}) uptime {}", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId, getUptime()});
905        }
906        LOG.info("Apache ActiveMQ {} ({}, {}) is shutdown", new Object[]{ getBrokerVersion(), getBrokerName(), brokerId});
907
908        synchronized (shutdownHooks) {
909            for (Runnable hook : shutdownHooks) {
910                try {
911                    hook.run();
912                } catch (Throwable e) {
913                    stopper.onException(hook, e);
914                }
915            }
916        }
917
918        MDC.remove("activemq.broker");
919
920        // and clear start date
921        startDate = null;
922
923        stopper.throwFirstException();
924    }
925
926    public boolean checkQueueSize(String queueName) {
927        long count = 0;
928        long queueSize = 0;
929        Map<ActiveMQDestination, Destination> destinationMap = regionBroker.getDestinationMap();
930        for (Map.Entry<ActiveMQDestination, Destination> entry : destinationMap.entrySet()) {
931            if (entry.getKey().isQueue()) {
932                if (entry.getValue().getName().matches(queueName)) {
933                    queueSize = entry.getValue().getDestinationStatistics().getMessages().getCount();
934                    count += queueSize;
935                    if (queueSize > 0) {
936                        LOG.info("Queue has pending message: {} queueSize is: {}", entry.getValue().getName(), queueSize);
937                    }
938                }
939            }
940        }
941        return count == 0;
942    }
943
944    /**
945     * This method (both connectorName and queueName are using regex to match)
946     * 1. stop the connector (supposed the user input the connector which the
947     * clients connect to) 2. to check whether there is any pending message on
948     * the queues defined by queueName 3. supposedly, after stop the connector,
949     * client should failover to other broker and pending messages should be
950     * forwarded. if no pending messages, the method finally call stop to stop
951     * the broker.
952     *
953     * @param connectorName
954     * @param queueName
955     * @param timeout
956     * @param pollInterval
957     * @throws Exception
958     */
959    public void stopGracefully(String connectorName, String queueName, long timeout, long pollInterval) throws Exception {
960        if (isUseJmx()) {
961            if (connectorName == null || queueName == null || timeout <= 0) {
962                throw new Exception(
963                        "connectorName and queueName cannot be null and timeout should be >0 for stopGracefully.");
964            }
965            if (pollInterval <= 0) {
966                pollInterval = 30;
967            }
968            LOG.info("Stop gracefully with connectorName: {} queueName: {} timeout: {} pollInterval: {}", new Object[]{
969                    connectorName, queueName, timeout, pollInterval
970            });
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 isUseVirtualTopics() {
1734        return useVirtualTopics;
1735    }
1736
1737    /**
1738     * Sets whether or not <a
1739     * href="http://activemq.apache.org/virtual-destinations.html">Virtual
1740     * Topics</a> should be supported by default if they have not been
1741     * explicitly configured.
1742     */
1743    public void setUseVirtualTopics(boolean useVirtualTopics) {
1744        this.useVirtualTopics = useVirtualTopics;
1745    }
1746
1747    public DestinationInterceptor[] getDestinationInterceptors() {
1748        return destinationInterceptors;
1749    }
1750
1751    public boolean isUseMirroredQueues() {
1752        return useMirroredQueues;
1753    }
1754
1755    /**
1756     * Sets whether or not <a
1757     * href="http://activemq.apache.org/mirrored-queues.html">Mirrored
1758     * Queues</a> should be supported by default if they have not been
1759     * explicitly configured.
1760     */
1761    public void setUseMirroredQueues(boolean useMirroredQueues) {
1762        this.useMirroredQueues = useMirroredQueues;
1763    }
1764
1765    /**
1766     * Sets the destination interceptors to use
1767     */
1768    public void setDestinationInterceptors(DestinationInterceptor[] destinationInterceptors) {
1769        this.destinationInterceptors = destinationInterceptors;
1770    }
1771
1772    public ActiveMQDestination[] getDestinations() {
1773        return destinations;
1774    }
1775
1776    /**
1777     * Sets the destinations which should be loaded/created on startup
1778     */
1779    public void setDestinations(ActiveMQDestination[] destinations) {
1780        this.destinations = destinations;
1781    }
1782
1783    /**
1784     * @return the tempDataStore
1785     */
1786    public synchronized PListStore getTempDataStore() {
1787        if (tempDataStore == null && !hasStartException()) {
1788            if (!isPersistent()) {
1789                return null;
1790            }
1791
1792            try {
1793                PersistenceAdapter pa = getPersistenceAdapter();
1794                if( pa!=null && pa instanceof PListStore) {
1795                    return (PListStore) pa;
1796                }
1797            } catch (IOException e) {
1798                throw new RuntimeException(e);
1799            }
1800
1801            try {
1802                String clazz = "org.apache.activemq.store.kahadb.plist.PListStoreImpl";
1803                this.tempDataStore = (PListStore) getClass().getClassLoader().loadClass(clazz).newInstance();
1804                this.tempDataStore.setDirectory(getTmpDataDirectory());
1805                configureService(tempDataStore);
1806            } catch (ClassNotFoundException e) {
1807                throw new RuntimeException("Kahadb class PListStoreImpl not found. Add activemq-kahadb jar or set persistent to false on BrokerService.", e);
1808            } catch (Exception e) {
1809                throw new RuntimeException(e);
1810            }
1811        }
1812        return tempDataStore;
1813    }
1814
1815    /**
1816     * @param tempDataStore
1817     *            the tempDataStore to set
1818     */
1819    public void setTempDataStore(PListStore tempDataStore) {
1820        this.tempDataStore = tempDataStore;
1821        if (tempDataStore != null) {
1822            if (tmpDataDirectory == null) {
1823                tmpDataDirectory = tempDataStore.getDirectory();
1824            } else if (tempDataStore.getDirectory() == null) {
1825                tempDataStore.setDirectory(tmpDataDirectory);
1826            }
1827        }
1828        configureService(tempDataStore);
1829    }
1830
1831    public int getPersistenceThreadPriority() {
1832        return persistenceThreadPriority;
1833    }
1834
1835    public void setPersistenceThreadPriority(int persistenceThreadPriority) {
1836        this.persistenceThreadPriority = persistenceThreadPriority;
1837    }
1838
1839    /**
1840     * @return the useLocalHostBrokerName
1841     */
1842    public boolean isUseLocalHostBrokerName() {
1843        return this.useLocalHostBrokerName;
1844    }
1845
1846    /**
1847     * @param useLocalHostBrokerName
1848     *            the useLocalHostBrokerName to set
1849     */
1850    public void setUseLocalHostBrokerName(boolean useLocalHostBrokerName) {
1851        this.useLocalHostBrokerName = useLocalHostBrokerName;
1852        if (useLocalHostBrokerName && !started.get() && brokerName == null || brokerName == DEFAULT_BROKER_NAME) {
1853            brokerName = LOCAL_HOST_NAME;
1854        }
1855    }
1856
1857    /**
1858     * Looks up and lazily creates if necessary the destination for the given
1859     * JMS name
1860     */
1861    public Destination getDestination(ActiveMQDestination destination) throws Exception {
1862        return getBroker().addDestination(getAdminConnectionContext(), destination,false);
1863    }
1864
1865    public void removeDestination(ActiveMQDestination destination) throws Exception {
1866        getBroker().removeDestination(getAdminConnectionContext(), destination, 0);
1867    }
1868
1869    public int getProducerSystemUsagePortion() {
1870        return producerSystemUsagePortion;
1871    }
1872
1873    public void setProducerSystemUsagePortion(int producerSystemUsagePortion) {
1874        this.producerSystemUsagePortion = producerSystemUsagePortion;
1875    }
1876
1877    public int getConsumerSystemUsagePortion() {
1878        return consumerSystemUsagePortion;
1879    }
1880
1881    public void setConsumerSystemUsagePortion(int consumerSystemUsagePortion) {
1882        this.consumerSystemUsagePortion = consumerSystemUsagePortion;
1883    }
1884
1885    public boolean isSplitSystemUsageForProducersConsumers() {
1886        return splitSystemUsageForProducersConsumers;
1887    }
1888
1889    public void setSplitSystemUsageForProducersConsumers(boolean splitSystemUsageForProducersConsumers) {
1890        this.splitSystemUsageForProducersConsumers = splitSystemUsageForProducersConsumers;
1891    }
1892
1893    public boolean isMonitorConnectionSplits() {
1894        return monitorConnectionSplits;
1895    }
1896
1897    public void setMonitorConnectionSplits(boolean monitorConnectionSplits) {
1898        this.monitorConnectionSplits = monitorConnectionSplits;
1899    }
1900
1901    public int getTaskRunnerPriority() {
1902        return taskRunnerPriority;
1903    }
1904
1905    public void setTaskRunnerPriority(int taskRunnerPriority) {
1906        this.taskRunnerPriority = taskRunnerPriority;
1907    }
1908
1909    public boolean isDedicatedTaskRunner() {
1910        return dedicatedTaskRunner;
1911    }
1912
1913    public void setDedicatedTaskRunner(boolean dedicatedTaskRunner) {
1914        this.dedicatedTaskRunner = dedicatedTaskRunner;
1915    }
1916
1917    public boolean isCacheTempDestinations() {
1918        return cacheTempDestinations;
1919    }
1920
1921    public void setCacheTempDestinations(boolean cacheTempDestinations) {
1922        this.cacheTempDestinations = cacheTempDestinations;
1923    }
1924
1925    public int getTimeBeforePurgeTempDestinations() {
1926        return timeBeforePurgeTempDestinations;
1927    }
1928
1929    public void setTimeBeforePurgeTempDestinations(int timeBeforePurgeTempDestinations) {
1930        this.timeBeforePurgeTempDestinations = timeBeforePurgeTempDestinations;
1931    }
1932
1933    public boolean isUseTempMirroredQueues() {
1934        return useTempMirroredQueues;
1935    }
1936
1937    public void setUseTempMirroredQueues(boolean useTempMirroredQueues) {
1938        this.useTempMirroredQueues = useTempMirroredQueues;
1939    }
1940
1941    public synchronized JobSchedulerStore getJobSchedulerStore() {
1942
1943        // If support is off don't allow any scheduler even is user configured their own.
1944        if (!isSchedulerSupport()) {
1945            return null;
1946        }
1947
1948        // If the user configured their own we use it even if persistence is disabled since
1949        // we don't know anything about their implementation.
1950        if (jobSchedulerStore == null && !hasStartException()) {
1951
1952            if (!isPersistent()) {
1953                this.jobSchedulerStore = new InMemoryJobSchedulerStore();
1954                configureService(jobSchedulerStore);
1955                return this.jobSchedulerStore;
1956            }
1957
1958            try {
1959                PersistenceAdapter pa = getPersistenceAdapter();
1960                if (pa != null) {
1961                    this.jobSchedulerStore = pa.createJobSchedulerStore();
1962                    jobSchedulerStore.setDirectory(getSchedulerDirectoryFile());
1963                    configureService(jobSchedulerStore);
1964                    return this.jobSchedulerStore;
1965                }
1966            } catch (IOException e) {
1967                throw new RuntimeException(e);
1968            } catch (UnsupportedOperationException ex) {
1969                // It's ok if the store doesn't implement a scheduler.
1970            } catch (Exception e) {
1971                throw new RuntimeException(e);
1972            }
1973
1974            try {
1975                PersistenceAdapter pa = getPersistenceAdapter();
1976                if (pa != null && pa instanceof JobSchedulerStore) {
1977                    this.jobSchedulerStore = (JobSchedulerStore) pa;
1978                    configureService(jobSchedulerStore);
1979                    return this.jobSchedulerStore;
1980                }
1981            } catch (IOException e) {
1982                throw new RuntimeException(e);
1983            }
1984
1985            // Load the KahaDB store as a last resort, this only works if KahaDB is
1986            // included at runtime, otherwise this will fail.  User should disable
1987            // scheduler support if this fails.
1988            try {
1989                String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter";
1990                PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance();
1991                jobSchedulerStore = adaptor.createJobSchedulerStore();
1992                jobSchedulerStore.setDirectory(getSchedulerDirectoryFile());
1993                configureService(jobSchedulerStore);
1994                LOG.info("JobScheduler using directory: {}", getSchedulerDirectoryFile());
1995            } catch (Exception e) {
1996                throw new RuntimeException(e);
1997            }
1998        }
1999        return jobSchedulerStore;
2000    }
2001
2002    public void setJobSchedulerStore(JobSchedulerStore jobSchedulerStore) {
2003        this.jobSchedulerStore = jobSchedulerStore;
2004        configureService(jobSchedulerStore);
2005    }
2006
2007    //
2008    // Implementation methods
2009    // -------------------------------------------------------------------------
2010    /**
2011     * Handles any lazy-creation helper properties which are added to make
2012     * things easier to configure inside environments such as Spring
2013     *
2014     * @throws Exception
2015     */
2016    protected void processHelperProperties() throws Exception {
2017        if (transportConnectorURIs != null) {
2018            for (int i = 0; i < transportConnectorURIs.length; i++) {
2019                String uri = transportConnectorURIs[i];
2020                addConnector(uri);
2021            }
2022        }
2023        if (networkConnectorURIs != null) {
2024            for (int i = 0; i < networkConnectorURIs.length; i++) {
2025                String uri = networkConnectorURIs[i];
2026                addNetworkConnector(uri);
2027            }
2028        }
2029        if (jmsBridgeConnectors != null) {
2030            for (int i = 0; i < jmsBridgeConnectors.length; i++) {
2031                addJmsConnector(jmsBridgeConnectors[i]);
2032            }
2033        }
2034    }
2035
2036    /**
2037     * Check that the store usage limit is not greater than max usable
2038     * space and adjust if it is
2039     */
2040    protected void checkStoreUsageLimits() throws Exception {
2041        final SystemUsage usage = getSystemUsage();
2042
2043        if (getPersistenceAdapter() != null) {
2044            PersistenceAdapter adapter = getPersistenceAdapter();
2045            checkUsageLimit(adapter.getDirectory(), usage.getStoreUsage(), usage.getStoreUsage().getPercentLimit());
2046
2047            long maxJournalFileSize = 0;
2048            long storeLimit = usage.getStoreUsage().getLimit();
2049
2050            if (adapter instanceof JournaledStore) {
2051                maxJournalFileSize = ((JournaledStore) adapter).getJournalMaxFileLength();
2052            }
2053
2054            if (storeLimit > 0 && storeLimit < maxJournalFileSize) {
2055                LOG.error("Store limit is " + storeLimit / (1024 * 1024) +
2056                          " mb, whilst the max journal file size for the store is: " +
2057                          maxJournalFileSize / (1024 * 1024) + " mb, " +
2058                          "the store will not accept any data when used.");
2059
2060            }
2061        }
2062    }
2063
2064    /**
2065     * Check that temporary usage limit is not greater than max usable
2066     * space and adjust if it is
2067     */
2068    protected void checkTmpStoreUsageLimits() throws Exception {
2069        final SystemUsage usage = getSystemUsage();
2070
2071        File tmpDir = getTmpDataDirectory();
2072
2073        if (tmpDir != null) {
2074            checkUsageLimit(tmpDir, usage.getTempUsage(), usage.getTempUsage().getPercentLimit());
2075
2076            if (isPersistent()) {
2077                long maxJournalFileSize;
2078
2079                PListStore store = usage.getTempUsage().getStore();
2080                if (store != null && store instanceof JournaledStore) {
2081                    maxJournalFileSize = ((JournaledStore) store).getJournalMaxFileLength();
2082                } else {
2083                    maxJournalFileSize = DEFAULT_MAX_FILE_LENGTH;
2084                }
2085                long storeLimit = usage.getTempUsage().getLimit();
2086
2087                if (storeLimit > 0 && storeLimit < maxJournalFileSize) {
2088                    LOG.error("Temporary Store limit is " + storeLimit / (1024 * 1024) +
2089                              " mb, whilst the max journal file size for the temporary store is: " +
2090                              maxJournalFileSize / (1024 * 1024) + " mb, " +
2091                              "the temp store will not accept any data when used.");
2092                }
2093            }
2094        }
2095    }
2096
2097    protected void checkUsageLimit(File dir, PercentLimitUsage<?> storeUsage, int percentLimit) throws ConfigurationException {
2098        if (dir != null) {
2099            dir = StoreUtil.findParentDirectory(dir);
2100            String storeName = storeUsage instanceof StoreUsage ? "Store" : "Temporary Store";
2101            long storeLimit = storeUsage.getLimit();
2102            long storeCurrent = storeUsage.getUsage();
2103            long totalSpace = storeUsage.getTotal() > 0 ? storeUsage.getTotal() : dir.getTotalSpace();
2104            long totalUsableSpace = (storeUsage.getTotal() > 0 ? storeUsage.getTotal() : dir.getUsableSpace()) + storeCurrent;
2105            if (totalUsableSpace < 0 || totalSpace < 0) {
2106                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";
2107                LOG.error(message);
2108                throw new ConfigurationException(message);
2109            }
2110            //compute byte value of the percent limit
2111            long bytePercentLimit = totalSpace * percentLimit / 100;
2112            int oneMeg = 1024 * 1024;
2113
2114            //Check if the store limit is less than the percent Limit that was set and also
2115            //the usable space...this means we can grow the store larger
2116            //Changes in partition size (total space) as well as changes in usable space should
2117            //be detected here
2118            if (diskUsageCheckRegrowThreshold > -1 && percentLimit > 0
2119                    && storeUsage.getTotal() == 0
2120                    && storeLimit < bytePercentLimit && storeLimit < totalUsableSpace){
2121
2122                // set the limit to be bytePercentLimit or usableSpace if
2123                // usableSpace is less than the percentLimit
2124                long newLimit = bytePercentLimit > totalUsableSpace ? totalUsableSpace : bytePercentLimit;
2125
2126                //To prevent changing too often, check threshold
2127                if (newLimit - storeLimit >= diskUsageCheckRegrowThreshold) {
2128                    LOG.info("Usable disk space has been increased, attempting to regrow " + storeName + " limit to "
2129                            + percentLimit + "% of the partition size.");
2130                    storeUsage.setLimit(newLimit);
2131                    LOG.info(storeName + " limit has been increased to " + newLimit * 100 / totalSpace
2132                            + "% (" + newLimit / oneMeg + " mb) of the partition size.");
2133                }
2134
2135            //check if the limit is too large for the amount of usable space
2136            } else if (storeLimit > totalUsableSpace) {
2137                final String message = storeName + " limit is " +  storeLimit / oneMeg
2138                        + " mb (current store usage is " + storeCurrent / oneMeg
2139                        + " mb). The data directory: " + dir.getAbsolutePath()
2140                        + " only has " + totalUsableSpace / oneMeg
2141                        + " mb of usable space.";
2142
2143                if (!isAdjustUsageLimits()) {
2144                    LOG.error(message);
2145                    throw new ConfigurationException(message);
2146                }
2147
2148                if (percentLimit > 0) {
2149                    LOG.warn(storeName + " limit has been set to "
2150                            + percentLimit + "% (" + bytePercentLimit / oneMeg + " mb)"
2151                            + " of the partition size but there is not enough usable space."
2152                            + " The current store limit (which may have been adjusted by a"
2153                            + " previous usage limit check) is set to (" + storeLimit / oneMeg + " mb)"
2154                            + " but only " + totalUsableSpace * 100 / totalSpace + "% (" + totalUsableSpace / oneMeg + " mb)"
2155                            + " is available - resetting limit");
2156                } else {
2157                    LOG.warn(message + " - resetting to maximum available disk space: " +
2158                            totalUsableSpace / oneMeg + " mb");
2159                }
2160                storeUsage.setLimit(totalUsableSpace);
2161            }
2162        }
2163    }
2164
2165    /**
2166     * Schedules a periodic task based on schedulePeriodForDiskLimitCheck to
2167     * update store and temporary store limits if the amount of available space
2168     * plus current store size is less than the existing configured limit
2169     */
2170    protected void scheduleDiskUsageLimitsCheck() throws IOException {
2171        if (schedulePeriodForDiskUsageCheck > 0 &&
2172                (getPersistenceAdapter() != null || getTmpDataDirectory() != null)) {
2173            Runnable diskLimitCheckTask = new Runnable() {
2174                @Override
2175                public void run() {
2176                    try {
2177                        checkStoreUsageLimits();
2178                    } catch (Throwable e) {
2179                        LOG.error("Failed to check persistent disk usage limits", e);
2180                    }
2181
2182                    try {
2183                        checkTmpStoreUsageLimits();
2184                    } catch (Throwable e) {
2185                        LOG.error("Failed to check temporary store usage limits", e);
2186                    }
2187                }
2188            };
2189            scheduler.executePeriodically(diskLimitCheckTask, schedulePeriodForDiskUsageCheck);
2190        }
2191    }
2192
2193    protected void checkMemorySystemUsageLimits() throws Exception {
2194        final SystemUsage usage = getSystemUsage();
2195        long memLimit = usage.getMemoryUsage().getLimit();
2196        long jvmLimit = Runtime.getRuntime().maxMemory();
2197
2198        if (memLimit > jvmLimit) {
2199            final String message = "Memory Usage for the Broker (" + memLimit / (1024 * 1024)
2200                    + "mb) is more than the maximum available for the JVM: " + jvmLimit / (1024 * 1024);
2201
2202            if (adjustUsageLimits) {
2203                usage.getMemoryUsage().setPercentOfJvmHeap(70);
2204                LOG.warn(message + " mb - resetting to 70% of maximum available: " + (usage.getMemoryUsage().getLimit() / (1024 * 1024)) + " mb");
2205            } else {
2206                LOG.error(message);
2207                throw new ConfigurationException(message);
2208            }
2209        }
2210    }
2211
2212    protected void checkStoreSystemUsageLimits() throws Exception {
2213        final SystemUsage usage = getSystemUsage();
2214
2215        //Check the persistent store and temp store limits if they exist
2216        //and schedule a periodic check to update disk limits if
2217        //schedulePeriodForDiskLimitCheck is set
2218        checkStoreUsageLimits();
2219        checkTmpStoreUsageLimits();
2220        scheduleDiskUsageLimitsCheck();
2221
2222        if (getJobSchedulerStore() != null) {
2223            JobSchedulerStore scheduler = getJobSchedulerStore();
2224            File schedulerDir = scheduler.getDirectory();
2225            if (schedulerDir != null) {
2226
2227                String schedulerDirPath = schedulerDir.getAbsolutePath();
2228                if (!schedulerDir.isAbsolute()) {
2229                    schedulerDir = new File(schedulerDirPath);
2230                }
2231
2232                while (schedulerDir != null && !schedulerDir.isDirectory()) {
2233                    schedulerDir = schedulerDir.getParentFile();
2234                }
2235                long schedulerLimit = usage.getJobSchedulerUsage().getLimit();
2236                long dirFreeSpace = schedulerDir.getUsableSpace();
2237                if (schedulerLimit > dirFreeSpace) {
2238                    LOG.warn("Job Scheduler Store limit is " + schedulerLimit / (1024 * 1024) +
2239                             " mb, whilst the data directory: " + schedulerDir.getAbsolutePath() +
2240                             " only has " + dirFreeSpace / (1024 * 1024) + " mb of usable space - resetting to " +
2241                            dirFreeSpace / (1024 * 1024) + " mb.");
2242                    usage.getJobSchedulerUsage().setLimit(dirFreeSpace);
2243                }
2244            }
2245        }
2246    }
2247
2248    public void stopAllConnectors(ServiceStopper stopper) {
2249        for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) {
2250            NetworkConnector connector = iter.next();
2251            unregisterNetworkConnectorMBean(connector);
2252            stopper.stop(connector);
2253        }
2254        for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) {
2255            ProxyConnector connector = iter.next();
2256            stopper.stop(connector);
2257        }
2258        for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) {
2259            JmsConnector connector = iter.next();
2260            stopper.stop(connector);
2261        }
2262        for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) {
2263            TransportConnector connector = iter.next();
2264            try {
2265                unregisterConnectorMBean(connector);
2266            } catch (IOException e) {
2267            }
2268            stopper.stop(connector);
2269        }
2270    }
2271
2272    protected TransportConnector registerConnectorMBean(TransportConnector connector) throws IOException {
2273        try {
2274            ObjectName objectName = createConnectorObjectName(connector);
2275            connector = connector.asManagedConnector(getManagementContext(), objectName);
2276            ConnectorViewMBean view = new ConnectorView(connector);
2277            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2278            return connector;
2279        } catch (Throwable e) {
2280            throw IOExceptionSupport.create("Transport Connector could not be registered in JMX: " + e, e);
2281        }
2282    }
2283
2284    protected void unregisterConnectorMBean(TransportConnector connector) throws IOException {
2285        if (isUseJmx()) {
2286            try {
2287                ObjectName objectName = createConnectorObjectName(connector);
2288                getManagementContext().unregisterMBean(objectName);
2289            } catch (Throwable e) {
2290                throw IOExceptionSupport.create(
2291                        "Transport Connector could not be unregistered in JMX: " + e.getMessage(), e);
2292            }
2293        }
2294    }
2295
2296    protected PersistenceAdapter registerPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException {
2297        return adaptor;
2298    }
2299
2300    protected void unregisterPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException {
2301        if (isUseJmx()) {}
2302    }
2303
2304    private ObjectName createConnectorObjectName(TransportConnector connector) throws MalformedObjectNameException {
2305        return BrokerMBeanSupport.createConnectorName(getBrokerObjectName(), "clientConnectors", connector.getName());
2306    }
2307
2308    public void registerNetworkConnectorMBean(NetworkConnector connector) throws IOException {
2309        NetworkConnectorViewMBean view = new NetworkConnectorView(connector);
2310        try {
2311            ObjectName objectName = createNetworkConnectorObjectName(connector);
2312            connector.setObjectName(objectName);
2313            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2314        } catch (Throwable e) {
2315            throw IOExceptionSupport.create("Network Connector could not be registered in JMX: " + e.getMessage(), e);
2316        }
2317    }
2318
2319    public ObjectName createNetworkConnectorObjectName(NetworkConnector connector) throws MalformedObjectNameException {
2320        return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "networkConnectors", connector.getName());
2321    }
2322
2323    public ObjectName createDuplexNetworkConnectorObjectName(String transport) throws MalformedObjectNameException {
2324        return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "duplexNetworkConnectors", transport);
2325    }
2326
2327    protected void unregisterNetworkConnectorMBean(NetworkConnector connector) {
2328        if (isUseJmx()) {
2329            try {
2330                ObjectName objectName = createNetworkConnectorObjectName(connector);
2331                getManagementContext().unregisterMBean(objectName);
2332            } catch (Exception e) {
2333                LOG.warn("Network Connector could not be unregistered from JMX due " + e.getMessage() + ". This exception is ignored.", e);
2334            }
2335        }
2336    }
2337
2338    protected void registerProxyConnectorMBean(ProxyConnector connector) throws IOException {
2339        ProxyConnectorView view = new ProxyConnectorView(connector);
2340        try {
2341            ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "proxyConnectors", connector.getName());
2342            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2343        } catch (Throwable e) {
2344            throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e);
2345        }
2346    }
2347
2348    protected void registerJmsConnectorMBean(JmsConnector connector) throws IOException {
2349        JmsConnectorView view = new JmsConnectorView(connector);
2350        try {
2351            ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "jmsConnectors", connector.getName());
2352            AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2353        } catch (Throwable e) {
2354            throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e);
2355        }
2356    }
2357
2358    /**
2359     * Factory method to create a new broker
2360     *
2361     * @throws Exception
2362     */
2363    protected Broker createBroker() throws Exception {
2364        regionBroker = createRegionBroker();
2365        Broker broker = addInterceptors(regionBroker);
2366        // Add a filter that will stop access to the broker once stopped
2367        broker = new MutableBrokerFilter(broker) {
2368            Broker old;
2369
2370            @Override
2371            public void stop() throws Exception {
2372                old = this.next.getAndSet(new ErrorBroker("Broker has been stopped: " + this) {
2373                    // Just ignore additional stop actions.
2374                    @Override
2375                    public void stop() throws Exception {
2376                    }
2377                });
2378                old.stop();
2379            }
2380
2381            @Override
2382            public void start() throws Exception {
2383                if (forceStart && old != null) {
2384                    this.next.set(old);
2385                }
2386                getNext().start();
2387            }
2388        };
2389        return broker;
2390    }
2391
2392    /**
2393     * Factory method to create the core region broker onto which interceptors
2394     * are added
2395     *
2396     * @throws Exception
2397     */
2398    protected Broker createRegionBroker() throws Exception {
2399        if (destinationInterceptors == null) {
2400            destinationInterceptors = createDefaultDestinationInterceptor();
2401        }
2402        configureServices(destinationInterceptors);
2403        DestinationInterceptor destinationInterceptor = new CompositeDestinationInterceptor(destinationInterceptors);
2404        if (destinationFactory == null) {
2405            destinationFactory = new DestinationFactoryImpl(this, getTaskRunnerFactory(), getPersistenceAdapter());
2406        }
2407        return createRegionBroker(destinationInterceptor);
2408    }
2409
2410    protected Broker createRegionBroker(DestinationInterceptor destinationInterceptor) throws IOException {
2411        RegionBroker regionBroker;
2412        if (isUseJmx()) {
2413            try {
2414                regionBroker = new ManagedRegionBroker(this, getManagementContext(), getBrokerObjectName(),
2415                    getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory, destinationInterceptor,getScheduler(),getExecutor());
2416            } catch(MalformedObjectNameException me){
2417                LOG.warn("Cannot create ManagedRegionBroker due " + me.getMessage(), me);
2418                throw new IOException(me);
2419            }
2420        } else {
2421            regionBroker = new RegionBroker(this, getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory,
2422                    destinationInterceptor,getScheduler(),getExecutor());
2423        }
2424        destinationFactory.setRegionBroker(regionBroker);
2425        regionBroker.setKeepDurableSubsActive(keepDurableSubsActive);
2426        regionBroker.setBrokerName(getBrokerName());
2427        regionBroker.getDestinationStatistics().setEnabled(enableStatistics);
2428        regionBroker.setAllowTempAutoCreationOnSend(isAllowTempAutoCreationOnSend());
2429        if (brokerId != null) {
2430            regionBroker.setBrokerId(brokerId);
2431        }
2432        return regionBroker;
2433    }
2434
2435    /**
2436     * Create the default destination interceptor
2437     */
2438    protected DestinationInterceptor[] createDefaultDestinationInterceptor() {
2439        List<DestinationInterceptor> answer = new ArrayList<>();
2440        if (isUseVirtualTopics()) {
2441            VirtualDestinationInterceptor interceptor = new VirtualDestinationInterceptor();
2442            VirtualTopic virtualTopic = new VirtualTopic();
2443            virtualTopic.setName("VirtualTopic.>");
2444            VirtualDestination[] virtualDestinations = { virtualTopic };
2445            interceptor.setVirtualDestinations(virtualDestinations);
2446            answer.add(interceptor);
2447        }
2448        if (isUseMirroredQueues()) {
2449            MirroredQueue interceptor = new MirroredQueue();
2450            answer.add(interceptor);
2451        }
2452        DestinationInterceptor[] array = new DestinationInterceptor[answer.size()];
2453        answer.toArray(array);
2454        return array;
2455    }
2456
2457    /**
2458     * Strategy method to add interceptors to the broker
2459     *
2460     * @throws IOException
2461     */
2462    protected Broker addInterceptors(Broker broker) throws Exception {
2463        if (isSchedulerSupport()) {
2464            SchedulerBroker sb = new SchedulerBroker(this, broker, getJobSchedulerStore());
2465            sb.setMaxRepeatAllowed(maxSchedulerRepeatAllowed);
2466            if (isUseJmx()) {
2467                JobSchedulerViewMBean view = new JobSchedulerView(sb.getJobScheduler());
2468                try {
2469                    ObjectName objectName = BrokerMBeanSupport.createJobSchedulerServiceName(getBrokerObjectName());
2470                    AnnotatedMBean.registerMBean(getManagementContext(), view, objectName);
2471                    this.adminView.setJMSJobScheduler(objectName);
2472                } catch (Throwable e) {
2473                    throw IOExceptionSupport.create("JobScheduler could not be registered in JMX: "
2474                            + e.getMessage(), e);
2475                }
2476            }
2477            broker = sb;
2478        }
2479        if (isUseJmx()) {
2480            HealthViewMBean statusView = new HealthView((ManagedRegionBroker)getRegionBroker());
2481            try {
2482                ObjectName objectName = BrokerMBeanSupport.createHealthServiceName(getBrokerObjectName());
2483                AnnotatedMBean.registerMBean(getManagementContext(), statusView, objectName);
2484            } catch (Throwable e) {
2485                throw IOExceptionSupport.create("Status MBean could not be registered in JMX: "
2486                        + e.getMessage(), e);
2487            }
2488        }
2489        if (isAdvisorySupport()) {
2490            broker = new AdvisoryBroker(broker);
2491        }
2492        broker = new CompositeDestinationBroker(broker);
2493        broker = new TransactionBroker(broker, getPersistenceAdapter().createTransactionStore());
2494        if (isPopulateJMSXUserID()) {
2495            UserIDBroker userIDBroker = new UserIDBroker(broker);
2496            userIDBroker.setUseAuthenticatePrincipal(isUseAuthenticatedPrincipalForJMSXUserID());
2497            broker = userIDBroker;
2498        }
2499        if (isMonitorConnectionSplits()) {
2500            broker = new ConnectionSplitBroker(broker);
2501        }
2502        if (plugins != null) {
2503            for (int i = 0; i < plugins.length; i++) {
2504                BrokerPlugin plugin = plugins[i];
2505                broker = plugin.installPlugin(broker);
2506            }
2507        }
2508        return broker;
2509    }
2510
2511    protected PersistenceAdapter createPersistenceAdapter() throws IOException {
2512        if (isPersistent()) {
2513            PersistenceAdapterFactory fac = getPersistenceFactory();
2514            if (fac != null) {
2515                return fac.createPersistenceAdapter();
2516            } else {
2517                try {
2518                    String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter";
2519                    PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance();
2520                    File dir = new File(getBrokerDataDirectory(),"KahaDB");
2521                    adaptor.setDirectory(dir);
2522                    return adaptor;
2523                } catch (Throwable e) {
2524                    throw IOExceptionSupport.create(e);
2525                }
2526            }
2527        } else {
2528            return new MemoryPersistenceAdapter();
2529        }
2530    }
2531
2532    protected ObjectName createBrokerObjectName() throws MalformedObjectNameException  {
2533        return BrokerMBeanSupport.createBrokerObjectName(getManagementContext().getJmxDomainName(), getBrokerName());
2534    }
2535
2536    protected TransportConnector createTransportConnector(URI brokerURI) throws Exception {
2537        TransportServer transport = TransportFactorySupport.bind(this, brokerURI);
2538        return new TransportConnector(transport);
2539    }
2540
2541    /**
2542     * Extracts the port from the options
2543     */
2544    protected Object getPort(Map<?,?> options) {
2545        Object port = options.get("port");
2546        if (port == null) {
2547            port = DEFAULT_PORT;
2548            LOG.warn("No port specified so defaulting to: {}", port);
2549        }
2550        return port;
2551    }
2552
2553    protected void addShutdownHook() {
2554        if (useShutdownHook) {
2555            shutdownHook = new Thread("ActiveMQ ShutdownHook") {
2556                @Override
2557                public void run() {
2558                    containerShutdown();
2559                }
2560            };
2561            Runtime.getRuntime().addShutdownHook(shutdownHook);
2562        }
2563    }
2564
2565    protected void removeShutdownHook() {
2566        if (shutdownHook != null) {
2567            try {
2568                Runtime.getRuntime().removeShutdownHook(shutdownHook);
2569            } catch (Exception e) {
2570                LOG.debug("Caught exception, must be shutting down. This exception is ignored.", e);
2571            }
2572        }
2573    }
2574
2575    /**
2576     * Sets hooks to be executed when broker shut down
2577     *
2578     * @org.apache.xbean.Property
2579     */
2580    public void setShutdownHooks(List<Runnable> hooks) throws Exception {
2581        for (Runnable hook : hooks) {
2582            addShutdownHook(hook);
2583        }
2584    }
2585
2586    /**
2587     * Causes a clean shutdown of the container when the VM is being shut down
2588     */
2589    protected void containerShutdown() {
2590        try {
2591            stop();
2592        } catch (IOException e) {
2593            Throwable linkedException = e.getCause();
2594            if (linkedException != null) {
2595                logError("Failed to shut down: " + e + ". Reason: " + linkedException, linkedException);
2596            } else {
2597                logError("Failed to shut down: " + e, e);
2598            }
2599            if (!useLoggingForShutdownErrors) {
2600                e.printStackTrace(System.err);
2601            }
2602        } catch (Exception e) {
2603            logError("Failed to shut down: " + e, e);
2604        }
2605    }
2606
2607    protected void logError(String message, Throwable e) {
2608        if (useLoggingForShutdownErrors) {
2609            LOG.error("Failed to shut down: " + e);
2610        } else {
2611            System.err.println("Failed to shut down: " + e);
2612        }
2613    }
2614
2615    /**
2616     * Starts any configured destinations on startup
2617     */
2618    protected void startDestinations() throws Exception {
2619        if (destinations != null) {
2620            ConnectionContext adminConnectionContext = getAdminConnectionContext();
2621            for (int i = 0; i < destinations.length; i++) {
2622                ActiveMQDestination destination = destinations[i];
2623                getBroker().addDestination(adminConnectionContext, destination,true);
2624            }
2625        }
2626        if (isUseVirtualTopics()) {
2627            startVirtualConsumerDestinations();
2628        }
2629    }
2630
2631    /**
2632     * Returns the broker's administration connection context used for
2633     * configuring the broker at startup
2634     */
2635    public ConnectionContext getAdminConnectionContext() throws Exception {
2636        return BrokerSupport.getConnectionContext(getBroker());
2637    }
2638
2639    protected void startManagementContext() throws Exception {
2640        getManagementContext().setBrokerName(brokerName);
2641        getManagementContext().start();
2642        adminView = new BrokerView(this, null);
2643        ObjectName objectName = getBrokerObjectName();
2644        AnnotatedMBean.registerMBean(getManagementContext(), adminView, objectName);
2645    }
2646
2647    /**
2648     * Start all transport and network connections, proxies and bridges
2649     *
2650     * @throws Exception
2651     */
2652    public void startAllConnectors() throws Exception {
2653        final Set<ActiveMQDestination> durableDestinations = getBroker().getDurableDestinations();
2654        List<TransportConnector> al = new ArrayList<>();
2655        for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) {
2656            TransportConnector connector = iter.next();
2657            al.add(startTransportConnector(connector));
2658        }
2659        if (al.size() > 0) {
2660            // let's clear the transportConnectors list and replace it with
2661            // the started transportConnector instances
2662            this.transportConnectors.clear();
2663            setTransportConnectors(al);
2664        }
2665        this.slave = false;
2666        if (!stopped.get()) {
2667            ThreadPoolExecutor networkConnectorStartExecutor = null;
2668            if (isNetworkConnectorStartAsync()) {
2669                // spin up as many threads as needed
2670                networkConnectorStartExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE,
2671                    10, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
2672                    new ThreadFactory() {
2673                        int count=0;
2674                        @Override
2675                        public Thread newThread(Runnable runnable) {
2676                            Thread thread = new Thread(runnable, "NetworkConnector Start Thread-" +(count++));
2677                            thread.setDaemon(true);
2678                            return thread;
2679                        }
2680                    });
2681            }
2682
2683            for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) {
2684                final NetworkConnector connector = iter.next();
2685                connector.setLocalUri(getVmConnectorURI());
2686                startNetworkConnector(connector, durableDestinations, networkConnectorStartExecutor);
2687            }
2688            if (networkConnectorStartExecutor != null) {
2689                // executor done when enqueued tasks are complete
2690                ThreadPoolUtils.shutdown(networkConnectorStartExecutor);
2691            }
2692
2693            for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) {
2694                ProxyConnector connector = iter.next();
2695                connector.start();
2696            }
2697            for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) {
2698                JmsConnector connector = iter.next();
2699                connector.start();
2700            }
2701            for (Service service : services) {
2702                configureService(service);
2703                service.start();
2704            }
2705        }
2706    }
2707
2708    public void startNetworkConnector(final NetworkConnector connector,
2709            final ThreadPoolExecutor networkConnectorStartExecutor) throws Exception {
2710        startNetworkConnector(connector, getBroker().getDurableDestinations(), networkConnectorStartExecutor);
2711    }
2712
2713    public void startNetworkConnector(final NetworkConnector connector,
2714            final Set<ActiveMQDestination> durableDestinations,
2715            final ThreadPoolExecutor networkConnectorStartExecutor) throws Exception {
2716        connector.setBrokerName(getBrokerName());
2717        //set the durable destinations to match the broker if not set on the connector
2718        if (connector.getDurableDestinations() == null) {
2719            connector.setDurableDestinations(durableDestinations);
2720        }
2721        String defaultSocketURI = getDefaultSocketURIString();
2722        if (defaultSocketURI != null) {
2723            connector.setBrokerURL(defaultSocketURI);
2724        }
2725        //If using the runtime plugin to start a network connector then the mbean needs
2726        //to be added, under normal start it will already exist so check for InstanceNotFoundException
2727        if (isUseJmx()) {
2728            ObjectName networkMbean = createNetworkConnectorObjectName(connector);
2729            try {
2730                getManagementContext().getObjectInstance(networkMbean);
2731            } catch (InstanceNotFoundException e) {
2732                LOG.debug("Network connector MBean {} not found, registering", networkMbean);
2733                registerNetworkConnectorMBean(connector);
2734            }
2735        }
2736        if (networkConnectorStartExecutor != null) {
2737            networkConnectorStartExecutor.execute(new Runnable() {
2738                @Override
2739                public void run() {
2740                    try {
2741                        LOG.info("Async start of {}", connector);
2742                        connector.start();
2743                    } catch(Exception e) {
2744                        LOG.error("Async start of network connector: {} failed", connector, e);
2745                    }
2746                }
2747            });
2748        } else {
2749            connector.start();
2750        }
2751    }
2752
2753    public TransportConnector startTransportConnector(TransportConnector connector) throws Exception {
2754        connector.setBrokerService(this);
2755        connector.setTaskRunnerFactory(getTaskRunnerFactory());
2756        MessageAuthorizationPolicy policy = getMessageAuthorizationPolicy();
2757        if (policy != null) {
2758            connector.setMessageAuthorizationPolicy(policy);
2759        }
2760        if (isUseJmx()) {
2761            connector = registerConnectorMBean(connector);
2762        }
2763        connector.getStatistics().setEnabled(enableStatistics);
2764        connector.start();
2765        return connector;
2766    }
2767
2768    /**
2769     * Perform any custom dependency injection
2770     */
2771    protected void configureServices(Object[] services) {
2772        for (Object service : services) {
2773            configureService(service);
2774        }
2775    }
2776
2777    /**
2778     * Perform any custom dependency injection
2779     */
2780    protected void configureService(Object service) {
2781        if (service instanceof BrokerServiceAware) {
2782            BrokerServiceAware serviceAware = (BrokerServiceAware) service;
2783            serviceAware.setBrokerService(this);
2784        }
2785    }
2786
2787    public void handleIOException(IOException exception) {
2788        if (ioExceptionHandler != null) {
2789            ioExceptionHandler.handle(exception);
2790         } else {
2791            LOG.info("No IOExceptionHandler registered, ignoring IO exception", exception);
2792         }
2793    }
2794
2795    protected void startVirtualConsumerDestinations() throws Exception {
2796        checkStartException();
2797        ConnectionContext adminConnectionContext = getAdminConnectionContext();
2798        Set<ActiveMQDestination> destinations = destinationFactory.getDestinations();
2799        DestinationFilter filter = getVirtualTopicConsumerDestinationFilter();
2800        if (!destinations.isEmpty()) {
2801            for (ActiveMQDestination destination : destinations) {
2802                if (filter.matches(destination) == true) {
2803                    broker.addDestination(adminConnectionContext, destination, false);
2804                }
2805            }
2806        }
2807    }
2808
2809    private DestinationFilter getVirtualTopicConsumerDestinationFilter() {
2810        // created at startup, so no sync needed
2811        if (virtualConsumerDestinationFilter == null) {
2812            Set <ActiveMQQueue> consumerDestinations = new HashSet<>();
2813            if (destinationInterceptors != null) {
2814                for (DestinationInterceptor interceptor : destinationInterceptors) {
2815                    if (interceptor instanceof VirtualDestinationInterceptor) {
2816                        VirtualDestinationInterceptor virtualDestinationInterceptor = (VirtualDestinationInterceptor) interceptor;
2817                        for (VirtualDestination virtualDestination: virtualDestinationInterceptor.getVirtualDestinations()) {
2818                            if (virtualDestination instanceof VirtualTopic) {
2819                                consumerDestinations.add(new ActiveMQQueue(((VirtualTopic) virtualDestination).getPrefix() + DestinationFilter.ANY_DESCENDENT));
2820                            }
2821                            if (isUseVirtualDestSubs()) {
2822                                try {
2823                                    broker.virtualDestinationAdded(getAdminConnectionContext(), virtualDestination);
2824                                    LOG.debug("Adding virtual destination: {}", virtualDestination);
2825                                } catch (Exception e) {
2826                                    LOG.warn("Could not fire virtual destination consumer advisory", e);
2827                                }
2828                            }
2829                        }
2830                    }
2831                }
2832            }
2833            ActiveMQQueue filter = new ActiveMQQueue();
2834            filter.setCompositeDestinations(consumerDestinations.toArray(new ActiveMQDestination[]{}));
2835            virtualConsumerDestinationFilter = DestinationFilter.parseFilter(filter);
2836        }
2837        return virtualConsumerDestinationFilter;
2838    }
2839
2840    protected synchronized ThreadPoolExecutor getExecutor() {
2841        if (this.executor == null) {
2842            this.executor = new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
2843
2844                private long i = 0;
2845
2846                @Override
2847                public Thread newThread(Runnable runnable) {
2848                    this.i++;
2849                    Thread thread = new Thread(runnable, "ActiveMQ BrokerService.worker." + this.i);
2850                    thread.setDaemon(true);
2851                    thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
2852                        @Override
2853                        public void uncaughtException(final Thread t, final Throwable e) {
2854                            LOG.error("Error in thread '{}'", t.getName(), e);
2855                        }
2856                    });
2857                    return thread;
2858                }
2859            }, new RejectedExecutionHandler() {
2860                @Override
2861                public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) {
2862                    try {
2863                        if (!executor.getQueue().offer(r, 60, TimeUnit.SECONDS)) {
2864                            throw new RejectedExecutionException("Timed Out while attempting to enqueue Task.");
2865                        }
2866                    } catch (InterruptedException e) {
2867                        throw new RejectedExecutionException("Interrupted waiting for BrokerService.worker");
2868                    }
2869                }
2870            });
2871        }
2872        return this.executor;
2873    }
2874
2875    public synchronized Scheduler getScheduler() {
2876        if (this.scheduler==null) {
2877            this.scheduler = new Scheduler("ActiveMQ Broker["+getBrokerName()+"] Scheduler");
2878            try {
2879                this.scheduler.start();
2880            } catch (Exception e) {
2881               LOG.error("Failed to start Scheduler", e);
2882            }
2883        }
2884        return this.scheduler;
2885    }
2886
2887    public Broker getRegionBroker() {
2888        return regionBroker;
2889    }
2890
2891    public void setRegionBroker(Broker regionBroker) {
2892        this.regionBroker = regionBroker;
2893    }
2894
2895    public final void removePreShutdownHook(final Runnable hook) {
2896        preShutdownHooks.remove(hook);
2897    }
2898
2899    public void addShutdownHook(Runnable hook) {
2900        synchronized (shutdownHooks) {
2901            shutdownHooks.add(hook);
2902        }
2903    }
2904
2905    public void removeShutdownHook(Runnable hook) {
2906        synchronized (shutdownHooks) {
2907            shutdownHooks.remove(hook);
2908        }
2909    }
2910
2911    public boolean isSystemExitOnShutdown() {
2912        return systemExitOnShutdown;
2913    }
2914
2915    /**
2916     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2917     */
2918    public void setSystemExitOnShutdown(boolean systemExitOnShutdown) {
2919        this.systemExitOnShutdown = systemExitOnShutdown;
2920    }
2921
2922    public int getSystemExitOnShutdownExitCode() {
2923        return systemExitOnShutdownExitCode;
2924    }
2925
2926    public void setSystemExitOnShutdownExitCode(int systemExitOnShutdownExitCode) {
2927        this.systemExitOnShutdownExitCode = systemExitOnShutdownExitCode;
2928    }
2929
2930    public SslContext getSslContext() {
2931        return sslContext;
2932    }
2933
2934    public void setSslContext(SslContext sslContext) {
2935        this.sslContext = sslContext;
2936    }
2937
2938    public boolean isShutdownOnSlaveFailure() {
2939        return shutdownOnSlaveFailure;
2940    }
2941
2942    /**
2943     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2944     */
2945    public void setShutdownOnSlaveFailure(boolean shutdownOnSlaveFailure) {
2946        this.shutdownOnSlaveFailure = shutdownOnSlaveFailure;
2947    }
2948
2949    public boolean isWaitForSlave() {
2950        return waitForSlave;
2951    }
2952
2953    /**
2954     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2955     */
2956    public void setWaitForSlave(boolean waitForSlave) {
2957        this.waitForSlave = waitForSlave;
2958    }
2959
2960    public long getWaitForSlaveTimeout() {
2961        return this.waitForSlaveTimeout;
2962    }
2963
2964    public void setWaitForSlaveTimeout(long waitForSlaveTimeout) {
2965        this.waitForSlaveTimeout = waitForSlaveTimeout;
2966    }
2967
2968    /**
2969     * Get the passiveSlave
2970     * @return the passiveSlave
2971     */
2972    public boolean isPassiveSlave() {
2973        return this.passiveSlave;
2974    }
2975
2976    /**
2977     * Set the passiveSlave
2978     * @param passiveSlave the passiveSlave to set
2979     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
2980     */
2981    public void setPassiveSlave(boolean passiveSlave) {
2982        this.passiveSlave = passiveSlave;
2983    }
2984
2985    /**
2986     * override the Default IOException handler, called when persistence adapter
2987     * has experiences File or JDBC I/O Exceptions
2988     *
2989     * @param ioExceptionHandler
2990     */
2991    public void setIoExceptionHandler(IOExceptionHandler ioExceptionHandler) {
2992        configureService(ioExceptionHandler);
2993        this.ioExceptionHandler = ioExceptionHandler;
2994    }
2995
2996    public IOExceptionHandler getIoExceptionHandler() {
2997        return ioExceptionHandler;
2998    }
2999
3000    /**
3001     * @return the schedulerSupport
3002     */
3003    public boolean isSchedulerSupport() {
3004        return this.schedulerSupport;
3005    }
3006
3007    /**
3008     * @param schedulerSupport the schedulerSupport to set
3009     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor"
3010     */
3011    public void setSchedulerSupport(boolean schedulerSupport) {
3012        this.schedulerSupport = schedulerSupport;
3013    }
3014
3015    /**
3016     * @return the schedulerDirectory
3017     */
3018    public File getSchedulerDirectoryFile() {
3019        if (this.schedulerDirectoryFile == null) {
3020            this.schedulerDirectoryFile = new File(getBrokerDataDirectory(), "scheduler");
3021        }
3022        return schedulerDirectoryFile;
3023    }
3024
3025    /**
3026     * @param schedulerDirectory the schedulerDirectory to set
3027     */
3028    public void setSchedulerDirectoryFile(File schedulerDirectory) {
3029        this.schedulerDirectoryFile = schedulerDirectory;
3030    }
3031
3032    public void setSchedulerDirectory(String schedulerDirectory) {
3033        setSchedulerDirectoryFile(new File(schedulerDirectory));
3034    }
3035
3036    public int getSchedulePeriodForDestinationPurge() {
3037        return this.schedulePeriodForDestinationPurge;
3038    }
3039
3040    public void setSchedulePeriodForDestinationPurge(int schedulePeriodForDestinationPurge) {
3041        this.schedulePeriodForDestinationPurge = schedulePeriodForDestinationPurge;
3042    }
3043
3044    /**
3045     * @param schedulePeriodForDiskUsageCheck
3046     */
3047    public void setSchedulePeriodForDiskUsageCheck(
3048            int schedulePeriodForDiskUsageCheck) {
3049        this.schedulePeriodForDiskUsageCheck = schedulePeriodForDiskUsageCheck;
3050    }
3051
3052    public int getDiskUsageCheckRegrowThreshold() {
3053        return diskUsageCheckRegrowThreshold;
3054    }
3055
3056    /**
3057     * @param diskUsageCheckRegrowThreshold
3058     * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.MemoryPropertyEditor"
3059     */
3060    public void setDiskUsageCheckRegrowThreshold(int diskUsageCheckRegrowThreshold) {
3061        this.diskUsageCheckRegrowThreshold = diskUsageCheckRegrowThreshold;
3062    }
3063
3064    public int getMaxPurgedDestinationsPerSweep() {
3065        return this.maxPurgedDestinationsPerSweep;
3066    }
3067
3068    public void setMaxPurgedDestinationsPerSweep(int maxPurgedDestinationsPerSweep) {
3069        this.maxPurgedDestinationsPerSweep = maxPurgedDestinationsPerSweep;
3070    }
3071
3072    public BrokerContext getBrokerContext() {
3073        return brokerContext;
3074    }
3075
3076    public void setBrokerContext(BrokerContext brokerContext) {
3077        this.brokerContext = brokerContext;
3078    }
3079
3080    public void setBrokerId(String brokerId) {
3081        this.brokerId = new BrokerId(brokerId);
3082    }
3083
3084    public boolean isUseAuthenticatedPrincipalForJMSXUserID() {
3085        return useAuthenticatedPrincipalForJMSXUserID;
3086    }
3087
3088    public void setUseAuthenticatedPrincipalForJMSXUserID(boolean useAuthenticatedPrincipalForJMSXUserID) {
3089        this.useAuthenticatedPrincipalForJMSXUserID = useAuthenticatedPrincipalForJMSXUserID;
3090    }
3091
3092    /**
3093     * Should MBeans that support showing the Authenticated User Name information have this
3094     * value filled in or not.
3095     *
3096     * @return true if user names should be exposed in MBeans
3097     */
3098    public boolean isPopulateUserNameInMBeans() {
3099        return this.populateUserNameInMBeans;
3100    }
3101
3102    /**
3103     * Sets whether Authenticated User Name information is shown in MBeans that support this field.
3104     * @param value if MBeans should expose user name information.
3105     */
3106    public void setPopulateUserNameInMBeans(boolean value) {
3107        this.populateUserNameInMBeans = value;
3108    }
3109
3110    /**
3111     * Gets the time in Milliseconds that an invocation of an MBean method will wait before
3112     * failing.  The default value is to wait forever (zero).
3113     *
3114     * @return timeout in milliseconds before MBean calls fail, (default is 0 or no timeout).
3115     */
3116    public long getMbeanInvocationTimeout() {
3117        return mbeanInvocationTimeout;
3118    }
3119
3120    /**
3121     * Gets the time in Milliseconds that an invocation of an MBean method will wait before
3122     * failing. The default value is to wait forever (zero).
3123     *
3124     * @param mbeanInvocationTimeout
3125     *      timeout in milliseconds before MBean calls fail, (default is 0 or no timeout).
3126     */
3127    public void setMbeanInvocationTimeout(long mbeanInvocationTimeout) {
3128        this.mbeanInvocationTimeout = mbeanInvocationTimeout;
3129    }
3130
3131    public boolean isNetworkConnectorStartAsync() {
3132        return networkConnectorStartAsync;
3133    }
3134
3135    public void setNetworkConnectorStartAsync(boolean networkConnectorStartAsync) {
3136        this.networkConnectorStartAsync = networkConnectorStartAsync;
3137    }
3138
3139    public boolean isAllowTempAutoCreationOnSend() {
3140        return allowTempAutoCreationOnSend;
3141    }
3142
3143    /**
3144     * enable if temp destinations need to be propagated through a network when
3145     * advisorySupport==false. This is used in conjunction with the policy
3146     * gcInactiveDestinations for matching temps so they can get removed
3147     * when inactive
3148     *
3149     * @param allowTempAutoCreationOnSend
3150     */
3151    public void setAllowTempAutoCreationOnSend(boolean allowTempAutoCreationOnSend) {
3152        this.allowTempAutoCreationOnSend = allowTempAutoCreationOnSend;
3153    }
3154
3155    public long getOfflineDurableSubscriberTimeout() {
3156        return offlineDurableSubscriberTimeout;
3157    }
3158
3159    public void setOfflineDurableSubscriberTimeout(long offlineDurableSubscriberTimeout) {
3160        this.offlineDurableSubscriberTimeout = offlineDurableSubscriberTimeout;
3161    }
3162
3163    public long getOfflineDurableSubscriberTaskSchedule() {
3164        return offlineDurableSubscriberTaskSchedule;
3165    }
3166
3167    public void setOfflineDurableSubscriberTaskSchedule(long offlineDurableSubscriberTaskSchedule) {
3168        this.offlineDurableSubscriberTaskSchedule = offlineDurableSubscriberTaskSchedule;
3169    }
3170
3171    public boolean shouldRecordVirtualDestination(ActiveMQDestination destination) {
3172        return isUseVirtualTopics() && destination.isQueue() &&
3173               getVirtualTopicConsumerDestinationFilter().matches(destination);
3174    }
3175
3176    synchronized public Throwable getStartException() {
3177        return startException;
3178    }
3179
3180    public boolean isStartAsync() {
3181        return startAsync;
3182    }
3183
3184    public void setStartAsync(boolean startAsync) {
3185        this.startAsync = startAsync;
3186    }
3187
3188    public boolean isSlave() {
3189        return this.slave;
3190    }
3191
3192    public boolean isStopping() {
3193        return this.stopping.get();
3194    }
3195
3196    /**
3197     * @return true if the broker allowed to restart on shutdown.
3198     */
3199    public boolean isRestartAllowed() {
3200        return restartAllowed;
3201    }
3202
3203    /**
3204     * Sets if the broker allowed to restart on shutdown.
3205     */
3206    public void setRestartAllowed(boolean restartAllowed) {
3207        this.restartAllowed = restartAllowed;
3208    }
3209
3210    /**
3211     * A lifecycle manager of the BrokerService should
3212     * inspect this property after a broker shutdown has occurred
3213     * to find out if the broker needs to be re-created and started
3214     * again.
3215     *
3216     * @return true if the broker wants to be restarted after it shuts down.
3217     */
3218    public boolean isRestartRequested() {
3219        return restartRequested;
3220    }
3221
3222    public void requestRestart() {
3223        this.restartRequested = true;
3224    }
3225
3226    public int getStoreOpenWireVersion() {
3227        return storeOpenWireVersion;
3228    }
3229
3230    public void setStoreOpenWireVersion(int storeOpenWireVersion) {
3231        this.storeOpenWireVersion = storeOpenWireVersion;
3232    }
3233
3234    /**
3235     * @return the current number of connections on this Broker.
3236     */
3237    public int getCurrentConnections() {
3238        return this.currentConnections.get();
3239    }
3240
3241    /**
3242     * @return the total number of connections this broker has handled since startup.
3243     */
3244    public long getTotalConnections() {
3245        return this.totalConnections.get();
3246    }
3247
3248    public void incrementCurrentConnections() {
3249        this.currentConnections.incrementAndGet();
3250    }
3251
3252    public void decrementCurrentConnections() {
3253        this.currentConnections.decrementAndGet();
3254    }
3255
3256    public void incrementTotalConnections() {
3257        this.totalConnections.incrementAndGet();
3258    }
3259
3260    public boolean isRejectDurableConsumers() {
3261        return rejectDurableConsumers;
3262    }
3263
3264    public void setRejectDurableConsumers(boolean rejectDurableConsumers) {
3265        this.rejectDurableConsumers = rejectDurableConsumers;
3266    }
3267
3268    public boolean isUseVirtualDestSubs() {
3269        return useVirtualDestSubs;
3270    }
3271
3272    public void setUseVirtualDestSubs(
3273            boolean useVirtualDestSubs) {
3274        this.useVirtualDestSubs = useVirtualDestSubs;
3275    }
3276
3277    public boolean isUseVirtualDestSubsOnCreation() {
3278        return useVirtualDestSubsOnCreation;
3279    }
3280
3281    public void setUseVirtualDestSubsOnCreation(
3282            boolean useVirtualDestSubsOnCreation) {
3283        this.useVirtualDestSubsOnCreation = useVirtualDestSubsOnCreation;
3284    }
3285
3286    public boolean isAdjustUsageLimits() {
3287        return adjustUsageLimits;
3288    }
3289
3290    public void setAdjustUsageLimits(boolean adjustUsageLimits) {
3291        this.adjustUsageLimits = adjustUsageLimits;
3292    }
3293
3294    public void setRollbackOnlyOnAsyncException(boolean rollbackOnlyOnAsyncException) {
3295        this.rollbackOnlyOnAsyncException = rollbackOnlyOnAsyncException;
3296    }
3297
3298    public boolean isRollbackOnlyOnAsyncException() {
3299        return rollbackOnlyOnAsyncException;
3300    }
3301
3302    public int getMaxSchedulerRepeatAllowed() {
3303        return maxSchedulerRepeatAllowed;
3304    }
3305
3306    public void setMaxSchedulerRepeatAllowed(int maxSchedulerRepeatAllowed) {
3307        this.maxSchedulerRepeatAllowed = maxSchedulerRepeatAllowed;
3308    }
3309}