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