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