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