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