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