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