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.net.UnknownHostException; 020import java.util.concurrent.ThreadPoolExecutor; 021 022import javax.management.MalformedObjectNameException; 023import javax.management.ObjectName; 024 025import org.apache.camel.CamelContext; 026import org.apache.camel.CamelContextAware; 027import org.apache.camel.Component; 028import org.apache.camel.Consumer; 029import org.apache.camel.Endpoint; 030import org.apache.camel.ErrorHandlerFactory; 031import org.apache.camel.NamedNode; 032import org.apache.camel.Processor; 033import org.apache.camel.Producer; 034import org.apache.camel.Route; 035import org.apache.camel.Service; 036import org.apache.camel.StaticService; 037import org.apache.camel.builder.ErrorHandlerBuilderRef; 038import org.apache.camel.cluster.CamelClusterService; 039import org.apache.camel.management.mbean.ManagedBacklogDebugger; 040import org.apache.camel.management.mbean.ManagedBacklogTracer; 041import org.apache.camel.management.mbean.ManagedCamelContext; 042import org.apache.camel.management.mbean.ManagedCamelHealth; 043import org.apache.camel.management.mbean.ManagedClusterService; 044import org.apache.camel.management.mbean.ManagedComponent; 045import org.apache.camel.management.mbean.ManagedConsumer; 046import org.apache.camel.management.mbean.ManagedDataFormat; 047import org.apache.camel.management.mbean.ManagedEndpoint; 048import org.apache.camel.management.mbean.ManagedErrorHandler; 049import org.apache.camel.management.mbean.ManagedEventNotifier; 050import org.apache.camel.management.mbean.ManagedProcessor; 051import org.apache.camel.management.mbean.ManagedProducer; 052import org.apache.camel.management.mbean.ManagedRoute; 053import org.apache.camel.management.mbean.ManagedRouteController; 054import org.apache.camel.management.mbean.ManagedService; 055import org.apache.camel.management.mbean.ManagedThreadPool; 056import org.apache.camel.spi.DataFormat; 057import org.apache.camel.spi.EventNotifier; 058import org.apache.camel.spi.ManagementObjectNameStrategy; 059import org.apache.camel.spi.RouteContext; 060import org.apache.camel.util.InetAddressUtil; 061import org.apache.camel.util.ObjectHelper; 062import org.apache.camel.util.URISupport; 063 064/** 065 * Naming strategy used when registering MBeans. 066 */ 067public class DefaultManagementObjectNameStrategy implements ManagementObjectNameStrategy, CamelContextAware { 068 public static final String VALUE_UNKNOWN = "unknown"; 069 public static final String KEY_NAME = "name"; 070 public static final String KEY_TYPE = "type"; 071 public static final String KEY_CONTEXT = "context"; 072 public static final String TYPE_CONTEXT = "context"; 073 public static final String TYPE_ROUTE_CONTROLLER = "routecontrollers"; 074 public static final String TYPE_HEALTH = "health"; 075 public static final String TYPE_ENDPOINT = "endpoints"; 076 public static final String TYPE_DATAFORMAT = "dataformats"; 077 public static final String TYPE_PROCESSOR = "processors"; 078 public static final String TYPE_CONSUMER = "consumers"; 079 public static final String TYPE_PRODUCER = "producers"; 080 public static final String TYPE_ROUTE = "routes"; 081 public static final String TYPE_COMPONENT = "components"; 082 public static final String TYPE_TRACER = "tracer"; 083 public static final String TYPE_EVENT_NOTIFIER = "eventnotifiers"; 084 public static final String TYPE_ERRORHANDLER = "errorhandlers"; 085 public static final String TYPE_THREAD_POOL = "threadpools"; 086 public static final String TYPE_SERVICE = "services"; 087 public static final String TYPE_HA = "clusterservices"; 088 089 protected String domainName; 090 protected String hostName = "localhost"; 091 protected CamelContext camelContext; 092 093 public DefaultManagementObjectNameStrategy() { 094 this(null); 095 // default constructor needed for <bean> style configuration 096 } 097 098 public DefaultManagementObjectNameStrategy(String domainName) { 099 this.domainName = domainName != null ? domainName : "org.apache.camel"; 100 try { 101 hostName = InetAddressUtil.getLocalHostName(); 102 } catch (UnknownHostException ex) { 103 // ignore, use the default "localhost" 104 } 105 } 106 107 public CamelContext getCamelContext() { 108 return camelContext; 109 } 110 111 public void setCamelContext(CamelContext camelContext) { 112 this.camelContext = camelContext; 113 } 114 115 public ObjectName getObjectName(Object managedObject) throws MalformedObjectNameException { 116 if (managedObject == null) { 117 return null; 118 } 119 ObjectName objectName = null; 120 if (managedObject instanceof ManagedCamelContext) { 121 ManagedCamelContext mcc = (ManagedCamelContext) managedObject; 122 objectName = getObjectNameForCamelContext(mcc.getContext()); 123 } else if (managedObject instanceof ManagedCamelHealth) { 124 ManagedCamelHealth mch = (ManagedCamelHealth) managedObject; 125 objectName = getObjectNameForCamelHealth(mch.getContext()); 126 } else if (managedObject instanceof ManagedRouteController) { 127 ManagedRouteController mrc = (ManagedRouteController) managedObject; 128 objectName = getObjectNameForRouteController(mrc.getContext()); 129 } else if (managedObject instanceof ManagedComponent) { 130 ManagedComponent mc = (ManagedComponent) managedObject; 131 objectName = getObjectNameForComponent(mc.getComponent(), mc.getComponentName()); 132 } else if (managedObject instanceof ManagedDataFormat) { 133 ManagedDataFormat md = (ManagedDataFormat) managedObject; 134 objectName = getObjectNameForDataFormat(md.getContext(), md.getDataFormat()); 135 } else if (managedObject instanceof ManagedEndpoint) { 136 ManagedEndpoint me = (ManagedEndpoint) managedObject; 137 objectName = getObjectNameForEndpoint(me.getEndpoint()); 138 } else if (managedObject instanceof Endpoint) { 139 objectName = getObjectNameForEndpoint((Endpoint) managedObject); 140 } else if (managedObject instanceof ManagedRoute) { 141 ManagedRoute mr = (ManagedRoute) managedObject; 142 objectName = getObjectNameForRoute(mr.getRoute()); 143 } else if (managedObject instanceof ManagedErrorHandler) { 144 ManagedErrorHandler meh = (ManagedErrorHandler) managedObject; 145 objectName = getObjectNameForErrorHandler(meh.getRouteContext(), meh.getErrorHandler(), meh.getErrorHandlerBuilder()); 146 } else if (managedObject instanceof ManagedProcessor) { 147 ManagedProcessor mp = (ManagedProcessor) managedObject; 148 objectName = getObjectNameForProcessor(mp.getContext(), mp.getProcessor(), mp.getDefinition()); 149 } else if (managedObject instanceof ManagedConsumer) { 150 ManagedConsumer ms = (ManagedConsumer) managedObject; 151 objectName = getObjectNameForConsumer(ms.getContext(), ms.getConsumer()); 152 } else if (managedObject instanceof ManagedProducer) { 153 ManagedProducer ms = (ManagedProducer) managedObject; 154 objectName = getObjectNameForProducer(ms.getContext(), ms.getProducer()); 155 } else if (managedObject instanceof ManagedBacklogTracer) { 156 ManagedBacklogTracer mt = (ManagedBacklogTracer) managedObject; 157 objectName = getObjectNameForTracer(mt.getContext(), mt.getBacklogTracer()); 158 } else if (managedObject instanceof ManagedBacklogDebugger) { 159 ManagedBacklogDebugger md = (ManagedBacklogDebugger) managedObject; 160 objectName = getObjectNameForTracer(md.getContext(), md.getBacklogDebugger()); 161 } else if (managedObject instanceof ManagedEventNotifier) { 162 ManagedEventNotifier men = (ManagedEventNotifier) managedObject; 163 objectName = getObjectNameForEventNotifier(men.getContext(), men.getEventNotifier()); 164 } else if (managedObject instanceof ManagedThreadPool) { 165 ManagedThreadPool mes = (ManagedThreadPool) managedObject; 166 objectName = getObjectNameForThreadPool(mes.getContext(), mes.getThreadPool(), mes.getId(), mes.getSourceId()); 167 } else if (managedObject instanceof ManagedClusterService) { 168 ManagedClusterService mcs = (ManagedClusterService) managedObject; 169 objectName = getObjectNameForClusterService(mcs.getContext(), mcs.getService()); 170 } else if (managedObject instanceof ManagedService) { 171 // check for managed service should be last 172 ManagedService ms = (ManagedService) managedObject; 173 // skip endpoints as they are already managed 174 if (ms.getService() instanceof Endpoint) { 175 return null; 176 } 177 objectName = getObjectNameForService(ms.getContext(), ms.getService()); 178 } 179 180 return objectName; 181 } 182 183 public ObjectName getObjectNameForCamelContext(String managementName, String name) throws MalformedObjectNameException { 184 StringBuilder buffer = new StringBuilder(); 185 buffer.append(domainName).append(":"); 186 buffer.append(KEY_CONTEXT + "=").append(getContextId(managementName)).append(","); 187 buffer.append(KEY_TYPE + "=" + TYPE_CONTEXT + ","); 188 buffer.append(KEY_NAME + "=").append(ObjectName.quote(name)); 189 return createObjectName(buffer); 190 } 191 192 public ObjectName getObjectNameForCamelContext(CamelContext context) throws MalformedObjectNameException { 193 // prefer to use the given management name if previously assigned 194 String managementName = context.getManagementName(); 195 if (managementName == null) { 196 managementName = context.getManagementNameStrategy().getName(); 197 } 198 String name = context.getName(); 199 return getObjectNameForCamelContext(managementName, name); 200 } 201 202 @Override 203 public ObjectName getObjectNameForCamelHealth(CamelContext context) throws MalformedObjectNameException { 204 // prefer to use the given management name if previously assigned 205 String managementName = context.getManagementName(); 206 if (managementName == null) { 207 managementName = context.getManagementNameStrategy().getName(); 208 } 209 210 StringBuilder buffer = new StringBuilder(); 211 buffer.append(domainName).append(":"); 212 buffer.append(KEY_CONTEXT + "=").append(getContextId(managementName)).append(","); 213 buffer.append(KEY_TYPE + "=" + TYPE_HEALTH + ","); 214 buffer.append(KEY_NAME + "=").append(ObjectName.quote(context.getName())); 215 216 return createObjectName(buffer); 217 } 218 219 @Override 220 public ObjectName getObjectNameForRouteController(CamelContext context) throws MalformedObjectNameException { 221 // prefer to use the given management name if previously assigned 222 String managementName = context.getManagementName(); 223 if (managementName == null) { 224 managementName = context.getManagementNameStrategy().getName(); 225 } 226 227 StringBuilder buffer = new StringBuilder(); 228 buffer.append(domainName).append(":"); 229 buffer.append(KEY_CONTEXT + "=").append(getContextId(managementName)).append(","); 230 buffer.append(KEY_TYPE + "=" + TYPE_ROUTE_CONTROLLER + ","); 231 buffer.append(KEY_NAME + "=").append(ObjectName.quote(context.getName())); 232 233 return createObjectName(buffer); 234 } 235 236 public ObjectName getObjectNameForEndpoint(Endpoint endpoint) throws MalformedObjectNameException { 237 StringBuilder buffer = new StringBuilder(); 238 buffer.append(domainName).append(":"); 239 buffer.append(KEY_CONTEXT + "=").append(getContextId(endpoint.getCamelContext())).append(","); 240 buffer.append(KEY_TYPE + "=" + TYPE_ENDPOINT + ","); 241 buffer.append(KEY_NAME + "=").append(ObjectName.quote(getEndpointId(endpoint))); 242 return createObjectName(buffer); 243 } 244 245 public ObjectName getObjectNameForDataFormat(CamelContext context, DataFormat dataFormat) throws MalformedObjectNameException { 246 StringBuilder buffer = new StringBuilder(); 247 buffer.append(domainName).append(":"); 248 buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(","); 249 buffer.append(KEY_TYPE + "=" + TYPE_DATAFORMAT + ","); 250 buffer.append(KEY_NAME + "=").append(dataFormat.getClass().getSimpleName()); 251 if (!(dataFormat instanceof StaticService)) { 252 buffer.append("(").append(ObjectHelper.getIdentityHashCode(dataFormat)).append(")"); 253 } 254 return createObjectName(buffer); 255 } 256 257 public ObjectName getObjectNameForComponent(Component component, String name) throws MalformedObjectNameException { 258 StringBuilder buffer = new StringBuilder(); 259 buffer.append(domainName).append(":"); 260 buffer.append(KEY_CONTEXT + "=").append(getContextId(component.getCamelContext())).append(","); 261 buffer.append(KEY_TYPE + "=" + TYPE_COMPONENT + ","); 262 buffer.append(KEY_NAME + "=").append(ObjectName.quote(name)); 263 return createObjectName(buffer); 264 } 265 266 public ObjectName getObjectNameForProcessor(CamelContext context, Processor processor, NamedNode definition) throws MalformedObjectNameException { 267 StringBuilder buffer = new StringBuilder(); 268 buffer.append(domainName).append(":"); 269 buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(","); 270 buffer.append(KEY_TYPE + "=").append(TYPE_PROCESSOR).append(","); 271 buffer.append(KEY_NAME + "=").append(ObjectName.quote(definition.getId())); 272 return createObjectName(buffer); 273 } 274 275 public ObjectName getObjectNameForErrorHandler(RouteContext routeContext, Processor errorHandler, ErrorHandlerFactory builder) throws MalformedObjectNameException { 276 StringBuilder buffer = new StringBuilder(); 277 buffer.append(domainName).append(":"); 278 buffer.append(KEY_CONTEXT + "=").append(getContextId(routeContext.getCamelContext())).append(","); 279 buffer.append(KEY_TYPE + "=").append(TYPE_ERRORHANDLER + ","); 280 281 // we want to only register one instance of the various error handler types and thus do some lookup 282 // if its a ErrorHandlerBuildRef. We need a bit of work to do that as there are potential indirection. 283 String ref = null; 284 if (builder instanceof ErrorHandlerBuilderRef) { 285 ErrorHandlerBuilderRef builderRef = (ErrorHandlerBuilderRef) builder; 286 287 // it has not then its an indirection and we should do some work to lookup the real builder 288 ref = builderRef.getRef(); 289 ErrorHandlerFactory refBuilder = ErrorHandlerBuilderRef.lookupErrorHandlerBuilder(routeContext, builderRef.getRef(), false); 290 if (refBuilder != null) { 291 builder = refBuilder; 292 } 293 294 // must do a 2nd lookup in case this is also a reference 295 // (this happens with spring DSL using errorHandlerRef on <route> as it gets a bit 296 // complex with indirections for error handler references 297 if (builder instanceof ErrorHandlerBuilderRef) { 298 builderRef = (ErrorHandlerBuilderRef) builder; 299 // does it refer to a non default error handler then do a 2nd lookup 300 if (!builderRef.getRef().equals(ErrorHandlerBuilderRef.DEFAULT_ERROR_HANDLER_BUILDER)) { 301 refBuilder = ErrorHandlerBuilderRef.lookupErrorHandlerBuilder(routeContext, builderRef.getRef(), false); 302 if (refBuilder != null) { 303 ref = builderRef.getRef(); 304 builder = refBuilder; 305 } 306 } 307 } 308 } 309 310 if (ref != null) { 311 String name = builder.getClass().getSimpleName() + "(ref:" + ref + ")"; 312 buffer.append(KEY_NAME + "=").append(ObjectName.quote(name)); 313 } else { 314 // create a name based on its instance 315 buffer.append(KEY_NAME + "=") 316 .append(builder.getClass().getSimpleName()) 317 .append("(").append(ObjectHelper.getIdentityHashCode(builder)).append(")"); 318 } 319 320 return createObjectName(buffer); 321 } 322 323 public ObjectName getObjectNameForConsumer(CamelContext context, Consumer consumer) throws MalformedObjectNameException { 324 StringBuilder buffer = new StringBuilder(); 325 buffer.append(domainName).append(":"); 326 buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(","); 327 buffer.append(KEY_TYPE + "=").append(TYPE_CONSUMER).append(","); 328 329 String name = consumer.getClass().getSimpleName(); 330 if (ObjectHelper.isEmpty(name)) { 331 name = "Consumer"; 332 } 333 buffer.append(KEY_NAME + "=") 334 .append(name) 335 .append("(").append(ObjectHelper.getIdentityHashCode(consumer)).append(")"); 336 return createObjectName(buffer); 337 } 338 339 public ObjectName getObjectNameForProducer(CamelContext context, Producer producer) throws MalformedObjectNameException { 340 StringBuilder buffer = new StringBuilder(); 341 buffer.append(domainName).append(":"); 342 buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(","); 343 buffer.append(KEY_TYPE + "=").append(TYPE_PRODUCER).append(","); 344 345 String name = producer.getClass().getSimpleName(); 346 if (ObjectHelper.isEmpty(name)) { 347 name = "Producer"; 348 } 349 buffer.append(KEY_NAME + "=") 350 .append(name) 351 .append("(").append(ObjectHelper.getIdentityHashCode(producer)).append(")"); 352 return createObjectName(buffer); 353 } 354 355 public ObjectName getObjectNameForTracer(CamelContext context, Service tracer) throws MalformedObjectNameException { 356 // use the simple name of the class as the mbean name (eg Tracer, BacklogTracer, BacklogDebugger) 357 String name = tracer.getClass().getSimpleName(); 358 359 StringBuilder buffer = new StringBuilder(); 360 buffer.append(domainName).append(":"); 361 buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(","); 362 buffer.append(KEY_TYPE + "=" + TYPE_TRACER + ","); 363 buffer.append(KEY_NAME + "=").append(name); 364 return createObjectName(buffer); 365 } 366 367 public ObjectName getObjectNameForEventNotifier(CamelContext context, EventNotifier eventNotifier) throws MalformedObjectNameException { 368 StringBuilder buffer = new StringBuilder(); 369 buffer.append(domainName).append(":"); 370 buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(","); 371 buffer.append(KEY_TYPE + "=" + TYPE_EVENT_NOTIFIER + ","); 372 373 if (eventNotifier instanceof JmxNotificationEventNotifier) { 374 // JMX notifier shall have an easy to use name 375 buffer.append(KEY_NAME + "=").append("JmxEventNotifier"); 376 } else { 377 // others can be per instance 378 buffer.append(KEY_NAME + "=") 379 .append("EventNotifier") 380 .append("(").append(ObjectHelper.getIdentityHashCode(eventNotifier)).append(")"); 381 } 382 return createObjectName(buffer); 383 } 384 385 public ObjectName getObjectNameForRoute(Route route) throws MalformedObjectNameException { 386 Endpoint ep = route.getEndpoint(); 387 String id = route.getId(); 388 389 StringBuilder buffer = new StringBuilder(); 390 buffer.append(domainName).append(":"); 391 buffer.append(KEY_CONTEXT + "=").append(getContextId(ep.getCamelContext())).append(","); 392 buffer.append(KEY_TYPE + "=" + TYPE_ROUTE + ","); 393 buffer.append(KEY_NAME + "=").append(ObjectName.quote(id)); 394 return createObjectName(buffer); 395 } 396 397 public ObjectName getObjectNameForService(CamelContext context, Service service) throws MalformedObjectNameException { 398 StringBuilder buffer = new StringBuilder(); 399 buffer.append(domainName).append(":"); 400 buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(","); 401 buffer.append(KEY_TYPE + "=" + TYPE_SERVICE + ","); 402 buffer.append(KEY_NAME + "=").append(service.getClass().getSimpleName()); 403 if (!(service instanceof StaticService)) { 404 buffer.append("(").append(ObjectHelper.getIdentityHashCode(service)).append(")"); 405 } 406 return createObjectName(buffer); 407 } 408 409 public ObjectName getObjectNameForClusterService(CamelContext context, CamelClusterService service) throws MalformedObjectNameException { 410 StringBuilder buffer = new StringBuilder(); 411 buffer.append(domainName).append(":"); 412 buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(","); 413 buffer.append(KEY_TYPE + "=" + TYPE_HA + ","); 414 buffer.append(KEY_NAME + "=").append(service.getClass().getSimpleName()); 415 if (!(service instanceof StaticService)) { 416 buffer.append("(").append(ObjectHelper.getIdentityHashCode(service)).append(")"); 417 } 418 return createObjectName(buffer); 419 } 420 421 public ObjectName getObjectNameForThreadPool(CamelContext context, ThreadPoolExecutor threadPool, String id, String sourceId) throws MalformedObjectNameException { 422 StringBuilder buffer = new StringBuilder(); 423 buffer.append(domainName).append(":"); 424 buffer.append(KEY_CONTEXT + "=").append(getContextId(context)).append(","); 425 buffer.append(KEY_TYPE + "=" + TYPE_THREAD_POOL + ","); 426 427 String name = id; 428 if (sourceId != null) { 429 // provide source id if we know it, this helps end user to know where the pool is used 430 name = name + "(" + sourceId + ")"; 431 } 432 buffer.append(KEY_NAME + "=").append(ObjectName.quote(name)); 433 return createObjectName(buffer); 434 } 435 436 public String getDomainName() { 437 return domainName; 438 } 439 440 public void setDomainName(String domainName) { 441 this.domainName = domainName; 442 } 443 444 public String getHostName() { 445 return hostName; 446 } 447 448 public void setHostName(String hostName) { 449 this.hostName = hostName; 450 } 451 452 protected String getContextId(CamelContext context) { 453 if (context == null) { 454 return getContextId(VALUE_UNKNOWN); 455 } else { 456 String name = context.getManagementName() != null ? context.getManagementName() : context.getName(); 457 return getContextId(name); 458 } 459 } 460 461 protected String getContextId(String name) { 462 Boolean includeHostName = camelContext != null && camelContext.getManagementStrategy().getManagementAgent().getIncludeHostName(); 463 if (includeHostName != null && includeHostName) { 464 return hostName + "/" + (name != null ? name : VALUE_UNKNOWN); 465 } else { 466 return name != null ? name : VALUE_UNKNOWN; 467 } 468 } 469 470 protected String getEndpointId(Endpoint ep) { 471 String answer = doGetEndpointId(ep); 472 Boolean sanitize = camelContext != null && camelContext.getManagementStrategy().getManagementAgent().getMask(); 473 if (sanitize != null && sanitize) { 474 // use xxxxxx as replacements as * has to be quoted for MBean names 475 answer = URISupport.sanitizeUri(answer); 476 } 477 return answer; 478 } 479 480 private String doGetEndpointId(Endpoint ep) { 481 if (ep.isSingleton()) { 482 return ep.getEndpointKey(); 483 } else { 484 // non singleton then add hashcoded id 485 String uri = ep.getEndpointKey(); 486 int pos = uri.indexOf('?'); 487 String id = (pos == -1) ? uri : uri.substring(0, pos); 488 id += "?id=" + ObjectHelper.getIdentityHashCode(ep); 489 return id; 490 } 491 } 492 493 /** 494 * Factory method to create an ObjectName escaping any required characters 495 */ 496 protected ObjectName createObjectName(StringBuilder buffer) throws MalformedObjectNameException { 497 String text = buffer.toString(); 498 try { 499 return new ObjectName(text); 500 } catch (MalformedObjectNameException e) { 501 throw new MalformedObjectNameException("Could not create ObjectName from: " + text + ". Reason: " + e); 502 } 503 } 504}