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