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