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