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