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