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