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