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 (Exception e) { 1791 throw new RuntimeException(e); 1792 } 1793 } 1794 return tempDataStore; 1795 } 1796 1797 /** 1798 * @param tempDataStore 1799 * the tempDataStore to set 1800 */ 1801 public void setTempDataStore(PListStore tempDataStore) { 1802 this.tempDataStore = tempDataStore; 1803 if (tempDataStore != null) { 1804 if (tmpDataDirectory == null) { 1805 tmpDataDirectory = tempDataStore.getDirectory(); 1806 } else if (tempDataStore.getDirectory() == null) { 1807 tempDataStore.setDirectory(tmpDataDirectory); 1808 } 1809 } 1810 configureService(tempDataStore); 1811 } 1812 1813 public int getPersistenceThreadPriority() { 1814 return persistenceThreadPriority; 1815 } 1816 1817 public void setPersistenceThreadPriority(int persistenceThreadPriority) { 1818 this.persistenceThreadPriority = persistenceThreadPriority; 1819 } 1820 1821 /** 1822 * @return the useLocalHostBrokerName 1823 */ 1824 public boolean isUseLocalHostBrokerName() { 1825 return this.useLocalHostBrokerName; 1826 } 1827 1828 /** 1829 * @param useLocalHostBrokerName 1830 * the useLocalHostBrokerName to set 1831 */ 1832 public void setUseLocalHostBrokerName(boolean useLocalHostBrokerName) { 1833 this.useLocalHostBrokerName = useLocalHostBrokerName; 1834 if (useLocalHostBrokerName && !started.get() && brokerName == null || brokerName == DEFAULT_BROKER_NAME) { 1835 brokerName = LOCAL_HOST_NAME; 1836 } 1837 } 1838 1839 /** 1840 * Looks up and lazily creates if necessary the destination for the given 1841 * JMS name 1842 */ 1843 public Destination getDestination(ActiveMQDestination destination) throws Exception { 1844 return getBroker().addDestination(getAdminConnectionContext(), destination,false); 1845 } 1846 1847 public void removeDestination(ActiveMQDestination destination) throws Exception { 1848 getBroker().removeDestination(getAdminConnectionContext(), destination, 0); 1849 } 1850 1851 public int getProducerSystemUsagePortion() { 1852 return producerSystemUsagePortion; 1853 } 1854 1855 public void setProducerSystemUsagePortion(int producerSystemUsagePortion) { 1856 this.producerSystemUsagePortion = producerSystemUsagePortion; 1857 } 1858 1859 public int getConsumerSystemUsagePortion() { 1860 return consumerSystemUsagePortion; 1861 } 1862 1863 public void setConsumerSystemUsagePortion(int consumerSystemUsagePortion) { 1864 this.consumerSystemUsagePortion = consumerSystemUsagePortion; 1865 } 1866 1867 public boolean isSplitSystemUsageForProducersConsumers() { 1868 return splitSystemUsageForProducersConsumers; 1869 } 1870 1871 public void setSplitSystemUsageForProducersConsumers(boolean splitSystemUsageForProducersConsumers) { 1872 this.splitSystemUsageForProducersConsumers = splitSystemUsageForProducersConsumers; 1873 } 1874 1875 public boolean isMonitorConnectionSplits() { 1876 return monitorConnectionSplits; 1877 } 1878 1879 public void setMonitorConnectionSplits(boolean monitorConnectionSplits) { 1880 this.monitorConnectionSplits = monitorConnectionSplits; 1881 } 1882 1883 public int getTaskRunnerPriority() { 1884 return taskRunnerPriority; 1885 } 1886 1887 public void setTaskRunnerPriority(int taskRunnerPriority) { 1888 this.taskRunnerPriority = taskRunnerPriority; 1889 } 1890 1891 public boolean isDedicatedTaskRunner() { 1892 return dedicatedTaskRunner; 1893 } 1894 1895 public void setDedicatedTaskRunner(boolean dedicatedTaskRunner) { 1896 this.dedicatedTaskRunner = dedicatedTaskRunner; 1897 } 1898 1899 public boolean isCacheTempDestinations() { 1900 return cacheTempDestinations; 1901 } 1902 1903 public void setCacheTempDestinations(boolean cacheTempDestinations) { 1904 this.cacheTempDestinations = cacheTempDestinations; 1905 } 1906 1907 public int getTimeBeforePurgeTempDestinations() { 1908 return timeBeforePurgeTempDestinations; 1909 } 1910 1911 public void setTimeBeforePurgeTempDestinations(int timeBeforePurgeTempDestinations) { 1912 this.timeBeforePurgeTempDestinations = timeBeforePurgeTempDestinations; 1913 } 1914 1915 public boolean isUseTempMirroredQueues() { 1916 return useTempMirroredQueues; 1917 } 1918 1919 public void setUseTempMirroredQueues(boolean useTempMirroredQueues) { 1920 this.useTempMirroredQueues = useTempMirroredQueues; 1921 } 1922 1923 public synchronized JobSchedulerStore getJobSchedulerStore() { 1924 1925 // If support is off don't allow any scheduler even is user configured their own. 1926 if (!isSchedulerSupport()) { 1927 return null; 1928 } 1929 1930 // If the user configured their own we use it even if persistence is disabled since 1931 // we don't know anything about their implementation. 1932 if (jobSchedulerStore == null) { 1933 1934 if (!isPersistent()) { 1935 this.jobSchedulerStore = new InMemoryJobSchedulerStore(); 1936 configureService(jobSchedulerStore); 1937 return this.jobSchedulerStore; 1938 } 1939 1940 try { 1941 PersistenceAdapter pa = getPersistenceAdapter(); 1942 if (pa != null) { 1943 this.jobSchedulerStore = pa.createJobSchedulerStore(); 1944 jobSchedulerStore.setDirectory(getSchedulerDirectoryFile()); 1945 configureService(jobSchedulerStore); 1946 return this.jobSchedulerStore; 1947 } 1948 } catch (IOException e) { 1949 throw new RuntimeException(e); 1950 } catch (UnsupportedOperationException ex) { 1951 // It's ok if the store doesn't implement a scheduler. 1952 } catch (Exception e) { 1953 throw new RuntimeException(e); 1954 } 1955 1956 try { 1957 PersistenceAdapter pa = getPersistenceAdapter(); 1958 if (pa != null && pa instanceof JobSchedulerStore) { 1959 this.jobSchedulerStore = (JobSchedulerStore) pa; 1960 configureService(jobSchedulerStore); 1961 return this.jobSchedulerStore; 1962 } 1963 } catch (IOException e) { 1964 throw new RuntimeException(e); 1965 } 1966 1967 // Load the KahaDB store as a last resort, this only works if KahaDB is 1968 // included at runtime, otherwise this will fail. User should disable 1969 // scheduler support if this fails. 1970 try { 1971 String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter"; 1972 PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance(); 1973 jobSchedulerStore = adaptor.createJobSchedulerStore(); 1974 jobSchedulerStore.setDirectory(getSchedulerDirectoryFile()); 1975 configureService(jobSchedulerStore); 1976 LOG.info("JobScheduler using directory: {}", getSchedulerDirectoryFile()); 1977 } catch (Exception e) { 1978 throw new RuntimeException(e); 1979 } 1980 } 1981 return jobSchedulerStore; 1982 } 1983 1984 public void setJobSchedulerStore(JobSchedulerStore jobSchedulerStore) { 1985 this.jobSchedulerStore = jobSchedulerStore; 1986 configureService(jobSchedulerStore); 1987 } 1988 1989 // 1990 // Implementation methods 1991 // ------------------------------------------------------------------------- 1992 /** 1993 * Handles any lazy-creation helper properties which are added to make 1994 * things easier to configure inside environments such as Spring 1995 * 1996 * @throws Exception 1997 */ 1998 protected void processHelperProperties() throws Exception { 1999 if (transportConnectorURIs != null) { 2000 for (int i = 0; i < transportConnectorURIs.length; i++) { 2001 String uri = transportConnectorURIs[i]; 2002 addConnector(uri); 2003 } 2004 } 2005 if (networkConnectorURIs != null) { 2006 for (int i = 0; i < networkConnectorURIs.length; i++) { 2007 String uri = networkConnectorURIs[i]; 2008 addNetworkConnector(uri); 2009 } 2010 } 2011 if (jmsBridgeConnectors != null) { 2012 for (int i = 0; i < jmsBridgeConnectors.length; i++) { 2013 addJmsConnector(jmsBridgeConnectors[i]); 2014 } 2015 } 2016 } 2017 2018 /** 2019 * Check that the store usage limit is not greater than max usable 2020 * space and adjust if it is 2021 */ 2022 protected void checkStoreUsageLimits() throws Exception { 2023 final SystemUsage usage = getSystemUsage(); 2024 2025 if (getPersistenceAdapter() != null) { 2026 PersistenceAdapter adapter = getPersistenceAdapter(); 2027 checkUsageLimit(adapter.getDirectory(), usage.getStoreUsage(), usage.getStoreUsage().getPercentLimit()); 2028 2029 long maxJournalFileSize = 0; 2030 long storeLimit = usage.getStoreUsage().getLimit(); 2031 2032 if (adapter instanceof JournaledStore) { 2033 maxJournalFileSize = ((JournaledStore) adapter).getJournalMaxFileLength(); 2034 } 2035 2036 if (storeLimit > 0 && storeLimit < maxJournalFileSize) { 2037 LOG.error("Store limit is " + storeLimit / (1024 * 1024) + 2038 " mb, whilst the max journal file size for the store is: " + 2039 maxJournalFileSize / (1024 * 1024) + " mb, " + 2040 "the store will not accept any data when used."); 2041 2042 } 2043 } 2044 } 2045 2046 /** 2047 * Check that temporary usage limit is not greater than max usable 2048 * space and adjust if it is 2049 */ 2050 protected void checkTmpStoreUsageLimits() throws Exception { 2051 final SystemUsage usage = getSystemUsage(); 2052 2053 File tmpDir = getTmpDataDirectory(); 2054 2055 if (tmpDir != null) { 2056 checkUsageLimit(tmpDir, usage.getTempUsage(), usage.getTempUsage().getPercentLimit()); 2057 2058 if (isPersistent()) { 2059 long maxJournalFileSize; 2060 2061 PListStore store = usage.getTempUsage().getStore(); 2062 if (store != null && store instanceof JournaledStore) { 2063 maxJournalFileSize = ((JournaledStore) store).getJournalMaxFileLength(); 2064 } else { 2065 maxJournalFileSize = DEFAULT_MAX_FILE_LENGTH; 2066 } 2067 long storeLimit = usage.getTempUsage().getLimit(); 2068 2069 if (storeLimit > 0 && storeLimit < maxJournalFileSize) { 2070 LOG.error("Temporary Store limit is " + storeLimit / (1024 * 1024) + 2071 " mb, whilst the max journal file size for the temporary store is: " + 2072 maxJournalFileSize / (1024 * 1024) + " mb, " + 2073 "the temp store will not accept any data when used."); 2074 } 2075 } 2076 } 2077 } 2078 2079 protected void checkUsageLimit(File dir, PercentLimitUsage<?> storeUsage, int percentLimit) throws ConfigurationException { 2080 if (dir != null) { 2081 dir = StoreUtil.findParentDirectory(dir); 2082 String storeName = storeUsage instanceof StoreUsage ? "Store" : "Temporary Store"; 2083 long storeLimit = storeUsage.getLimit(); 2084 long storeCurrent = storeUsage.getUsage(); 2085 long totalSpace = storeUsage.getTotal() > 0 ? storeUsage.getTotal() : dir.getTotalSpace(); 2086 long totalUsableSpace = (storeUsage.getTotal() > 0 ? storeUsage.getTotal() : dir.getUsableSpace()) + storeCurrent; 2087 if (totalUsableSpace < 0 || totalSpace < 0) { 2088 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"; 2089 LOG.error(message); 2090 throw new ConfigurationException(message); 2091 } 2092 //compute byte value of the percent limit 2093 long bytePercentLimit = totalSpace * percentLimit / 100; 2094 int oneMeg = 1024 * 1024; 2095 2096 //Check if the store limit is less than the percent Limit that was set and also 2097 //the usable space...this means we can grow the store larger 2098 //Changes in partition size (total space) as well as changes in usable space should 2099 //be detected here 2100 if (diskUsageCheckRegrowThreshold > -1 && percentLimit > 0 2101 && storeUsage.getTotal() == 0 2102 && storeLimit < bytePercentLimit && storeLimit < totalUsableSpace){ 2103 2104 // set the limit to be bytePercentLimit or usableSpace if 2105 // usableSpace is less than the percentLimit 2106 long newLimit = bytePercentLimit > totalUsableSpace ? totalUsableSpace : bytePercentLimit; 2107 2108 //To prevent changing too often, check threshold 2109 if (newLimit - storeLimit >= diskUsageCheckRegrowThreshold) { 2110 LOG.info("Usable disk space has been increased, attempting to regrow " + storeName + " limit to " 2111 + percentLimit + "% of the partition size."); 2112 storeUsage.setLimit(newLimit); 2113 LOG.info(storeName + " limit has been increased to " + newLimit * 100 / totalSpace 2114 + "% (" + newLimit / oneMeg + " mb) of the partition size."); 2115 } 2116 2117 //check if the limit is too large for the amount of usable space 2118 } else if (storeLimit > totalUsableSpace) { 2119 final String message = storeName + " limit is " + storeLimit / oneMeg 2120 + " mb (current store usage is " + storeCurrent / oneMeg 2121 + " mb). The data directory: " + dir.getAbsolutePath() 2122 + " only has " + totalUsableSpace / oneMeg 2123 + " mb of usable space."; 2124 2125 if (!isAdjustUsageLimits()) { 2126 LOG.error(message); 2127 throw new ConfigurationException(message); 2128 } 2129 2130 if (percentLimit > 0) { 2131 LOG.warn(storeName + " limit has been set to " 2132 + percentLimit + "% (" + bytePercentLimit / oneMeg + " mb)" 2133 + " of the partition size but there is not enough usable space." 2134 + " The current store limit (which may have been adjusted by a" 2135 + " previous usage limit check) is set to (" + storeLimit / oneMeg + " mb)" 2136 + " but only " + totalUsableSpace * 100 / totalSpace + "% (" + totalUsableSpace / oneMeg + " mb)" 2137 + " is available - resetting limit"); 2138 } else { 2139 LOG.warn(message + " - resetting to maximum available disk space: " + 2140 totalUsableSpace / oneMeg + " mb"); 2141 } 2142 storeUsage.setLimit(totalUsableSpace); 2143 } 2144 } 2145 } 2146 2147 /** 2148 * Schedules a periodic task based on schedulePeriodForDiskLimitCheck to 2149 * update store and temporary store limits if the amount of available space 2150 * plus current store size is less than the existin configured limit 2151 */ 2152 protected void scheduleDiskUsageLimitsCheck() throws IOException { 2153 if (schedulePeriodForDiskUsageCheck > 0 && 2154 (getPersistenceAdapter() != null || getTmpDataDirectory() != null)) { 2155 Runnable diskLimitCheckTask = new Runnable() { 2156 @Override 2157 public void run() { 2158 try { 2159 checkStoreUsageLimits(); 2160 } catch (Exception e) { 2161 LOG.error("Failed to check persistent disk usage limits", e); 2162 } 2163 2164 try { 2165 checkTmpStoreUsageLimits(); 2166 } catch (Exception e) { 2167 LOG.error("Failed to check temporary store usage limits", e); 2168 } 2169 } 2170 }; 2171 scheduler.executePeriodically(diskLimitCheckTask, schedulePeriodForDiskUsageCheck); 2172 } 2173 } 2174 2175 protected void checkMemorySystemUsageLimits() throws Exception { 2176 final SystemUsage usage = getSystemUsage(); 2177 long memLimit = usage.getMemoryUsage().getLimit(); 2178 long jvmLimit = Runtime.getRuntime().maxMemory(); 2179 2180 if (memLimit > jvmLimit) { 2181 final String message = "Memory Usage for the Broker (" + memLimit / (1024 * 1024) 2182 + "mb) is more than the maximum available for the JVM: " + jvmLimit / (1024 * 1024); 2183 2184 if (adjustUsageLimits) { 2185 usage.getMemoryUsage().setPercentOfJvmHeap(70); 2186 LOG.warn(message + " mb - resetting to 70% of maximum available: " + (usage.getMemoryUsage().getLimit() / (1024 * 1024)) + " mb"); 2187 } else { 2188 LOG.error(message); 2189 throw new ConfigurationException(message); 2190 } 2191 } 2192 } 2193 2194 protected void checkStoreSystemUsageLimits() throws Exception { 2195 final SystemUsage usage = getSystemUsage(); 2196 2197 //Check the persistent store and temp store limits if they exist 2198 //and schedule a periodic check to update disk limits if 2199 //schedulePeriodForDiskLimitCheck is set 2200 checkStoreUsageLimits(); 2201 checkTmpStoreUsageLimits(); 2202 scheduleDiskUsageLimitsCheck(); 2203 2204 if (getJobSchedulerStore() != null) { 2205 JobSchedulerStore scheduler = getJobSchedulerStore(); 2206 File schedulerDir = scheduler.getDirectory(); 2207 if (schedulerDir != null) { 2208 2209 String schedulerDirPath = schedulerDir.getAbsolutePath(); 2210 if (!schedulerDir.isAbsolute()) { 2211 schedulerDir = new File(schedulerDirPath); 2212 } 2213 2214 while (schedulerDir != null && !schedulerDir.isDirectory()) { 2215 schedulerDir = schedulerDir.getParentFile(); 2216 } 2217 long schedulerLimit = usage.getJobSchedulerUsage().getLimit(); 2218 long dirFreeSpace = schedulerDir.getUsableSpace(); 2219 if (schedulerLimit > dirFreeSpace) { 2220 LOG.warn("Job Scheduler Store limit is " + schedulerLimit / (1024 * 1024) + 2221 " mb, whilst the data directory: " + schedulerDir.getAbsolutePath() + 2222 " only has " + dirFreeSpace / (1024 * 1024) + " mb of usable space - resetting to " + 2223 dirFreeSpace / (1024 * 1024) + " mb."); 2224 usage.getJobSchedulerUsage().setLimit(dirFreeSpace); 2225 } 2226 } 2227 } 2228 } 2229 2230 public void stopAllConnectors(ServiceStopper stopper) { 2231 for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) { 2232 NetworkConnector connector = iter.next(); 2233 unregisterNetworkConnectorMBean(connector); 2234 stopper.stop(connector); 2235 } 2236 for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) { 2237 ProxyConnector connector = iter.next(); 2238 stopper.stop(connector); 2239 } 2240 for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) { 2241 JmsConnector connector = iter.next(); 2242 stopper.stop(connector); 2243 } 2244 for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) { 2245 TransportConnector connector = iter.next(); 2246 try { 2247 unregisterConnectorMBean(connector); 2248 } catch (IOException e) { 2249 } 2250 stopper.stop(connector); 2251 } 2252 } 2253 2254 protected TransportConnector registerConnectorMBean(TransportConnector connector) throws IOException { 2255 try { 2256 ObjectName objectName = createConnectorObjectName(connector); 2257 connector = connector.asManagedConnector(getManagementContext(), objectName); 2258 ConnectorViewMBean view = new ConnectorView(connector); 2259 AnnotatedMBean.registerMBean(getManagementContext(), view, objectName); 2260 return connector; 2261 } catch (Throwable e) { 2262 throw IOExceptionSupport.create("Transport Connector could not be registered in JMX: " + e, e); 2263 } 2264 } 2265 2266 protected void unregisterConnectorMBean(TransportConnector connector) throws IOException { 2267 if (isUseJmx()) { 2268 try { 2269 ObjectName objectName = createConnectorObjectName(connector); 2270 getManagementContext().unregisterMBean(objectName); 2271 } catch (Throwable e) { 2272 throw IOExceptionSupport.create( 2273 "Transport Connector could not be unregistered in JMX: " + e.getMessage(), e); 2274 } 2275 } 2276 } 2277 2278 protected PersistenceAdapter registerPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException { 2279 return adaptor; 2280 } 2281 2282 protected void unregisterPersistenceAdapterMBean(PersistenceAdapter adaptor) throws IOException { 2283 if (isUseJmx()) {} 2284 } 2285 2286 private ObjectName createConnectorObjectName(TransportConnector connector) throws MalformedObjectNameException { 2287 return BrokerMBeanSupport.createConnectorName(getBrokerObjectName(), "clientConnectors", connector.getName()); 2288 } 2289 2290 public void registerNetworkConnectorMBean(NetworkConnector connector) throws IOException { 2291 NetworkConnectorViewMBean view = new NetworkConnectorView(connector); 2292 try { 2293 ObjectName objectName = createNetworkConnectorObjectName(connector); 2294 connector.setObjectName(objectName); 2295 AnnotatedMBean.registerMBean(getManagementContext(), view, objectName); 2296 } catch (Throwable e) { 2297 throw IOExceptionSupport.create("Network Connector could not be registered in JMX: " + e.getMessage(), e); 2298 } 2299 } 2300 2301 public ObjectName createNetworkConnectorObjectName(NetworkConnector connector) throws MalformedObjectNameException { 2302 return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "networkConnectors", connector.getName()); 2303 } 2304 2305 public ObjectName createDuplexNetworkConnectorObjectName(String transport) throws MalformedObjectNameException { 2306 return BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "duplexNetworkConnectors", transport); 2307 } 2308 2309 protected void unregisterNetworkConnectorMBean(NetworkConnector connector) { 2310 if (isUseJmx()) { 2311 try { 2312 ObjectName objectName = createNetworkConnectorObjectName(connector); 2313 getManagementContext().unregisterMBean(objectName); 2314 } catch (Exception e) { 2315 LOG.warn("Network Connector could not be unregistered from JMX due " + e.getMessage() + ". This exception is ignored.", e); 2316 } 2317 } 2318 } 2319 2320 protected void registerProxyConnectorMBean(ProxyConnector connector) throws IOException { 2321 ProxyConnectorView view = new ProxyConnectorView(connector); 2322 try { 2323 ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "proxyConnectors", connector.getName()); 2324 AnnotatedMBean.registerMBean(getManagementContext(), view, objectName); 2325 } catch (Throwable e) { 2326 throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e); 2327 } 2328 } 2329 2330 protected void registerJmsConnectorMBean(JmsConnector connector) throws IOException { 2331 JmsConnectorView view = new JmsConnectorView(connector); 2332 try { 2333 ObjectName objectName = BrokerMBeanSupport.createNetworkConnectorName(getBrokerObjectName(), "jmsConnectors", connector.getName()); 2334 AnnotatedMBean.registerMBean(getManagementContext(), view, objectName); 2335 } catch (Throwable e) { 2336 throw IOExceptionSupport.create("Broker could not be registered in JMX: " + e.getMessage(), e); 2337 } 2338 } 2339 2340 /** 2341 * Factory method to create a new broker 2342 * 2343 * @throws Exception 2344 */ 2345 protected Broker createBroker() throws Exception { 2346 regionBroker = createRegionBroker(); 2347 Broker broker = addInterceptors(regionBroker); 2348 // Add a filter that will stop access to the broker once stopped 2349 broker = new MutableBrokerFilter(broker) { 2350 Broker old; 2351 2352 @Override 2353 public void stop() throws Exception { 2354 old = this.next.getAndSet(new ErrorBroker("Broker has been stopped: " + this) { 2355 // Just ignore additional stop actions. 2356 @Override 2357 public void stop() throws Exception { 2358 } 2359 }); 2360 old.stop(); 2361 } 2362 2363 @Override 2364 public void start() throws Exception { 2365 if (forceStart && old != null) { 2366 this.next.set(old); 2367 } 2368 getNext().start(); 2369 } 2370 }; 2371 return broker; 2372 } 2373 2374 /** 2375 * Factory method to create the core region broker onto which interceptors 2376 * are added 2377 * 2378 * @throws Exception 2379 */ 2380 protected Broker createRegionBroker() throws Exception { 2381 if (destinationInterceptors == null) { 2382 destinationInterceptors = createDefaultDestinationInterceptor(); 2383 } 2384 configureServices(destinationInterceptors); 2385 DestinationInterceptor destinationInterceptor = new CompositeDestinationInterceptor(destinationInterceptors); 2386 if (destinationFactory == null) { 2387 destinationFactory = new DestinationFactoryImpl(this, getTaskRunnerFactory(), getPersistenceAdapter()); 2388 } 2389 return createRegionBroker(destinationInterceptor); 2390 } 2391 2392 protected Broker createRegionBroker(DestinationInterceptor destinationInterceptor) throws IOException { 2393 RegionBroker regionBroker; 2394 if (isUseJmx()) { 2395 try { 2396 regionBroker = new ManagedRegionBroker(this, getManagementContext(), getBrokerObjectName(), 2397 getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory, destinationInterceptor,getScheduler(),getExecutor()); 2398 } catch(MalformedObjectNameException me){ 2399 LOG.warn("Cannot create ManagedRegionBroker due " + me.getMessage(), me); 2400 throw new IOException(me); 2401 } 2402 } else { 2403 regionBroker = new RegionBroker(this, getTaskRunnerFactory(), getConsumerSystemUsage(), destinationFactory, 2404 destinationInterceptor,getScheduler(),getExecutor()); 2405 } 2406 destinationFactory.setRegionBroker(regionBroker); 2407 regionBroker.setKeepDurableSubsActive(keepDurableSubsActive); 2408 regionBroker.setBrokerName(getBrokerName()); 2409 regionBroker.getDestinationStatistics().setEnabled(enableStatistics); 2410 regionBroker.setAllowTempAutoCreationOnSend(isAllowTempAutoCreationOnSend()); 2411 if (brokerId != null) { 2412 regionBroker.setBrokerId(brokerId); 2413 } 2414 return regionBroker; 2415 } 2416 2417 /** 2418 * Create the default destination interceptor 2419 */ 2420 protected DestinationInterceptor[] createDefaultDestinationInterceptor() { 2421 List<DestinationInterceptor> answer = new ArrayList<>(); 2422 if (isUseVirtualTopics()) { 2423 VirtualDestinationInterceptor interceptor = new VirtualDestinationInterceptor(); 2424 VirtualTopic virtualTopic = new VirtualTopic(); 2425 virtualTopic.setName("VirtualTopic.>"); 2426 VirtualDestination[] virtualDestinations = { virtualTopic }; 2427 interceptor.setVirtualDestinations(virtualDestinations); 2428 answer.add(interceptor); 2429 } 2430 if (isUseMirroredQueues()) { 2431 MirroredQueue interceptor = new MirroredQueue(); 2432 answer.add(interceptor); 2433 } 2434 DestinationInterceptor[] array = new DestinationInterceptor[answer.size()]; 2435 answer.toArray(array); 2436 return array; 2437 } 2438 2439 /** 2440 * Strategy method to add interceptors to the broker 2441 * 2442 * @throws IOException 2443 */ 2444 protected Broker addInterceptors(Broker broker) throws Exception { 2445 if (isSchedulerSupport()) { 2446 SchedulerBroker sb = new SchedulerBroker(this, broker, getJobSchedulerStore()); 2447 if (isUseJmx()) { 2448 JobSchedulerViewMBean view = new JobSchedulerView(sb.getJobScheduler()); 2449 try { 2450 ObjectName objectName = BrokerMBeanSupport.createJobSchedulerServiceName(getBrokerObjectName()); 2451 AnnotatedMBean.registerMBean(getManagementContext(), view, objectName); 2452 this.adminView.setJMSJobScheduler(objectName); 2453 } catch (Throwable e) { 2454 throw IOExceptionSupport.create("JobScheduler could not be registered in JMX: " 2455 + e.getMessage(), e); 2456 } 2457 } 2458 broker = sb; 2459 } 2460 if (isUseJmx()) { 2461 HealthViewMBean statusView = new HealthView((ManagedRegionBroker)getRegionBroker()); 2462 try { 2463 ObjectName objectName = BrokerMBeanSupport.createHealthServiceName(getBrokerObjectName()); 2464 AnnotatedMBean.registerMBean(getManagementContext(), statusView, objectName); 2465 } catch (Throwable e) { 2466 throw IOExceptionSupport.create("Status MBean could not be registered in JMX: " 2467 + e.getMessage(), e); 2468 } 2469 } 2470 if (isAdvisorySupport()) { 2471 broker = new AdvisoryBroker(broker); 2472 } 2473 broker = new CompositeDestinationBroker(broker); 2474 broker = new TransactionBroker(broker, getPersistenceAdapter().createTransactionStore()); 2475 if (isPopulateJMSXUserID()) { 2476 UserIDBroker userIDBroker = new UserIDBroker(broker); 2477 userIDBroker.setUseAuthenticatePrincipal(isUseAuthenticatedPrincipalForJMSXUserID()); 2478 broker = userIDBroker; 2479 } 2480 if (isMonitorConnectionSplits()) { 2481 broker = new ConnectionSplitBroker(broker); 2482 } 2483 if (plugins != null) { 2484 for (int i = 0; i < plugins.length; i++) { 2485 BrokerPlugin plugin = plugins[i]; 2486 broker = plugin.installPlugin(broker); 2487 } 2488 } 2489 return broker; 2490 } 2491 2492 protected PersistenceAdapter createPersistenceAdapter() throws IOException { 2493 if (isPersistent()) { 2494 PersistenceAdapterFactory fac = getPersistenceFactory(); 2495 if (fac != null) { 2496 return fac.createPersistenceAdapter(); 2497 } else { 2498 try { 2499 String clazz = "org.apache.activemq.store.kahadb.KahaDBPersistenceAdapter"; 2500 PersistenceAdapter adaptor = (PersistenceAdapter)getClass().getClassLoader().loadClass(clazz).newInstance(); 2501 File dir = new File(getBrokerDataDirectory(),"KahaDB"); 2502 adaptor.setDirectory(dir); 2503 return adaptor; 2504 } catch (Throwable e) { 2505 throw IOExceptionSupport.create(e); 2506 } 2507 } 2508 } else { 2509 return new MemoryPersistenceAdapter(); 2510 } 2511 } 2512 2513 protected ObjectName createBrokerObjectName() throws MalformedObjectNameException { 2514 return BrokerMBeanSupport.createBrokerObjectName(getManagementContext().getJmxDomainName(), getBrokerName()); 2515 } 2516 2517 protected TransportConnector createTransportConnector(URI brokerURI) throws Exception { 2518 TransportServer transport = TransportFactorySupport.bind(this, brokerURI); 2519 return new TransportConnector(transport); 2520 } 2521 2522 /** 2523 * Extracts the port from the options 2524 */ 2525 protected Object getPort(Map<?,?> options) { 2526 Object port = options.get("port"); 2527 if (port == null) { 2528 port = DEFAULT_PORT; 2529 LOG.warn("No port specified so defaulting to: {}", port); 2530 } 2531 return port; 2532 } 2533 2534 protected void addShutdownHook() { 2535 if (useShutdownHook) { 2536 shutdownHook = new Thread("ActiveMQ ShutdownHook") { 2537 @Override 2538 public void run() { 2539 containerShutdown(); 2540 } 2541 }; 2542 Runtime.getRuntime().addShutdownHook(shutdownHook); 2543 } 2544 } 2545 2546 protected void removeShutdownHook() { 2547 if (shutdownHook != null) { 2548 try { 2549 Runtime.getRuntime().removeShutdownHook(shutdownHook); 2550 } catch (Exception e) { 2551 LOG.debug("Caught exception, must be shutting down. This exception is ignored.", e); 2552 } 2553 } 2554 } 2555 2556 /** 2557 * Sets hooks to be executed when broker shut down 2558 * 2559 * @org.apache.xbean.Property 2560 */ 2561 public void setShutdownHooks(List<Runnable> hooks) throws Exception { 2562 for (Runnable hook : hooks) { 2563 addShutdownHook(hook); 2564 } 2565 } 2566 2567 /** 2568 * Causes a clean shutdown of the container when the VM is being shut down 2569 */ 2570 protected void containerShutdown() { 2571 try { 2572 stop(); 2573 } catch (IOException e) { 2574 Throwable linkedException = e.getCause(); 2575 if (linkedException != null) { 2576 logError("Failed to shut down: " + e + ". Reason: " + linkedException, linkedException); 2577 } else { 2578 logError("Failed to shut down: " + e, e); 2579 } 2580 if (!useLoggingForShutdownErrors) { 2581 e.printStackTrace(System.err); 2582 } 2583 } catch (Exception e) { 2584 logError("Failed to shut down: " + e, e); 2585 } 2586 } 2587 2588 protected void logError(String message, Throwable e) { 2589 if (useLoggingForShutdownErrors) { 2590 LOG.error("Failed to shut down: " + e); 2591 } else { 2592 System.err.println("Failed to shut down: " + e); 2593 } 2594 } 2595 2596 /** 2597 * Starts any configured destinations on startup 2598 */ 2599 protected void startDestinations() throws Exception { 2600 if (destinations != null) { 2601 ConnectionContext adminConnectionContext = getAdminConnectionContext(); 2602 for (int i = 0; i < destinations.length; i++) { 2603 ActiveMQDestination destination = destinations[i]; 2604 getBroker().addDestination(adminConnectionContext, destination,true); 2605 } 2606 } 2607 if (isUseVirtualTopics()) { 2608 startVirtualConsumerDestinations(); 2609 } 2610 } 2611 2612 /** 2613 * Returns the broker's administration connection context used for 2614 * configuring the broker at startup 2615 */ 2616 public ConnectionContext getAdminConnectionContext() throws Exception { 2617 return BrokerSupport.getConnectionContext(getBroker()); 2618 } 2619 2620 protected void startManagementContext() throws Exception { 2621 getManagementContext().setBrokerName(brokerName); 2622 getManagementContext().start(); 2623 adminView = new BrokerView(this, null); 2624 ObjectName objectName = getBrokerObjectName(); 2625 AnnotatedMBean.registerMBean(getManagementContext(), adminView, objectName); 2626 } 2627 2628 /** 2629 * Start all transport and network connections, proxies and bridges 2630 * 2631 * @throws Exception 2632 */ 2633 public void startAllConnectors() throws Exception { 2634 final Set<ActiveMQDestination> durableDestinations = getBroker().getDurableDestinations(); 2635 List<TransportConnector> al = new ArrayList<>(); 2636 for (Iterator<TransportConnector> iter = getTransportConnectors().iterator(); iter.hasNext();) { 2637 TransportConnector connector = iter.next(); 2638 al.add(startTransportConnector(connector)); 2639 } 2640 if (al.size() > 0) { 2641 // let's clear the transportConnectors list and replace it with 2642 // the started transportConnector instances 2643 this.transportConnectors.clear(); 2644 setTransportConnectors(al); 2645 } 2646 this.slave = false; 2647 if (!stopped.get()) { 2648 ThreadPoolExecutor networkConnectorStartExecutor = null; 2649 if (isNetworkConnectorStartAsync()) { 2650 // spin up as many threads as needed 2651 networkConnectorStartExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 2652 10, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), 2653 new ThreadFactory() { 2654 int count=0; 2655 @Override 2656 public Thread newThread(Runnable runnable) { 2657 Thread thread = new Thread(runnable, "NetworkConnector Start Thread-" +(count++)); 2658 thread.setDaemon(true); 2659 return thread; 2660 } 2661 }); 2662 } 2663 2664 for (Iterator<NetworkConnector> iter = getNetworkConnectors().iterator(); iter.hasNext();) { 2665 final NetworkConnector connector = iter.next(); 2666 connector.setLocalUri(getVmConnectorURI()); 2667 startNetworkConnector(connector, durableDestinations, networkConnectorStartExecutor); 2668 } 2669 if (networkConnectorStartExecutor != null) { 2670 // executor done when enqueued tasks are complete 2671 ThreadPoolUtils.shutdown(networkConnectorStartExecutor); 2672 } 2673 2674 for (Iterator<ProxyConnector> iter = getProxyConnectors().iterator(); iter.hasNext();) { 2675 ProxyConnector connector = iter.next(); 2676 connector.start(); 2677 } 2678 for (Iterator<JmsConnector> iter = jmsConnectors.iterator(); iter.hasNext();) { 2679 JmsConnector connector = iter.next(); 2680 connector.start(); 2681 } 2682 for (Service service : services) { 2683 configureService(service); 2684 service.start(); 2685 } 2686 } 2687 } 2688 2689 public void startNetworkConnector(final NetworkConnector connector, 2690 final ThreadPoolExecutor networkConnectorStartExecutor) throws Exception { 2691 startNetworkConnector(connector, getBroker().getDurableDestinations(), networkConnectorStartExecutor); 2692 } 2693 2694 public void startNetworkConnector(final NetworkConnector connector, 2695 final Set<ActiveMQDestination> durableDestinations, 2696 final ThreadPoolExecutor networkConnectorStartExecutor) throws Exception { 2697 connector.setBrokerName(getBrokerName()); 2698 //set the durable destinations to match the broker if not set on the connector 2699 if (connector.getDurableDestinations() == null) { 2700 connector.setDurableDestinations(durableDestinations); 2701 } 2702 String defaultSocketURI = getDefaultSocketURIString(); 2703 if (defaultSocketURI != null) { 2704 connector.setBrokerURL(defaultSocketURI); 2705 } 2706 //If using the runtime plugin to start a network connector then the mbean needs 2707 //to be added, under normal start it will already exist so check for InstanceNotFoundException 2708 if (isUseJmx()) { 2709 ObjectName networkMbean = createNetworkConnectorObjectName(connector); 2710 try { 2711 getManagementContext().getObjectInstance(networkMbean); 2712 } catch (InstanceNotFoundException e) { 2713 LOG.debug("Network connector MBean {} not found, registering", networkMbean); 2714 registerNetworkConnectorMBean(connector); 2715 } 2716 } 2717 if (networkConnectorStartExecutor != null) { 2718 networkConnectorStartExecutor.execute(new Runnable() { 2719 @Override 2720 public void run() { 2721 try { 2722 LOG.info("Async start of {}", connector); 2723 connector.start(); 2724 } catch(Exception e) { 2725 LOG.error("Async start of network connector: {} failed", connector, e); 2726 } 2727 } 2728 }); 2729 } else { 2730 connector.start(); 2731 } 2732 } 2733 2734 public TransportConnector startTransportConnector(TransportConnector connector) throws Exception { 2735 connector.setBrokerService(this); 2736 connector.setTaskRunnerFactory(getTaskRunnerFactory()); 2737 MessageAuthorizationPolicy policy = getMessageAuthorizationPolicy(); 2738 if (policy != null) { 2739 connector.setMessageAuthorizationPolicy(policy); 2740 } 2741 if (isUseJmx()) { 2742 connector = registerConnectorMBean(connector); 2743 } 2744 connector.getStatistics().setEnabled(enableStatistics); 2745 connector.start(); 2746 return connector; 2747 } 2748 2749 /** 2750 * Perform any custom dependency injection 2751 */ 2752 protected void configureServices(Object[] services) { 2753 for (Object service : services) { 2754 configureService(service); 2755 } 2756 } 2757 2758 /** 2759 * Perform any custom dependency injection 2760 */ 2761 protected void configureService(Object service) { 2762 if (service instanceof BrokerServiceAware) { 2763 BrokerServiceAware serviceAware = (BrokerServiceAware) service; 2764 serviceAware.setBrokerService(this); 2765 } 2766 } 2767 2768 public void handleIOException(IOException exception) { 2769 if (ioExceptionHandler != null) { 2770 ioExceptionHandler.handle(exception); 2771 } else { 2772 LOG.info("No IOExceptionHandler registered, ignoring IO exception", exception); 2773 } 2774 } 2775 2776 protected void startVirtualConsumerDestinations() throws Exception { 2777 checkStartException(); 2778 ConnectionContext adminConnectionContext = getAdminConnectionContext(); 2779 Set<ActiveMQDestination> destinations = destinationFactory.getDestinations(); 2780 DestinationFilter filter = getVirtualTopicConsumerDestinationFilter(); 2781 if (!destinations.isEmpty()) { 2782 for (ActiveMQDestination destination : destinations) { 2783 if (filter.matches(destination) == true) { 2784 broker.addDestination(adminConnectionContext, destination, false); 2785 } 2786 } 2787 } 2788 } 2789 2790 private DestinationFilter getVirtualTopicConsumerDestinationFilter() { 2791 // created at startup, so no sync needed 2792 if (virtualConsumerDestinationFilter == null) { 2793 Set <ActiveMQQueue> consumerDestinations = new HashSet<>(); 2794 if (destinationInterceptors != null) { 2795 for (DestinationInterceptor interceptor : destinationInterceptors) { 2796 if (interceptor instanceof VirtualDestinationInterceptor) { 2797 VirtualDestinationInterceptor virtualDestinationInterceptor = (VirtualDestinationInterceptor) interceptor; 2798 for (VirtualDestination virtualDestination: virtualDestinationInterceptor.getVirtualDestinations()) { 2799 if (virtualDestination instanceof VirtualTopic) { 2800 consumerDestinations.add(new ActiveMQQueue(((VirtualTopic) virtualDestination).getPrefix() + DestinationFilter.ANY_DESCENDENT)); 2801 } 2802 if (isUseVirtualDestSubs()) { 2803 try { 2804 broker.virtualDestinationAdded(getAdminConnectionContext(), virtualDestination); 2805 LOG.debug("Adding virtual destination: {}", virtualDestination); 2806 } catch (Exception e) { 2807 LOG.warn("Could not fire virtual destination consumer advisory", e); 2808 } 2809 } 2810 } 2811 } 2812 } 2813 } 2814 ActiveMQQueue filter = new ActiveMQQueue(); 2815 filter.setCompositeDestinations(consumerDestinations.toArray(new ActiveMQDestination[]{})); 2816 virtualConsumerDestinationFilter = DestinationFilter.parseFilter(filter); 2817 } 2818 return virtualConsumerDestinationFilter; 2819 } 2820 2821 protected synchronized ThreadPoolExecutor getExecutor() { 2822 if (this.executor == null) { 2823 this.executor = new ThreadPoolExecutor(1, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() { 2824 2825 private long i = 0; 2826 2827 @Override 2828 public Thread newThread(Runnable runnable) { 2829 this.i++; 2830 Thread thread = new Thread(runnable, "ActiveMQ BrokerService.worker." + this.i); 2831 thread.setDaemon(true); 2832 thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 2833 @Override 2834 public void uncaughtException(final Thread t, final Throwable e) { 2835 LOG.error("Error in thread '{}'", t.getName(), e); 2836 } 2837 }); 2838 return thread; 2839 } 2840 }, new RejectedExecutionHandler() { 2841 @Override 2842 public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) { 2843 try { 2844 executor.getQueue().offer(r, 60, TimeUnit.SECONDS); 2845 } catch (InterruptedException e) { 2846 throw new RejectedExecutionException("Interrupted waiting for BrokerService.worker"); 2847 } 2848 2849 throw new RejectedExecutionException("Timed Out while attempting to enqueue Task."); 2850 } 2851 }); 2852 } 2853 return this.executor; 2854 } 2855 2856 public synchronized Scheduler getScheduler() { 2857 if (this.scheduler==null) { 2858 this.scheduler = new Scheduler("ActiveMQ Broker["+getBrokerName()+"] Scheduler"); 2859 try { 2860 this.scheduler.start(); 2861 } catch (Exception e) { 2862 LOG.error("Failed to start Scheduler", e); 2863 } 2864 } 2865 return this.scheduler; 2866 } 2867 2868 public Broker getRegionBroker() { 2869 return regionBroker; 2870 } 2871 2872 public void setRegionBroker(Broker regionBroker) { 2873 this.regionBroker = regionBroker; 2874 } 2875 2876 public final void removePreShutdownHook(final Runnable hook) { 2877 preShutdownHooks.remove(hook); 2878 } 2879 2880 public void addShutdownHook(Runnable hook) { 2881 synchronized (shutdownHooks) { 2882 shutdownHooks.add(hook); 2883 } 2884 } 2885 2886 public void removeShutdownHook(Runnable hook) { 2887 synchronized (shutdownHooks) { 2888 shutdownHooks.remove(hook); 2889 } 2890 } 2891 2892 public boolean isSystemExitOnShutdown() { 2893 return systemExitOnShutdown; 2894 } 2895 2896 /** 2897 * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor" 2898 */ 2899 public void setSystemExitOnShutdown(boolean systemExitOnShutdown) { 2900 this.systemExitOnShutdown = systemExitOnShutdown; 2901 } 2902 2903 public int getSystemExitOnShutdownExitCode() { 2904 return systemExitOnShutdownExitCode; 2905 } 2906 2907 public void setSystemExitOnShutdownExitCode(int systemExitOnShutdownExitCode) { 2908 this.systemExitOnShutdownExitCode = systemExitOnShutdownExitCode; 2909 } 2910 2911 public SslContext getSslContext() { 2912 return sslContext; 2913 } 2914 2915 public void setSslContext(SslContext sslContext) { 2916 this.sslContext = sslContext; 2917 } 2918 2919 public boolean isShutdownOnSlaveFailure() { 2920 return shutdownOnSlaveFailure; 2921 } 2922 2923 /** 2924 * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor" 2925 */ 2926 public void setShutdownOnSlaveFailure(boolean shutdownOnSlaveFailure) { 2927 this.shutdownOnSlaveFailure = shutdownOnSlaveFailure; 2928 } 2929 2930 public boolean isWaitForSlave() { 2931 return waitForSlave; 2932 } 2933 2934 /** 2935 * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor" 2936 */ 2937 public void setWaitForSlave(boolean waitForSlave) { 2938 this.waitForSlave = waitForSlave; 2939 } 2940 2941 public long getWaitForSlaveTimeout() { 2942 return this.waitForSlaveTimeout; 2943 } 2944 2945 public void setWaitForSlaveTimeout(long waitForSlaveTimeout) { 2946 this.waitForSlaveTimeout = waitForSlaveTimeout; 2947 } 2948 2949 /** 2950 * Get the passiveSlave 2951 * @return the passiveSlave 2952 */ 2953 public boolean isPassiveSlave() { 2954 return this.passiveSlave; 2955 } 2956 2957 /** 2958 * Set the passiveSlave 2959 * @param passiveSlave the passiveSlave to set 2960 * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor" 2961 */ 2962 public void setPassiveSlave(boolean passiveSlave) { 2963 this.passiveSlave = passiveSlave; 2964 } 2965 2966 /** 2967 * override the Default IOException handler, called when persistence adapter 2968 * has experiences File or JDBC I/O Exceptions 2969 * 2970 * @param ioExceptionHandler 2971 */ 2972 public void setIoExceptionHandler(IOExceptionHandler ioExceptionHandler) { 2973 configureService(ioExceptionHandler); 2974 this.ioExceptionHandler = ioExceptionHandler; 2975 } 2976 2977 public IOExceptionHandler getIoExceptionHandler() { 2978 return ioExceptionHandler; 2979 } 2980 2981 /** 2982 * @return the schedulerSupport 2983 */ 2984 public boolean isSchedulerSupport() { 2985 return this.schedulerSupport; 2986 } 2987 2988 /** 2989 * @param schedulerSupport the schedulerSupport to set 2990 * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.BooleanEditor" 2991 */ 2992 public void setSchedulerSupport(boolean schedulerSupport) { 2993 this.schedulerSupport = schedulerSupport; 2994 } 2995 2996 /** 2997 * @return the schedulerDirectory 2998 */ 2999 public File getSchedulerDirectoryFile() { 3000 if (this.schedulerDirectoryFile == null) { 3001 this.schedulerDirectoryFile = new File(getBrokerDataDirectory(), "scheduler"); 3002 } 3003 return schedulerDirectoryFile; 3004 } 3005 3006 /** 3007 * @param schedulerDirectory the schedulerDirectory to set 3008 */ 3009 public void setSchedulerDirectoryFile(File schedulerDirectory) { 3010 this.schedulerDirectoryFile = schedulerDirectory; 3011 } 3012 3013 public void setSchedulerDirectory(String schedulerDirectory) { 3014 setSchedulerDirectoryFile(new File(schedulerDirectory)); 3015 } 3016 3017 public int getSchedulePeriodForDestinationPurge() { 3018 return this.schedulePeriodForDestinationPurge; 3019 } 3020 3021 public void setSchedulePeriodForDestinationPurge(int schedulePeriodForDestinationPurge) { 3022 this.schedulePeriodForDestinationPurge = schedulePeriodForDestinationPurge; 3023 } 3024 3025 /** 3026 * @param schedulePeriodForDiskUsageCheck 3027 */ 3028 public void setSchedulePeriodForDiskUsageCheck( 3029 int schedulePeriodForDiskUsageCheck) { 3030 this.schedulePeriodForDiskUsageCheck = schedulePeriodForDiskUsageCheck; 3031 } 3032 3033 public int getDiskUsageCheckRegrowThreshold() { 3034 return diskUsageCheckRegrowThreshold; 3035 } 3036 3037 /** 3038 * @param diskUsageCheckRegrowThreshold 3039 * @org.apache.xbean.Property propertyEditor="org.apache.activemq.util.MemoryPropertyEditor" 3040 */ 3041 public void setDiskUsageCheckRegrowThreshold(int diskUsageCheckRegrowThreshold) { 3042 this.diskUsageCheckRegrowThreshold = diskUsageCheckRegrowThreshold; 3043 } 3044 3045 public int getMaxPurgedDestinationsPerSweep() { 3046 return this.maxPurgedDestinationsPerSweep; 3047 } 3048 3049 public void setMaxPurgedDestinationsPerSweep(int maxPurgedDestinationsPerSweep) { 3050 this.maxPurgedDestinationsPerSweep = maxPurgedDestinationsPerSweep; 3051 } 3052 3053 public BrokerContext getBrokerContext() { 3054 return brokerContext; 3055 } 3056 3057 public void setBrokerContext(BrokerContext brokerContext) { 3058 this.brokerContext = brokerContext; 3059 } 3060 3061 public void setBrokerId(String brokerId) { 3062 this.brokerId = new BrokerId(brokerId); 3063 } 3064 3065 public boolean isUseAuthenticatedPrincipalForJMSXUserID() { 3066 return useAuthenticatedPrincipalForJMSXUserID; 3067 } 3068 3069 public void setUseAuthenticatedPrincipalForJMSXUserID(boolean useAuthenticatedPrincipalForJMSXUserID) { 3070 this.useAuthenticatedPrincipalForJMSXUserID = useAuthenticatedPrincipalForJMSXUserID; 3071 } 3072 3073 /** 3074 * Should MBeans that support showing the Authenticated User Name information have this 3075 * value filled in or not. 3076 * 3077 * @return true if user names should be exposed in MBeans 3078 */ 3079 public boolean isPopulateUserNameInMBeans() { 3080 return this.populateUserNameInMBeans; 3081 } 3082 3083 /** 3084 * Sets whether Authenticated User Name information is shown in MBeans that support this field. 3085 * @param value if MBeans should expose user name information. 3086 */ 3087 public void setPopulateUserNameInMBeans(boolean value) { 3088 this.populateUserNameInMBeans = value; 3089 } 3090 3091 /** 3092 * Gets the time in Milliseconds that an invocation of an MBean method will wait before 3093 * failing. The default value is to wait forever (zero). 3094 * 3095 * @return timeout in milliseconds before MBean calls fail, (default is 0 or no timeout). 3096 */ 3097 public long getMbeanInvocationTimeout() { 3098 return mbeanInvocationTimeout; 3099 } 3100 3101 /** 3102 * Gets the time in Milliseconds that an invocation of an MBean method will wait before 3103 * failing. The default value is to wait forever (zero). 3104 * 3105 * @param mbeanInvocationTimeout 3106 * timeout in milliseconds before MBean calls fail, (default is 0 or no timeout). 3107 */ 3108 public void setMbeanInvocationTimeout(long mbeanInvocationTimeout) { 3109 this.mbeanInvocationTimeout = mbeanInvocationTimeout; 3110 } 3111 3112 public boolean isNetworkConnectorStartAsync() { 3113 return networkConnectorStartAsync; 3114 } 3115 3116 public void setNetworkConnectorStartAsync(boolean networkConnectorStartAsync) { 3117 this.networkConnectorStartAsync = networkConnectorStartAsync; 3118 } 3119 3120 public boolean isAllowTempAutoCreationOnSend() { 3121 return allowTempAutoCreationOnSend; 3122 } 3123 3124 /** 3125 * enable if temp destinations need to be propagated through a network when 3126 * advisorySupport==false. This is used in conjunction with the policy 3127 * gcInactiveDestinations for matching temps so they can get removed 3128 * when inactive 3129 * 3130 * @param allowTempAutoCreationOnSend 3131 */ 3132 public void setAllowTempAutoCreationOnSend(boolean allowTempAutoCreationOnSend) { 3133 this.allowTempAutoCreationOnSend = allowTempAutoCreationOnSend; 3134 } 3135 3136 public long getOfflineDurableSubscriberTimeout() { 3137 return offlineDurableSubscriberTimeout; 3138 } 3139 3140 public void setOfflineDurableSubscriberTimeout(long offlineDurableSubscriberTimeout) { 3141 this.offlineDurableSubscriberTimeout = offlineDurableSubscriberTimeout; 3142 } 3143 3144 public long getOfflineDurableSubscriberTaskSchedule() { 3145 return offlineDurableSubscriberTaskSchedule; 3146 } 3147 3148 public void setOfflineDurableSubscriberTaskSchedule(long offlineDurableSubscriberTaskSchedule) { 3149 this.offlineDurableSubscriberTaskSchedule = offlineDurableSubscriberTaskSchedule; 3150 } 3151 3152 public boolean shouldRecordVirtualDestination(ActiveMQDestination destination) { 3153 return isUseVirtualTopics() && destination.isQueue() && 3154 getVirtualTopicConsumerDestinationFilter().matches(destination); 3155 } 3156 3157 synchronized public Throwable getStartException() { 3158 return startException; 3159 } 3160 3161 public boolean isStartAsync() { 3162 return startAsync; 3163 } 3164 3165 public void setStartAsync(boolean startAsync) { 3166 this.startAsync = startAsync; 3167 } 3168 3169 public boolean isSlave() { 3170 return this.slave; 3171 } 3172 3173 public boolean isStopping() { 3174 return this.stopping.get(); 3175 } 3176 3177 /** 3178 * @return true if the broker allowed to restart on shutdown. 3179 */ 3180 public boolean isRestartAllowed() { 3181 return restartAllowed; 3182 } 3183 3184 /** 3185 * Sets if the broker allowed to restart on shutdown. 3186 */ 3187 public void setRestartAllowed(boolean restartAllowed) { 3188 this.restartAllowed = restartAllowed; 3189 } 3190 3191 /** 3192 * A lifecycle manager of the BrokerService should 3193 * inspect this property after a broker shutdown has occurred 3194 * to find out if the broker needs to be re-created and started 3195 * again. 3196 * 3197 * @return true if the broker wants to be restarted after it shuts down. 3198 */ 3199 public boolean isRestartRequested() { 3200 return restartRequested; 3201 } 3202 3203 public void requestRestart() { 3204 this.restartRequested = true; 3205 } 3206 3207 public int getStoreOpenWireVersion() { 3208 return storeOpenWireVersion; 3209 } 3210 3211 public void setStoreOpenWireVersion(int storeOpenWireVersion) { 3212 this.storeOpenWireVersion = storeOpenWireVersion; 3213 } 3214 3215 /** 3216 * @return the current number of connections on this Broker. 3217 */ 3218 public int getCurrentConnections() { 3219 return this.currentConnections.get(); 3220 } 3221 3222 /** 3223 * @return the total number of connections this broker has handled since startup. 3224 */ 3225 public long getTotalConnections() { 3226 return this.totalConnections.get(); 3227 } 3228 3229 public void incrementCurrentConnections() { 3230 this.currentConnections.incrementAndGet(); 3231 } 3232 3233 public void decrementCurrentConnections() { 3234 this.currentConnections.decrementAndGet(); 3235 } 3236 3237 public void incrementTotalConnections() { 3238 this.totalConnections.incrementAndGet(); 3239 } 3240 3241 public boolean isRejectDurableConsumers() { 3242 return rejectDurableConsumers; 3243 } 3244 3245 public void setRejectDurableConsumers(boolean rejectDurableConsumers) { 3246 this.rejectDurableConsumers = rejectDurableConsumers; 3247 } 3248 3249 public boolean isUseVirtualDestSubs() { 3250 return useVirtualDestSubs; 3251 } 3252 3253 public void setUseVirtualDestSubs( 3254 boolean useVirtualDestSubs) { 3255 this.useVirtualDestSubs = useVirtualDestSubs; 3256 } 3257 3258 public boolean isUseVirtualDestSubsOnCreation() { 3259 return useVirtualDestSubsOnCreation; 3260 } 3261 3262 public void setUseVirtualDestSubsOnCreation( 3263 boolean useVirtualDestSubsOnCreation) { 3264 this.useVirtualDestSubsOnCreation = useVirtualDestSubsOnCreation; 3265 } 3266 3267 public boolean isAdjustUsageLimits() { 3268 return adjustUsageLimits; 3269 } 3270 3271 public void setAdjustUsageLimits(boolean adjustUsageLimits) { 3272 this.adjustUsageLimits = adjustUsageLimits; 3273 } 3274 3275 public void setRollbackOnlyOnAsyncException(boolean rollbackOnlyOnAsyncException) { 3276 this.rollbackOnlyOnAsyncException = rollbackOnlyOnAsyncException; 3277 } 3278 3279 public boolean isRollbackOnlyOnAsyncException() { 3280 return rollbackOnlyOnAsyncException; 3281 } 3282}