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