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