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.camel.management; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.HashMap; 022import java.util.HashSet; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027import java.util.concurrent.ThreadPoolExecutor; 028import javax.management.JMException; 029import javax.management.MalformedObjectNameException; 030import javax.management.ObjectName; 031 032import org.apache.camel.CamelContext; 033import org.apache.camel.CamelContextAware; 034import org.apache.camel.Channel; 035import org.apache.camel.Component; 036import org.apache.camel.Consumer; 037import org.apache.camel.Endpoint; 038import org.apache.camel.ErrorHandlerFactory; 039import org.apache.camel.ManagementStatisticsLevel; 040import org.apache.camel.NonManagedService; 041import org.apache.camel.Processor; 042import org.apache.camel.Producer; 043import org.apache.camel.Route; 044import org.apache.camel.Service; 045import org.apache.camel.StartupListener; 046import org.apache.camel.TimerListener; 047import org.apache.camel.VetoCamelContextStartException; 048import org.apache.camel.api.management.PerformanceCounter; 049import org.apache.camel.impl.ConsumerCache; 050import org.apache.camel.impl.DefaultCamelContext; 051import org.apache.camel.impl.DefaultEndpointRegistry; 052import org.apache.camel.impl.EventDrivenConsumerRoute; 053import org.apache.camel.impl.ProducerCache; 054import org.apache.camel.impl.ThrottlingExceptionRoutePolicy; 055import org.apache.camel.impl.ThrottlingInflightRoutePolicy; 056import org.apache.camel.management.mbean.ManagedAsyncProcessorAwaitManager; 057import org.apache.camel.management.mbean.ManagedBacklogDebugger; 058import org.apache.camel.management.mbean.ManagedBacklogTracer; 059import org.apache.camel.management.mbean.ManagedCamelContext; 060import org.apache.camel.management.mbean.ManagedConsumerCache; 061import org.apache.camel.management.mbean.ManagedEndpoint; 062import org.apache.camel.management.mbean.ManagedEndpointRegistry; 063import org.apache.camel.management.mbean.ManagedInflightRepository; 064import org.apache.camel.management.mbean.ManagedProducerCache; 065import org.apache.camel.management.mbean.ManagedRestRegistry; 066import org.apache.camel.management.mbean.ManagedRoute; 067import org.apache.camel.management.mbean.ManagedRuntimeCamelCatalog; 068import org.apache.camel.management.mbean.ManagedRuntimeEndpointRegistry; 069import org.apache.camel.management.mbean.ManagedService; 070import org.apache.camel.management.mbean.ManagedStreamCachingStrategy; 071import org.apache.camel.management.mbean.ManagedThrottlingExceptionRoutePolicy; 072import org.apache.camel.management.mbean.ManagedThrottlingInflightRoutePolicy; 073import org.apache.camel.management.mbean.ManagedTracer; 074import org.apache.camel.management.mbean.ManagedTransformerRegistry; 075import org.apache.camel.management.mbean.ManagedTypeConverterRegistry; 076import org.apache.camel.management.mbean.ManagedValidatorRegistry; 077import org.apache.camel.model.AOPDefinition; 078import org.apache.camel.model.InterceptDefinition; 079import org.apache.camel.model.OnCompletionDefinition; 080import org.apache.camel.model.OnExceptionDefinition; 081import org.apache.camel.model.PolicyDefinition; 082import org.apache.camel.model.ProcessorDefinition; 083import org.apache.camel.model.ProcessorDefinitionHelper; 084import org.apache.camel.model.RouteDefinition; 085import org.apache.camel.processor.CamelInternalProcessor; 086import org.apache.camel.processor.interceptor.BacklogDebugger; 087import org.apache.camel.processor.interceptor.BacklogTracer; 088import org.apache.camel.processor.interceptor.Tracer; 089import org.apache.camel.runtimecatalog.RuntimeCamelCatalog; 090import org.apache.camel.spi.AsyncProcessorAwaitManager; 091import org.apache.camel.spi.DataFormat; 092import org.apache.camel.spi.EventNotifier; 093import org.apache.camel.spi.InflightRepository; 094import org.apache.camel.spi.LifecycleStrategy; 095import org.apache.camel.spi.ManagementAgent; 096import org.apache.camel.spi.ManagementAware; 097import org.apache.camel.spi.ManagementNameStrategy; 098import org.apache.camel.spi.ManagementObjectStrategy; 099import org.apache.camel.spi.ManagementStrategy; 100import org.apache.camel.spi.RestRegistry; 101import org.apache.camel.spi.RouteContext; 102import org.apache.camel.spi.RuntimeEndpointRegistry; 103import org.apache.camel.spi.StreamCachingStrategy; 104import org.apache.camel.spi.TransformerRegistry; 105import org.apache.camel.spi.TypeConverterRegistry; 106import org.apache.camel.spi.UnitOfWork; 107import org.apache.camel.spi.ValidatorRegistry; 108import org.apache.camel.support.ServiceSupport; 109import org.apache.camel.support.TimerListenerManager; 110import org.apache.camel.util.KeyValueHolder; 111import org.apache.camel.util.ObjectHelper; 112import org.slf4j.Logger; 113import org.slf4j.LoggerFactory; 114 115/** 116 * Default JMX managed lifecycle strategy that registered objects using the configured 117 * {@link org.apache.camel.spi.ManagementStrategy}. 118 * 119 * @see org.apache.camel.spi.ManagementStrategy 120 * @version 121 */ 122@SuppressWarnings("deprecation") 123public class DefaultManagementLifecycleStrategy extends ServiceSupport implements LifecycleStrategy, CamelContextAware { 124 125 private static final Logger LOG = LoggerFactory.getLogger(DefaultManagementLifecycleStrategy.class); 126 // the wrapped processors is for performance counters, which are in use for the created routes 127 // when a route is removed, we should remove the associated processors from this map 128 private final Map<Processor, KeyValueHolder<ProcessorDefinition<?>, InstrumentationProcessor>> wrappedProcessors = 129 new HashMap<Processor, KeyValueHolder<ProcessorDefinition<?>, InstrumentationProcessor>>(); 130 private final List<PreRegisterService> preServices = new ArrayList<PreRegisterService>(); 131 private final TimerListenerManager loadTimer = new ManagedLoadTimer(); 132 private final TimerListenerManagerStartupListener loadTimerStartupListener = new TimerListenerManagerStartupListener(); 133 private volatile CamelContext camelContext; 134 private volatile ManagedCamelContext camelContextMBean; 135 private volatile boolean initialized; 136 private final Set<String> knowRouteIds = new HashSet<String>(); 137 private final Map<Tracer, ManagedTracer> managedTracers = new HashMap<Tracer, ManagedTracer>(); 138 private final Map<BacklogTracer, ManagedBacklogTracer> managedBacklogTracers = new HashMap<BacklogTracer, ManagedBacklogTracer>(); 139 private final Map<BacklogDebugger, ManagedBacklogDebugger> managedBacklogDebuggers = new HashMap<BacklogDebugger, ManagedBacklogDebugger>(); 140 private final Map<ThreadPoolExecutor, Object> managedThreadPools = new HashMap<ThreadPoolExecutor, Object>(); 141 142 public DefaultManagementLifecycleStrategy() { 143 } 144 145 public DefaultManagementLifecycleStrategy(CamelContext camelContext) { 146 this.camelContext = camelContext; 147 } 148 149 public CamelContext getCamelContext() { 150 return camelContext; 151 } 152 153 public void setCamelContext(CamelContext camelContext) { 154 this.camelContext = camelContext; 155 } 156 157 public void onContextStart(CamelContext context) throws VetoCamelContextStartException { 158 Object mc = getManagementObjectStrategy().getManagedObjectForCamelContext(context); 159 160 String name = context.getName(); 161 String managementName = context.getManagementNameStrategy().getName(); 162 163 try { 164 boolean done = false; 165 while (!done) { 166 ObjectName on = getManagementStrategy().getManagementNamingStrategy().getObjectNameForCamelContext(managementName, name); 167 boolean exists = getManagementStrategy().isManaged(mc, on); 168 if (!exists) { 169 done = true; 170 } else { 171 // okay there exists already a CamelContext with this name, we can try to fix it by finding a free name 172 boolean fixed = false; 173 // if we use the default name strategy we can find a free name to use 174 String newName = findFreeName(mc, context.getManagementNameStrategy(), name); 175 if (newName != null) { 176 // use this as the fixed name 177 fixed = true; 178 done = true; 179 managementName = newName; 180 } 181 // we could not fix it so veto starting camel 182 if (!fixed) { 183 throw new VetoCamelContextStartException("CamelContext (" + context.getName() + ") with ObjectName[" + on + "] is already registered." 184 + " Make sure to use unique names on CamelContext when using multiple CamelContexts in the same MBeanServer.", context); 185 } else { 186 LOG.warn("This CamelContext(" + context.getName() + ") will be registered using the name: " + managementName 187 + " due to clash with an existing name already registered in MBeanServer."); 188 } 189 } 190 } 191 } catch (VetoCamelContextStartException e) { 192 // rethrow veto 193 throw e; 194 } catch (Exception e) { 195 // must rethrow to allow CamelContext fallback to non JMX agent to allow 196 // Camel to continue to run 197 throw ObjectHelper.wrapRuntimeCamelException(e); 198 } 199 200 // set the name we are going to use 201 if (context instanceof DefaultCamelContext) { 202 ((DefaultCamelContext) context).setManagementName(managementName); 203 } 204 205 try { 206 manageObject(mc); 207 } catch (Exception e) { 208 // must rethrow to allow CamelContext fallback to non JMX agent to allow 209 // Camel to continue to run 210 throw ObjectHelper.wrapRuntimeCamelException(e); 211 } 212 213 // yes we made it and are initialized 214 initialized = true; 215 216 if (mc instanceof ManagedCamelContext) { 217 camelContextMBean = (ManagedCamelContext) mc; 218 } 219 220 // register any pre registered now that we are initialized 221 enlistPreRegisteredServices(); 222 } 223 224 private String findFreeName(Object mc, ManagementNameStrategy strategy, String name) throws MalformedObjectNameException { 225 // we cannot find a free name for fixed named strategies 226 if (strategy.isFixedName()) { 227 return null; 228 } 229 230 // okay try to find a free name 231 boolean done = false; 232 String newName = null; 233 while (!done) { 234 // compute the next name 235 newName = strategy.getNextName(); 236 ObjectName on = getManagementStrategy().getManagementNamingStrategy().getObjectNameForCamelContext(newName, name); 237 done = !getManagementStrategy().isManaged(mc, on); 238 if (LOG.isTraceEnabled()) { 239 LOG.trace("Using name: {} in ObjectName[{}] exists? {}", new Object[]{name, on, done}); 240 } 241 } 242 return newName; 243 } 244 245 /** 246 * After {@link CamelContext} has been enlisted in JMX using {@link #onContextStart(org.apache.camel.CamelContext)} 247 * then we can enlist any pre registered services as well, as we had to wait for {@link CamelContext} to be 248 * enlisted first. 249 * <p/> 250 * A component/endpoint/service etc. can be pre registered when using dependency injection and annotations such as 251 * {@link org.apache.camel.Produce}, {@link org.apache.camel.EndpointInject}. Therefore we need to capture those 252 * registrations up front, and then afterwards enlist in JMX when {@link CamelContext} is being started. 253 */ 254 private void enlistPreRegisteredServices() { 255 if (preServices.isEmpty()) { 256 return; 257 } 258 259 LOG.debug("Registering {} pre registered services", preServices.size()); 260 for (PreRegisterService pre : preServices) { 261 if (pre.getComponent() != null) { 262 onComponentAdd(pre.getName(), pre.getComponent()); 263 } else if (pre.getEndpoint() != null) { 264 onEndpointAdd(pre.getEndpoint()); 265 } else if (pre.getService() != null) { 266 onServiceAdd(pre.getCamelContext(), pre.getService(), pre.getRoute()); 267 } 268 } 269 270 // we are done so clear the list 271 preServices.clear(); 272 } 273 274 public void onContextStop(CamelContext context) { 275 // the agent hasn't been started 276 if (!initialized) { 277 return; 278 } 279 try { 280 Object mc = getManagementObjectStrategy().getManagedObjectForCamelContext(context); 281 // the context could have been removed already 282 if (getManagementStrategy().isManaged(mc, null)) { 283 unmanageObject(mc); 284 } 285 } catch (Exception e) { 286 LOG.warn("Could not unregister CamelContext MBean", e); 287 } 288 289 camelContextMBean = null; 290 } 291 292 public void onComponentAdd(String name, Component component) { 293 // always register components as there are only a few of those 294 if (!initialized) { 295 // pre register so we can register later when we have been initialized 296 PreRegisterService pre = new PreRegisterService(); 297 pre.onComponentAdd(name, component); 298 preServices.add(pre); 299 return; 300 } 301 try { 302 Object mc = getManagementObjectStrategy().getManagedObjectForComponent(camelContext, component, name); 303 manageObject(mc); 304 } catch (Exception e) { 305 LOG.warn("Could not register Component MBean", e); 306 } 307 } 308 309 public void onComponentRemove(String name, Component component) { 310 // the agent hasn't been started 311 if (!initialized) { 312 return; 313 } 314 try { 315 Object mc = getManagementObjectStrategy().getManagedObjectForComponent(camelContext, component, name); 316 unmanageObject(mc); 317 } catch (Exception e) { 318 LOG.warn("Could not unregister Component MBean", e); 319 } 320 } 321 322 /** 323 * If the endpoint is an instance of ManagedResource then register it with the 324 * mbean server, if it is not then wrap the endpoint in a {@link ManagedEndpoint} and 325 * register that with the mbean server. 326 * 327 * @param endpoint the Endpoint attempted to be added 328 */ 329 public void onEndpointAdd(Endpoint endpoint) { 330 if (!initialized) { 331 // pre register so we can register later when we have been initialized 332 PreRegisterService pre = new PreRegisterService(); 333 pre.onEndpointAdd(endpoint); 334 preServices.add(pre); 335 return; 336 } 337 338 if (!shouldRegister(endpoint, null)) { 339 // avoid registering if not needed 340 return; 341 } 342 343 try { 344 Object me = getManagementObjectStrategy().getManagedObjectForEndpoint(camelContext, endpoint); 345 if (me == null) { 346 // endpoint should not be managed 347 return; 348 } 349 manageObject(me); 350 } catch (Exception e) { 351 LOG.warn("Could not register Endpoint MBean for endpoint: " + endpoint + ". This exception will be ignored.", e); 352 } 353 } 354 355 public void onEndpointRemove(Endpoint endpoint) { 356 // the agent hasn't been started 357 if (!initialized) { 358 return; 359 } 360 361 try { 362 Object me = getManagementObjectStrategy().getManagedObjectForEndpoint(camelContext, endpoint); 363 unmanageObject(me); 364 } catch (Exception e) { 365 LOG.warn("Could not unregister Endpoint MBean for endpoint: " + endpoint + ". This exception will be ignored.", e); 366 } 367 } 368 369 public void onServiceAdd(CamelContext context, Service service, Route route) { 370 if (!initialized) { 371 // pre register so we can register later when we have been initialized 372 PreRegisterService pre = new PreRegisterService(); 373 pre.onServiceAdd(context, service, route); 374 preServices.add(pre); 375 return; 376 } 377 378 // services can by any kind of misc type but also processors 379 // so we have special logic when its a processor 380 381 if (!shouldRegister(service, route)) { 382 // avoid registering if not needed 383 return; 384 } 385 386 Object managedObject = getManagedObjectForService(context, service, route); 387 if (managedObject == null) { 388 // service should not be managed 389 return; 390 } 391 392 // skip already managed services, for example if a route has been restarted 393 if (getManagementStrategy().isManaged(managedObject, null)) { 394 LOG.trace("The service is already managed: {}", service); 395 return; 396 } 397 398 try { 399 manageObject(managedObject); 400 } catch (Exception e) { 401 LOG.warn("Could not register service: " + service + " as Service MBean.", e); 402 } 403 } 404 405 public void onServiceRemove(CamelContext context, Service service, Route route) { 406 // the agent hasn't been started 407 if (!initialized) { 408 return; 409 } 410 411 Object managedObject = getManagedObjectForService(context, service, route); 412 if (managedObject != null) { 413 try { 414 unmanageObject(managedObject); 415 } catch (Exception e) { 416 LOG.warn("Could not unregister service: " + service + " as Service MBean.", e); 417 } 418 } 419 } 420 421 @SuppressWarnings("unchecked") 422 private Object getManagedObjectForService(CamelContext context, Service service, Route route) { 423 // skip channel, UoW and dont double wrap instrumentation 424 if (service instanceof Channel || service instanceof UnitOfWork || service instanceof InstrumentationProcessor) { 425 return null; 426 } 427 428 // skip non managed services 429 if (service instanceof NonManagedService) { 430 return null; 431 } 432 433 Object answer = null; 434 435 if (service instanceof ManagementAware) { 436 return ((ManagementAware<Service>) service).getManagedObject(service); 437 } else if (service instanceof Tracer) { 438 // special for tracer 439 Tracer tracer = (Tracer) service; 440 ManagedTracer mt = managedTracers.get(tracer); 441 if (mt == null) { 442 mt = new ManagedTracer(context, tracer); 443 mt.init(getManagementStrategy()); 444 managedTracers.put(tracer, mt); 445 } 446 return mt; 447 } else if (service instanceof BacklogTracer) { 448 // special for backlog tracer 449 BacklogTracer backlogTracer = (BacklogTracer) service; 450 ManagedBacklogTracer mt = managedBacklogTracers.get(backlogTracer); 451 if (mt == null) { 452 mt = new ManagedBacklogTracer(context, backlogTracer); 453 mt.init(getManagementStrategy()); 454 managedBacklogTracers.put(backlogTracer, mt); 455 } 456 return mt; 457 } else if (service instanceof BacklogDebugger) { 458 // special for backlog debugger 459 BacklogDebugger backlogDebugger = (BacklogDebugger) service; 460 ManagedBacklogDebugger md = managedBacklogDebuggers.get(backlogDebugger); 461 if (md == null) { 462 md = new ManagedBacklogDebugger(context, backlogDebugger); 463 md.init(getManagementStrategy()); 464 managedBacklogDebuggers.put(backlogDebugger, md); 465 } 466 return md; 467 } else if (service instanceof DataFormat) { 468 answer = getManagementObjectStrategy().getManagedObjectForDataFormat(context, (DataFormat) service); 469 } else if (service instanceof Producer) { 470 answer = getManagementObjectStrategy().getManagedObjectForProducer(context, (Producer) service); 471 } else if (service instanceof Consumer) { 472 answer = getManagementObjectStrategy().getManagedObjectForConsumer(context, (Consumer) service); 473 } else if (service instanceof Processor) { 474 // special for processors as we need to do some extra work 475 return getManagedObjectForProcessor(context, (Processor) service, route); 476 } else if (service instanceof ThrottlingInflightRoutePolicy) { 477 answer = new ManagedThrottlingInflightRoutePolicy(context, (ThrottlingInflightRoutePolicy) service); 478 } else if (service instanceof ThrottlingExceptionRoutePolicy) { 479 answer = new ManagedThrottlingExceptionRoutePolicy(context, (ThrottlingExceptionRoutePolicy) service); 480 } else if (service instanceof ConsumerCache) { 481 answer = new ManagedConsumerCache(context, (ConsumerCache) service); 482 } else if (service instanceof ProducerCache) { 483 answer = new ManagedProducerCache(context, (ProducerCache) service); 484 } else if (service instanceof DefaultEndpointRegistry) { 485 answer = new ManagedEndpointRegistry(context, (DefaultEndpointRegistry) service); 486 } else if (service instanceof TypeConverterRegistry) { 487 answer = new ManagedTypeConverterRegistry(context, (TypeConverterRegistry) service); 488 } else if (service instanceof RestRegistry) { 489 answer = new ManagedRestRegistry(context, (RestRegistry) service); 490 } else if (service instanceof InflightRepository) { 491 answer = new ManagedInflightRepository(context, (InflightRepository) service); 492 } else if (service instanceof AsyncProcessorAwaitManager) { 493 answer = new ManagedAsyncProcessorAwaitManager(context, (AsyncProcessorAwaitManager) service); 494 } else if (service instanceof RuntimeEndpointRegistry) { 495 answer = new ManagedRuntimeEndpointRegistry(context, (RuntimeEndpointRegistry) service); 496 } else if (service instanceof StreamCachingStrategy) { 497 answer = new ManagedStreamCachingStrategy(context, (StreamCachingStrategy) service); 498 } else if (service instanceof EventNotifier) { 499 answer = getManagementObjectStrategy().getManagedObjectForEventNotifier(context, (EventNotifier) service); 500 } else if (service instanceof TransformerRegistry) { 501 answer = new ManagedTransformerRegistry(context, (TransformerRegistry)service); 502 } else if (service instanceof ValidatorRegistry) { 503 answer = new ManagedValidatorRegistry(context, (ValidatorRegistry)service); 504 } else if (service instanceof RuntimeCamelCatalog) { 505 answer = new ManagedRuntimeCamelCatalog(context, (RuntimeCamelCatalog) service); 506 } else if (service != null) { 507 // fallback as generic service 508 answer = getManagementObjectStrategy().getManagedObjectForService(context, service); 509 } 510 511 if (answer != null && answer instanceof ManagedService) { 512 ManagedService ms = (ManagedService) answer; 513 ms.setRoute(route); 514 ms.init(getManagementStrategy()); 515 } 516 517 return answer; 518 } 519 520 private Object getManagedObjectForProcessor(CamelContext context, Processor processor, Route route) { 521 // a bit of magic here as the processors we want to manage have already been registered 522 // in the wrapped processors map when Camel have instrumented the route on route initialization 523 // so the idea is now to only manage the processors from the map 524 KeyValueHolder<ProcessorDefinition<?>, InstrumentationProcessor> holder = wrappedProcessors.get(processor); 525 if (holder == null) { 526 // skip as its not an well known processor we want to manage anyway, such as Channel/UnitOfWork/Pipeline etc. 527 return null; 528 } 529 530 // get the managed object as it can be a specialized type such as a Delayer/Throttler etc. 531 Object managedObject = getManagementObjectStrategy().getManagedObjectForProcessor(context, processor, holder.getKey(), route); 532 // only manage if we have a name for it as otherwise we do not want to manage it anyway 533 if (managedObject != null) { 534 // is it a performance counter then we need to set our counter 535 if (managedObject instanceof PerformanceCounter) { 536 InstrumentationProcessor counter = holder.getValue(); 537 if (counter != null) { 538 // change counter to us 539 counter.setCounter(managedObject); 540 } 541 } 542 } 543 544 return managedObject; 545 } 546 547 public void onRoutesAdd(Collection<Route> routes) { 548 for (Route route : routes) { 549 550 // if we are starting CamelContext or either of the two options has been 551 // enabled, then enlist the route as a known route 552 if (getCamelContext().getStatus().isStarting() 553 || getManagementStrategy().getManagementAgent().getRegisterAlways() 554 || getManagementStrategy().getManagementAgent().getRegisterNewRoutes()) { 555 // register as known route id 556 knowRouteIds.add(route.getId()); 557 } 558 559 if (!shouldRegister(route, route)) { 560 // avoid registering if not needed, skip to next route 561 continue; 562 } 563 564 Object mr = getManagementObjectStrategy().getManagedObjectForRoute(camelContext, route); 565 566 // skip already managed routes, for example if the route has been restarted 567 if (getManagementStrategy().isManaged(mr, null)) { 568 LOG.trace("The route is already managed: {}", route); 569 continue; 570 } 571 572 // get the wrapped instrumentation processor from this route 573 // and set me as the counter 574 if (route instanceof EventDrivenConsumerRoute) { 575 EventDrivenConsumerRoute edcr = (EventDrivenConsumerRoute) route; 576 Processor processor = edcr.getProcessor(); 577 if (processor instanceof CamelInternalProcessor && mr instanceof ManagedRoute) { 578 CamelInternalProcessor internal = (CamelInternalProcessor) processor; 579 ManagedRoute routeMBean = (ManagedRoute) mr; 580 581 CamelInternalProcessor.InstrumentationAdvice task = internal.getAdvice(CamelInternalProcessor.InstrumentationAdvice.class); 582 if (task != null) { 583 // we need to wrap the counter with the camel context so we get stats updated on the context as well 584 if (camelContextMBean != null) { 585 CompositePerformanceCounter wrapper = new CompositePerformanceCounter(routeMBean, camelContextMBean); 586 task.setCounter(wrapper); 587 } else { 588 task.setCounter(routeMBean); 589 } 590 } 591 } 592 } 593 594 try { 595 manageObject(mr); 596 } catch (JMException e) { 597 LOG.warn("Could not register Route MBean", e); 598 } catch (Exception e) { 599 LOG.warn("Could not create Route MBean", e); 600 } 601 } 602 } 603 604 public void onRoutesRemove(Collection<Route> routes) { 605 // the agent hasn't been started 606 if (!initialized) { 607 return; 608 } 609 610 for (Route route : routes) { 611 Object mr = getManagementObjectStrategy().getManagedObjectForRoute(camelContext, route); 612 613 // skip unmanaged routes 614 if (!getManagementStrategy().isManaged(mr, null)) { 615 LOG.trace("The route is not managed: {}", route); 616 continue; 617 } 618 619 try { 620 unmanageObject(mr); 621 } catch (Exception e) { 622 LOG.warn("Could not unregister Route MBean", e); 623 } 624 625 // remove from known routes ids, as the route has been removed 626 knowRouteIds.remove(route.getId()); 627 } 628 629 // after the routes has been removed, we should clear the wrapped processors as we no longer need them 630 // as they were just a provisional map used during creation of routes 631 removeWrappedProcessorsForRoutes(routes); 632 } 633 634 public void onErrorHandlerAdd(RouteContext routeContext, Processor errorHandler, ErrorHandlerFactory errorHandlerBuilder) { 635 if (!shouldRegister(errorHandler, null)) { 636 // avoid registering if not needed 637 return; 638 } 639 640 Object me = getManagementObjectStrategy().getManagedObjectForErrorHandler(camelContext, routeContext, errorHandler, errorHandlerBuilder); 641 642 // skip already managed services, for example if a route has been restarted 643 if (getManagementStrategy().isManaged(me, null)) { 644 LOG.trace("The error handler builder is already managed: {}", errorHandlerBuilder); 645 return; 646 } 647 648 try { 649 manageObject(me); 650 } catch (Exception e) { 651 LOG.warn("Could not register error handler builder: " + errorHandlerBuilder + " as ErrorHandler MBean.", e); 652 } 653 } 654 655 public void onErrorHandlerRemove(RouteContext routeContext, Processor errorHandler, ErrorHandlerFactory errorHandlerBuilder) { 656 if (!initialized) { 657 return; 658 } 659 660 Object me = getManagementObjectStrategy().getManagedObjectForErrorHandler(camelContext, routeContext, errorHandler, errorHandlerBuilder); 661 if (me != null) { 662 try { 663 unmanageObject(me); 664 } catch (Exception e) { 665 LOG.warn("Could not unregister error handler: " + me + " as ErrorHandler MBean.", e); 666 } 667 } 668 } 669 670 public void onThreadPoolAdd(CamelContext camelContext, ThreadPoolExecutor threadPool, String id, 671 String sourceId, String routeId, String threadPoolProfileId) { 672 673 if (!shouldRegister(threadPool, null)) { 674 // avoid registering if not needed 675 return; 676 } 677 678 Object mtp = getManagementObjectStrategy().getManagedObjectForThreadPool(camelContext, threadPool, id, sourceId, routeId, threadPoolProfileId); 679 680 // skip already managed services, for example if a route has been restarted 681 if (getManagementStrategy().isManaged(mtp, null)) { 682 LOG.trace("The thread pool is already managed: {}", threadPool); 683 return; 684 } 685 686 try { 687 manageObject(mtp); 688 // store a reference so we can unmanage from JMX when the thread pool is removed 689 // we need to keep track here, as we cannot re-construct the thread pool ObjectName when removing the thread pool 690 managedThreadPools.put(threadPool, mtp); 691 } catch (Exception e) { 692 LOG.warn("Could not register thread pool: " + threadPool + " as ThreadPool MBean.", e); 693 } 694 } 695 696 public void onThreadPoolRemove(CamelContext camelContext, ThreadPoolExecutor threadPool) { 697 if (!initialized) { 698 return; 699 } 700 701 // lookup the thread pool and remove it from JMX 702 Object mtp = managedThreadPools.remove(threadPool); 703 if (mtp != null) { 704 // skip unmanaged routes 705 if (!getManagementStrategy().isManaged(mtp, null)) { 706 LOG.trace("The thread pool is not managed: {}", threadPool); 707 return; 708 } 709 710 try { 711 unmanageObject(mtp); 712 } catch (Exception e) { 713 LOG.warn("Could not unregister ThreadPool MBean", e); 714 } 715 } 716 } 717 718 public void onRouteContextCreate(RouteContext routeContext) { 719 if (!initialized) { 720 return; 721 } 722 723 // Create a map (ProcessorType -> PerformanceCounter) 724 // to be passed to InstrumentationInterceptStrategy. 725 Map<ProcessorDefinition<?>, PerformanceCounter> registeredCounters = 726 new HashMap<ProcessorDefinition<?>, PerformanceCounter>(); 727 728 // Each processor in a route will have its own performance counter. 729 // These performance counter will be embedded to InstrumentationProcessor 730 // and wrap the appropriate processor by InstrumentationInterceptStrategy. 731 RouteDefinition route = routeContext.getRoute(); 732 733 // register performance counters for all processors and its children 734 for (ProcessorDefinition<?> processor : route.getOutputs()) { 735 registerPerformanceCounters(routeContext, processor, registeredCounters); 736 } 737 738 // set this managed intercept strategy that executes the JMX instrumentation for performance metrics 739 // so our registered counters can be used for fine grained performance instrumentation 740 routeContext.setManagedInterceptStrategy(new InstrumentationInterceptStrategy(registeredCounters, wrappedProcessors)); 741 } 742 743 /** 744 * Removes the wrapped processors for the given routes, as they are no longer in use. 745 * <p/> 746 * This is needed to avoid accumulating memory, if a lot of routes is being added and removed. 747 * 748 * @param routes the routes 749 */ 750 private void removeWrappedProcessorsForRoutes(Collection<Route> routes) { 751 // loop the routes, and remove the route associated wrapped processors, as they are no longer in use 752 for (Route route : routes) { 753 String id = route.getId(); 754 755 Iterator<KeyValueHolder<ProcessorDefinition<?>, InstrumentationProcessor>> it = wrappedProcessors.values().iterator(); 756 while (it.hasNext()) { 757 KeyValueHolder<ProcessorDefinition<?>, InstrumentationProcessor> holder = it.next(); 758 RouteDefinition def = ProcessorDefinitionHelper.getRoute(holder.getKey()); 759 if (def != null && id.equals(def.getId())) { 760 it.remove(); 761 } 762 } 763 } 764 765 } 766 767 private void registerPerformanceCounters(RouteContext routeContext, ProcessorDefinition<?> processor, 768 Map<ProcessorDefinition<?>, PerformanceCounter> registeredCounters) { 769 770 // traverse children if any exists 771 List<ProcessorDefinition<?>> children = processor.getOutputs(); 772 for (ProcessorDefinition<?> child : children) { 773 registerPerformanceCounters(routeContext, child, registeredCounters); 774 } 775 776 // skip processors that should not be registered 777 if (!registerProcessor(processor)) { 778 return; 779 } 780 781 // okay this is a processor we would like to manage so create the 782 // a delegate performance counter that acts as the placeholder in the interceptor 783 // that then delegates to the real mbean which we register later in the onServiceAdd method 784 DelegatePerformanceCounter pc = new DelegatePerformanceCounter(); 785 // set statistics enabled depending on the option 786 boolean enabled = camelContext.getManagementStrategy().getManagementAgent().getStatisticsLevel().isDefaultOrExtended(); 787 pc.setStatisticsEnabled(enabled); 788 789 // and add it as a a registered counter that will be used lazy when Camel 790 // does the instrumentation of the route and adds the InstrumentationProcessor 791 // that does the actual performance metrics gatherings at runtime 792 registeredCounters.put(processor, pc); 793 } 794 795 /** 796 * Should the given processor be registered. 797 */ 798 protected boolean registerProcessor(ProcessorDefinition<?> processor) { 799 // skip on exception 800 if (processor instanceof OnExceptionDefinition) { 801 return false; 802 } 803 // skip on completion 804 if (processor instanceof OnCompletionDefinition) { 805 return false; 806 } 807 // skip intercept 808 if (processor instanceof InterceptDefinition) { 809 return false; 810 } 811 // skip aop 812 if (processor instanceof AOPDefinition) { 813 return false; 814 } 815 // skip policy 816 if (processor instanceof PolicyDefinition) { 817 return false; 818 } 819 820 // only if custom id assigned 821 boolean only = getManagementStrategy().getManagementAgent().getOnlyRegisterProcessorWithCustomId() != null 822 && getManagementStrategy().getManagementAgent().getOnlyRegisterProcessorWithCustomId(); 823 if (only) { 824 return processor.hasCustomIdAssigned(); 825 } 826 827 // use customer filter 828 return getManagementStrategy().manageProcessor(processor); 829 } 830 831 private ManagementStrategy getManagementStrategy() { 832 ObjectHelper.notNull(camelContext, "CamelContext"); 833 return camelContext.getManagementStrategy(); 834 } 835 836 private ManagementObjectStrategy getManagementObjectStrategy() { 837 ObjectHelper.notNull(camelContext, "CamelContext"); 838 return camelContext.getManagementStrategy().getManagementObjectStrategy(); 839 } 840 841 /** 842 * Strategy for managing the object 843 * 844 * @param me the managed object 845 * @throws Exception is thrown if error registering the object for management 846 */ 847 protected void manageObject(Object me) throws Exception { 848 getManagementStrategy().manageObject(me); 849 if (me instanceof TimerListener) { 850 TimerListener timer = (TimerListener) me; 851 loadTimer.addTimerListener(timer); 852 } 853 } 854 855 /** 856 * Un-manages the object. 857 * 858 * @param me the managed object 859 * @throws Exception is thrown if error unregistering the managed object 860 */ 861 protected void unmanageObject(Object me) throws Exception { 862 if (me instanceof TimerListener) { 863 TimerListener timer = (TimerListener) me; 864 loadTimer.removeTimerListener(timer); 865 } 866 getManagementStrategy().unmanageObject(me); 867 } 868 869 /** 870 * Whether or not to register the mbean. 871 * <p/> 872 * The {@link ManagementAgent} has options which controls when to register. 873 * This allows us to only register mbeans accordingly. For example by default any 874 * dynamic endpoints is not registered. This avoids to register excessive mbeans, which 875 * most often is not desired. 876 * 877 * @param service the object to register 878 * @param route an optional route the mbean is associated with, can be <tt>null</tt> 879 * @return <tt>true</tt> to register, <tt>false</tt> to skip registering 880 */ 881 protected boolean shouldRegister(Object service, Route route) { 882 // the agent hasn't been started 883 if (!initialized) { 884 return false; 885 } 886 887 LOG.trace("Checking whether to register {} from route: {}", service, route); 888 889 ManagementAgent agent = getManagementStrategy().getManagementAgent(); 890 if (agent == null) { 891 // do not register if no agent 892 return false; 893 } 894 895 // always register if we are starting CamelContext 896 if (getCamelContext().getStatus().isStarting()) { 897 return true; 898 } 899 900 // always register if we are setting up routes 901 if (getCamelContext().isSetupRoutes()) { 902 return true; 903 } 904 905 // register if always is enabled 906 if (agent.getRegisterAlways()) { 907 return true; 908 } 909 910 // is it a known route then always accept 911 if (route != null && knowRouteIds.contains(route.getId())) { 912 return true; 913 } 914 915 // only register if we are starting a new route, and current thread is in starting routes mode 916 if (agent.getRegisterNewRoutes()) { 917 // no specific route, then fallback to see if this thread is starting routes 918 // which is kept as state on the camel context 919 return getCamelContext().isStartingRoutes(); 920 } 921 922 return false; 923 } 924 925 @Override 926 protected void doStart() throws Exception { 927 ObjectHelper.notNull(camelContext, "CamelContext"); 928 929 // defer starting the timer manager until CamelContext has been fully started 930 camelContext.addStartupListener(loadTimerStartupListener); 931 } 932 933 private final class TimerListenerManagerStartupListener implements StartupListener { 934 935 @Override 936 public void onCamelContextStarted(CamelContext context, boolean alreadyStarted) throws Exception { 937 // we are disabled either if configured explicit, or if level is off 938 boolean load = camelContext.getManagementStrategy().getManagementAgent().getLoadStatisticsEnabled() != null 939 && camelContext.getManagementStrategy().getManagementAgent().getLoadStatisticsEnabled(); 940 boolean disabled = !load || camelContext.getManagementStrategy().getStatisticsLevel() == ManagementStatisticsLevel.Off; 941 942 LOG.debug("Load performance statistics {}", disabled ? "disabled" : "enabled"); 943 if (!disabled) { 944 // must use 1 sec interval as the load statistics is based on 1 sec calculations 945 loadTimer.setInterval(1000); 946 // we have to defer enlisting timer lister manager as a service until CamelContext has been started 947 getCamelContext().addService(loadTimer); 948 } 949 } 950 } 951 952 @Override 953 protected void doStop() throws Exception { 954 initialized = false; 955 knowRouteIds.clear(); 956 preServices.clear(); 957 wrappedProcessors.clear(); 958 managedTracers.clear(); 959 managedBacklogTracers.clear(); 960 managedBacklogDebuggers.clear(); 961 managedThreadPools.clear(); 962 } 963 964 /** 965 * Class which holds any pre registration details. 966 * 967 * @see org.apache.camel.management.DefaultManagementLifecycleStrategy#enlistPreRegisteredServices() 968 */ 969 private static final class PreRegisterService { 970 971 private String name; 972 private Component component; 973 private Endpoint endpoint; 974 private CamelContext camelContext; 975 private Service service; 976 private Route route; 977 978 public void onComponentAdd(String name, Component component) { 979 this.name = name; 980 this.component = component; 981 } 982 983 public void onEndpointAdd(Endpoint endpoint) { 984 this.endpoint = endpoint; 985 } 986 987 public void onServiceAdd(CamelContext camelContext, Service service, Route route) { 988 this.camelContext = camelContext; 989 this.service = service; 990 this.route = route; 991 } 992 993 public String getName() { 994 return name; 995 } 996 997 public Component getComponent() { 998 return component; 999 } 1000 1001 public Endpoint getEndpoint() { 1002 return endpoint; 1003 } 1004 1005 public CamelContext getCamelContext() { 1006 return camelContext; 1007 } 1008 1009 public Service getService() { 1010 return service; 1011 } 1012 1013 public Route getRoute() { 1014 return route; 1015 } 1016 } 1017 1018} 1019