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